​ 作者:vivo 互联网大数据团队- Wang Lei

一、前言

一直以来,许多产品渠道都在测验经过可视化建立的手法来降低 GUI 运用的研制门槛,提高生产功率。跟着咱们业务的发展,数据建设的完善,用户关于数据可视化的诉求也日益增多,而数据大屏是数据可视化的其间一种展示办法,它作为大数据展示媒介的一种,被广泛运用于各种会议、公司展厅、发布会等。

比较于传统手艺定制的图表与数据仪表盘,通用大屏建立渠道的呈现,能够处理定制开发, 数据分散带来的运用开发、数据保护本钱高级问题,经过数据采集、清洗、剖析到直观实时的数据可视化展示,能够多方位、多角度、全景展示各项方针,实时监控,动态一望而知。

本文将经过敏捷BI渠道的通用大屏建立才能的完成计划,来讲解一下通用可视化建立渠道全体的规划思路。

二、快速了解可视化大屏

2.1 什么是数据可视化

从技术层面上来讲,最直观的便是前端可视化结构:Echart、Antv、Chart.js、D3.js、Vega 等,这些库都能帮咱们快速把数据转换成各种形式的可视化图表。

从0到1设计通用数据大屏搭建平台

业务层面来讲, 其最主要的含义就在于经过数据 -> 图表组合 -> 可视化页面这一业务流程,来帮助用户愈加直观全体的剖析不同职业和场景的趋势和规律。

从0到1设计通用数据大屏搭建平台

所以在数据范畴里,关于复杂难明且体量巨大的数据而言,图表的信息量要大得多,这也是数据可视化最底子的意图。

2.2 可视化大屏都有哪些部分

主要由 可视化组件 + 事情交互 + 坐标联系 组成,作用如下图所示:

从0到1设计通用数据大屏搭建平台

2.3 可视化大屏和常见的BI报表看板的差异

常常会有同学会问到,可视化大屏和BI报表看板的差异是什么?

这儿简略的做一下介绍:

  1. 大屏和报表看板都只是BI的其间一种展示办法,大屏更多是经过不同尺度的显现器硬件上进行投屏,而报表看板更多是在电脑端进行展示运用。

  2. 大屏愈加重视数据动态变化 ,会有极强的视觉体验和冲击力,供给丰厚的轮播动画、表格滚动等动画特效。而报表看板更重视交互式数据探究剖析,例如上卷下钻、排序、过滤、图表切换、条件预警等。

三、规划思路

3.1 技术选型

  • 前端结构:React 全家桶(个人习惯)

  • 可视化结构:Echarts\DataV-React (封装度高,json结构的装备项易拓宽) D3.js(可视化元素粒度小、定制才能强)

  • 拖拽插件:dnd-kit (满意树状结构视图的跨组件拖拽)

  • 布局插件:React-Grid-Layout(网格自在布局,修正源码,支撑多个方向的拖拽,自在布局、确定缩放比等)

3.2 架构规划

下图是咱们建立渠道的全体架构规划:

从0到1设计通用数据大屏搭建平台

整个大屏建立渠道包含四个非常重要的子系统和模块:

  • **可视化物料中心:**是整个渠道最基础的模块,咱们在开源的图表库和自主开发的可视化组件上面界说了一层规范的 DSL 协议,这个协议和接入 画布修正器 的协议是对应的,目前现已有 40+ 相关组件,组件数量还在不断增长。

  • **画布修正器:**是建立渠道的中心与难点,支撑页面布局装备、页面交互装备和组件数据装备等功用,别的还支撑代码片段的装备,也能够称得上是一个低代码渠道。

  • **数据中心:**是供给专门用于连接不同数据源的服务,例如直连 MySQL、ClickHouse、Elasticsearch、Presto 等,供给了大屏建立所需求的原始数据。

  • **办理中心:**是大屏的后台运营办理模块,包含了大屏模版办理、大屏发布下线、拜访权限等办理功用。

3.3 建立流程

经过上面说到的大屏组成元素,咱们能够剖析总结出大屏建立干流程如下图所示:

从0到1设计通用数据大屏搭建平台

四、中心功用完成

接下来咱们会逐一对渠道几个中心功用完成进行解析:

1、大屏自习惯布局

**背景:**处理页面紊乱问题,完成多种分辨率的大屏适配:

**思考:**首要咱们想到的是移动端适配干流的 vh、vw、rem组合的办法以及 font.js+rem 等两种计划。第一种计划主要是经过媒体查询来界说父级巨细,然后对组件的height、margin、padding等多种css特点选用rem作为单位,承继父级设置等单位(1vw),完成自习惯适配,第二种计划是引用第三方脚本,经过在main.js中写代码核算,运用rem进行承继,完成适配。

① vh、vw、rem组合

