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

一、前言

一直以来,许多产品平台都在尝试通过可视化搭建的手段来降低 GUI 应用的研发门槛,提高生产效率。随着我们业务的发展,数据建设的完善,用户对于数据可视化的诉求也日益增多,而数据大屏是数据可视化的其中一种展示方式,它作为大数据展示媒介的一种,被广泛运用于各种会展、公司展厅、发布会等。

相比于传统手工定制的图表与数据仪表盘,通用大屏搭建平台的出现,可以解决定制开发, 数据分散带来的应用开发、数据维护成本高等问题,通过数据采集、清洗、分析到直观实时的数据可视化展现,能够多方位、多角度、全景展现各项指标,实时监控,动态一目了然。

本文将通过敏捷BI平台的通用大屏搭建能力的实现方案,来讲解一下通用可视化搭建平台整体的设计思路。

二、快速了解可视化大屏

2.1 什么是数据可视化

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

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

所以在数据领域里,对于复杂难懂且体量庞大的数据而言,图表的信息量要大得多,这也是数据可视化最根本的目的。

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

主要由 可视化组件 + 事件交互 + 坐标关系  组成,效果如下图所示:

2.3 可视化大屏和常见的BI报表看板的区别

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

这里简单的做一下介绍:

  1. 大屏和报表看板都只是BI的其中一种展现方式,大屏更多是通过不同尺寸的显示器硬件上进行投屏,而报表看板更多是在电脑端进行展示使用。

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

三、设计思路

3.1 技术选型

  • 前端框架:React 全家桶(个人习惯)

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

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

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

3.2 架构设计

下图是我们搭建平台的整体架构设计:

整个大屏搭建平台包含四个非常重要的子系统和模块:

  • 可视化物料中心:是整个平台最基础的模块,我们在开源的图表库和自主开发的可视化组件上面定义了一层标准的 DSL 协议,这个协议和接入 画布编辑器 的协议是对应的,目前已经有 40+ 相关组件,组件数量还在不断增长。

  • 画布编辑器:是搭建平台的核心与难点,支持页面布局配置、页面交互配置和组件数据配置等功能,另外还支持代码片段的配置,也可以称得上是一个低代码平台。

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

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

3.3 搭建流程

通过上面提到的大屏组成元素,我们可以分析总结出大屏搭建主流程如下图所示:

四、核心功能实现

接下来我们会逐一对平台几个核心功能实现进行解析:

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=100px。
body,html {font-size:5.208vw
}

②  font.js + rem

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

缺陷:当我们大屏里面使用到的第三方插件,它的样式使用的是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})`
}

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 instanceconst echartObj = updateEChartsOption();// 2. bind eventsbindEvents(echartObj, onEvents || {});// 3. on chart readyif (typeof onChartReady === 'function') onChartReady(echartObj);// 4. on resizeechartObj.resize();
};// bind the events
const bindEvents = (instance, events) => {const _bindEvent = (eventName, func) => {instance.on(eventName, (param) => {func(param, instance);});};// loop and bindfor (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);}
};
  • 封装通用 DataV 组件(DataV-React、自定义等组件入口,统一负责配置、数据收集、监听resize)

const DataV: React.FC<DataVProps> = (props) => {const { config } = props;const [renderCounter, setRenderCounter] = useState(0);const $dataVWarpEl = useRef(null);const $componentEl = useRef(null);useEffect(() => {// 绑定容器size监听const resizefunc = debounce(() => {$componentEl.resize();}, 500)// fixmeaddResizeListener($dataVWarpEl.current, resizefunc);return () => {// 清除订阅removeResizeListener($dataVWarpEl.current, resizefunc);};}, []);return (<DataVWarp ref={$dataVWarpEl}><CompRender config={config} ref={$componentEl} /></DataVWarp>);
};

② schema 组件配置协议层 + 组件定义层(类型、从属关系、初始化宽高等)

我们自定义了一套 schema 组件的DSL,结构协议层。通过DSL约定了组件的配置协议,包括组件的可编辑属性、编辑类型、初始值等,之所以定义一致的协议层,主要是方便后期的组件扩展,配置后移。

  • 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值
},
  • 表单DSL设计:

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

3、拖拽器实现

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

解决方案:通过分析源码,对不同纬度的拖拽事件以及拖拽目标碰撞事件进行了重写,并且也拓展了锁定宽高比、旋转透明度等功能。

源码分析:

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);}
}

堆叠显示,自由布局(优化),通过控制布局是否压缩,动态调整拖拽目标的层级zIndex来实现多图层组件操作交互和自由定位。

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

改造后效果展示

4、大屏状态推送

背景:大屏的后期维护需要有版本发布自更新以及大屏下线等需求,这个时候就需要有一套消息通知机制,通过命令来控制大屏的运行状态。

解决方案:基于websocket通信机制,建立长链接,实现了心跳及重连机制,实时对上线发布后的大屏进行更新或下线管理。

五、效果预览

六、总结

本文通过可视化页面搭建、no/low code 平台、Schema 动态表单等技术思想来分析讲解了如何去设计开发一个通用的数据大屏搭建平台。

当前的设计方案基本满足了数据大屏的核心能力搭建需求。如果想实现更富有展现力, 满足更多场景的大屏搭建平台, 我们还需要进一步提高平台的扩展性和完善整体的物料生态, 具体规划如下:

  • 丰富和拓展大屏组件&配置能力,覆盖不同行业的可视化场景。

  • 可视化物料平台的搭建,沉淀优秀的可视化组件、大屏模版素材。

  • 3D以及动效渲染引擎开发实现。

可视化源码获取

请加下方微信(dataclub_bigdata),回复:可视化 获取

(备注:行业-职位-城市)

公众号推送规则变了

点击上方公众号名片,收藏公众号,不错过精彩内容推送!

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

  1. 《七天数据可视化之旅》第七天:可视化设计实战-数据大屏

    <七天数据可视化之旅>第七天:可视化设计实战-数据大屏 Destiny,某物流公司数据产品经理,目前从事数据平台搭建和可视化相关的工作.持续学习中,期望与大家多多交流数据相关的技术和实际应 ...

  2. 【大屏设计】数据大屏间距那点事-距离产生美

    这两张图有什么不同? 图片一 (注:未统计到台湾省数据,上图台湾省颜色为白色) 图片二 (注:未统计到台湾省数据,上图台湾省颜色为白色) 这两张图如果你看不出来有什么区别,那么建议这篇文章可以抽空看一 ...

  3. 从0到1开发可视化数据大屏

    前言:大数据时代,以大屏为载体的数据可视化需求日渐增多,数据大屏成为越来越多企业绩效展示,报表展示,业务监控等等的一种形式,大屏的上线带来的是便捷,无需编码,用户可以直接将所要呈现的组件拖拽到画布上, ...

  4. web大屏展示用到的组件_从零开始设计数据大屏—基于Vue

    为什么要做数据大屏? 现如今的大数据逐渐发挥出了它的力量,并无形的改变着我们的生活.但大数据在不是从事技术开发的人来说没有很明显的感受,很多人对大数据的概念只是停留在每年网易云音乐对个人听歌的汇总上. ...

  5. 可视化大数据大屏设计

    可视化大数据大屏设计 一.如何做好一款大屏 1.1工具的选择 帆软报表工具Finereport 1.2大屏设计 通用的大屏设计原则 1.大屏指标在8-12个为宜 2.比率类.数字类和子部分布类指标要合 ...

  6. 0代码搭建数据大屏技术 - 观远(AI+BI)商业智能数据分析平台

    大数据时代,企业的任何规划和决策都离不开数据分析的支撑.领导开会要看数据,项目拉投资要看数据,活动复盘要看数据-- 而传统的看数据方式要提前知晓领导需要哪些维度的数据,再由数据分析师基于历史数据做好报 ...

  7. 可视化搭建数据大屏系统的前端实现

    随着公司业务的发展,经常会收到一些数据大屏的需求.目前我司有两种实现方案,一是人肉搭建,二是用阿里云 DataV 搭建. 人肉搭建,在本地脚手架开发环境中进行编码,有大量的重复劳动,能力复用性差,占用 ...

  8. 数据卡片_手把手教你构建企业实时数据大屏

    大数据时代,企业的任何规划和决策都离不开数据分析的支撑.领导开会要看数据,项目拉投资要看数据,活动复盘要看数据-- 而传统的看数据方式要提前知晓领导需要哪些维度的数据,再由数据分析师基于历史数据做好报 ...

  9. 手把手教你搭建可视化数据大屏

    可视化现在也是越来越卷了,层出不穷的图表样式和各种各样的色彩搭配让人目不暇接,当然其中站在卷的顶峰的还是可视化数据大屏.就像下面这样: 但是怎么搭建呢,是不是很难呢?今天就带大家手把手搭建可视化数据大 ...

  10. 数据大屏 - guandata智能数据可视化分析

    数据大屏可视化可更直观更智能的决策场景体验,通过数据大屏实时监测企业数据,洞悉运营增长,助力智能高效决策. 数据大屏可以打破数据隔离,通过数据采集.清洗.分析到直观实时的数据可视化,从而达到高效管理决 ...

最新文章

  1. Windows搜索工具 — Everything
  2. jquery实现心算练习
  3. chrome添加来自其他网站的扩展程序
  4. marker主题 ros_(五)ROS主题理解
  5. Python 3 mysql 简介安装
  6. 【C++入门】C++ 输入输出和文件操作
  7. layer —— 一个简单的jQuery弹出层插件
  8. 未能加载文件或程序集“System.Data.SQLite.DLL”或它的某一个依赖项
  9. 使用SCRT操作CentOS,实现上传下载文件
  10. 多线程QThread的两种启用用法
  11. python是一门_人人用Python 篇一:Python是一门人人可掌握的手艺
  12. 百度关键词地区排名查询php源码,百度关键词地区排名查询
  13. html5页面交互,H5的交互原型设计
  14. 栈的输出_程序设计做题笔记:计算表达式(一):栈
  15. 计算机数字顺序怎么带公式,Excel函数公式:6个数据排序技巧,总有一个适合你!...
  16. 深度学习基础:1x1的卷积为什么代替全连接
  17. PADS9.5使用笔记(常用功能和疑难问题)
  18. 从Python看C语言(列表字典篇)
  19. 2021美团笔试秋招后台高清
  20. 智源承认论文抄袭,相关责任人已离职!

热门文章

  1. 创作swing 绝对布局 窗口事件 鼠标事件 键盘事件 上传头像流程
  2. sql语句中----删除表数据的三兄弟
  3. 格局炸裂,程序员必看的十部纪录片
  4. U-Boot下的I2C设备的读写
  5. CRichEditDoc下保存文档出现\rtf1\ansi\ansicpg936\deff0的解决方法
  6. 中石油 所罗门的宝藏
  7. ubuntu 替换清华源遇到的问题-不能更新,无法拉取 https 源解决
  8. python数据分析岗位做什么_Python数据分析--数据分析岗位最新招聘情况
  9. 51单片机最小系统板制作
  10. 前端工程师的前途与价值体现