//vw vh单位 w3c的官方解说 vw:1% of viewport’s width vh:1% of viewport’s height
//例如,规划稿的宽度为1920px,则1vw=19.2px,为了方便核算,咱们将html元素的font-size巨细设置为100px,也便是5.208vw=100pxbody,html {
     font-size:5.208vw
}

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

② font.js + rem

//监听窗口的oversize事情,来动态核算根节点字体巨细,再配合rem做适配
(function(doc, win) {
    const docEl = doc.documentElement
    const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
    const recalc = function() {
      let clientWidth = docEl.clientWidth
      if (!clientWidth) return
      docEl.style.fontSize = 100 * (clientWidth / 1920) + 'px'
    }
    if (!doc.addEventListener) return
    win.addEventListener(resizeEvt, recalc, false)
    doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

**缺点:**当咱们大屏里边运用到的第三方插件,它的款式运用的是px为单位时,例如 line-height 的设置为20px,此刻就不能习惯行高,就会呈现重叠等紊乱问题。或许咱们利用 postcss-px2rem 插件进行全局替换,但是在运用过程中,需求留意对现已处理过适配的插件,例如 Ant Design,不然引进的antd 控件运用会呈现款式紊乱的问题

**处理思路:**选用了css3 的缩放 transform: scale(X,Y) 特点,主要是经过监听浏览器窗口的 onresize 事情,当窗口巨细发生变化时,咱们只需求根据大屏容器的实际宽高,去核算对应的扩大缩小的份额,就能够完成布局的自习惯了,咱们也供给了不同的布局习惯作用,例如等高缩放、等宽缩放、全屏铺满等,不同的缩放办法,决定了咱们在核算宽高份额的优先级。因而咱们后面在做画布的缩小功用,也能够直接运用这种计划来完成。

// 基于设置的规划稿尺度 换算对应的宽高比
useEffect(() => {
    const wR = boxSize.width / viewWidth;
    const hR = boxSize.height / viewHeight;
    setBgScaleRatio(wR);
    setBgHeightScaleRatio(hR);
}, [boxSize, viewWidth, viewHeight]);
//根据等宽、等高、全屏等不同的缩放份额 核算scale值
const getScale = (proportion, x, y) => {
    if (proportion === 'radioWidth') {
        return `scaleX(${x})`
    }
    if (proportion === 'radioHeight') {
        return `scaleY(${y})`
    }
    return `scale(${x}, ${y})`
}

从0到1设计通用数据大屏搭建平台

2、大屏组件通用开发流程规划

**背景:**跟着可视化组件的增多、新增组件流程繁琐冗长,为了避免重复的造轮子以及后续引进第三方组件,需求制定一套通用的组件开发流程:

**规划思路:**组件 = component 组件主体 + schema 组件装备协议层 + 组件界说层(类型、从属联系、初始化宽高级)

① component 组件主体:

  • **可视化结构选型:**职业干流可视化库有 Echart、Antv、Chart.js、D3.js、Vega、DataV-React 基于可视化的通用性和定制性的需求,咱们挑选了 Echart、DataV-React 作为基础组件的开发结构,面临定制性要求更高的自界说组件,咱们挑选了可视化粒度更小的 D3.js。

  • 封装通用 Echarts 组件(初始化、事情注册、实例注销等):

    // initialization echarts const renderNewEcharts = () => { // 1. new echarts instance const echartObj = updateEChartsOption(); // 2. bind events bindEvents(echartObj, onEvents || {}); // 3. on chart ready if (typeof onChartReady === ‘function’) onChartReady(echartObj); // 4. on resize echartObj.resize(); };

    // bind the events const bindEvents = (instance, events) => { const _bindEvent = (eventName, func) => { instance.on(eventName, (param) => { func(param, instance); }); };

    // loop and bind
    for (const eventName in events) {
        if (Object.prototype.hasOwnProperty.call(events, eventName)) {
            _bindEvent(eventName, events[eventName]);
        }
    }
    

    };

    // dispose echarts and clear size-sensor const dispose = () => { if (chartEl.current) { clear(chartEl.current); // dispose echarts instance (echartsLib || echarts).dispose($chartEl.current); } };

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

  • 封装通用 DataV 组件(DataV-React、自界说等组件进口,统一负责装备、数据搜集、监听resize)

    const DataV: React.FC = (props) => { const { config } = props; const [renderCounter, setRenderCounter] = useState(0); const dataVWarpEl=useRef(null);constdataVWarpEl = useRef(null); const componentEl = useRef(null);

    useEffect(() => {
        // 绑定容器size监听
        const resizefunc = debounce(() => {
            $componentEl.resize();
        }, 500)
       // fixme
       addResizeListener($dataVWarpEl.current, resizefunc);
       return () => {
           // 铲除订阅
           removeResizeListener($dataVWarpEl.current, resizefunc);
       };
    }, []);
    return (
        <DataVWarp ref={$dataVWarpEl}>
            <CompRender config={config} ref={$componentEl} />
        </DataVWarp>
    );
    

    };

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

② schema 组件装备协议层 + 组件界说层(类型、从属联系、初始化宽高级)

咱们自界说了一套 schema 组件的DSL,结构协议层。经过DSL约好了组件的装备协议,包含组件的可修正特点、修正类型、初始值等,之所以界说一致的协议层,主要是方便后期的组件扩展,装备后移。

从0到1设计通用数据大屏搭建平台

  • JSON Schema规划:

    { headerGroupName: ‘公共装备’, //装备所属类型 headerGroupKey: ‘widget’, //装备所属类型key值 相同的key值都归属一类 name: ‘标题称号’, //特点称号 valueType: [‘string’], //特点值类型 optionLabels: [], //服务下拉列表、多选框等控件的标签名 optionValues: [], //服务下拉列表、多选框等控件的标签值 tip: false, //装备项的 Tooltip 注解 ui: [‘input’], //运用的控件类型 class: false, //控件类名,定制控件款式 css: { width: ‘50%’}, //修正控件款式 dependencies: [‘widget,title.show,true’], //特点之间的联动,规则[‘装备所属类型, 特点key, 特点值’] depContext: DepCommonShowState, //特点之间的校验回调办法 compShow: [‘line’], //哪些组件可装备 dataV: { key: ‘title.text’, value: ” }, //装备的key值和默认value值 },

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

  • 表单DSL规划:

从0到1设计通用数据大屏搭建平台

**收益:**以上是咱们定制的DSL结构协议层,用户只需求填写Excel表格,就能够完成动态表单的创建,完成组件装备项分类、装备复用、装备项之间联动、特点注释等功用。目前特点装备器现已支撑了常用的15种的装备UI控件,经过定制的DSL结构协议层,能够快速完成组件的装备界面初始化,为后续规划的组件物料中心做准备。

3、拖拽器完成

**背景:**React-Grid-Layout 拖拽插件不支撑自在布局和组件不同纬度拖拽:

**处理计划:**经过剖析源码,对不同纬度的拖拽事情以及拖拽方针磕碰事情进行了重写,而且也拓宽了确定宽高比、旋转透明度等功用。

源码剖析:

从0到1设计通用数据大屏搭建平台

resize弹性特性增强(优化),拖拽的同时,除了修正容器宽高外,也动态调整了组件的坐标位置

// CSS Transforms support (default)
if (useCSSTransforms) {
    if (activeResize) {
        const { width, height, handle } = activeResize;
        const clonePos = { ...pos };
        if (["w", "nw", "sw"].includes(handle)) {
            clonePos.left -= clonePos.width - width;
        }
        if (["n", "nw", "ne"].includes(handle)) {
            clonePos.top -= clonePos.height - height;
        }
        style = setTransform(clonePos, this.props.angle);
    } else {
        style = setTransform(pos, this.props.angle);
    }
}

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

堆叠显现,自在布局(优化),经过操控布局是否紧缩,动态调整拖拽方针的层级zIndex来完成多图层组件操作交互和自在定位。

// 每次拖拽时zIndex要在当前最大zIndex基础上 + 1,并返回给组件运用
const getAfterMaxZIndex = useCallback(i => {
    if (i === curDragItemI) {
        return;
    }
    setCurDragItemI(i);
    setMaxZIndex(maxZIndex => maxZIndex + 1);
    return maxZIndex;
}, []);

从0到1设计通用数据大屏搭建平台从0到1设计通用数据大屏搭建平台

改造后作用展示

从0到1设计通用数据大屏搭建平台

4、大屏状态推送

**背景:**大屏的后期保护需求有版本发布自更新以及大屏下线等需求,这个时分就需求有一套消息告诉机制,经过指令来操控大屏的运行状态。

**处理计划:**基于websocket通信机制,建立长链接,完成了心跳及重连机制,实时对上线发布后的大屏进行更新或下线办理。

从0到1设计通用数据大屏搭建平台

五、作用预览

六、总结

本文经过可视化页面建立、no/low code 渠道、Schema 动态表单等技术思想来剖析讲解了如何去规划开发一个通用的数据大屏建立渠道。

当前的规划计划基本满意了数据大屏的中心才能建立需求。如果想完成更赋有展示力, 满意更多场景的大屏建立渠道, 咱们还需求进一步提高渠道的扩展性和完善全体的物料生态, 详细规划如下:

  • 丰厚和拓宽大屏组件&装备才能,覆盖不同职业的可视化场景。

  • 可视化物料渠道的建立,沉淀优秀的可视化组件、大屏模版资料。

  • 3D以及动效渲染引擎开发完成。