写点什么

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

  • 2021-03-17
  • 本文字数:5190 字

    阅读完需:约 17 分钟

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

背景


随着公司业务的发展,经常会收到一些数据大屏的需求。目前我司有两种实现方案,一是人肉搭建,二是用阿里云 DataV 搭建。


人肉搭建,在本地脚手架开发环境中进行编码,有大量的重复劳动,能力复用性差,占用前端宝贵的开发时间。


DataV 功能强大,但需要付费使用,且好用的组件还要额外收费,不支持本地化部署,还需要维护两套数仓。


综上,如果此类大屏的需求较多,业务的重要性明显,就需要考虑是不是需要自己开发一套搭建大屏的系统,用以降低开发复杂度,提升研发效率,降低成本。本文尝试基于政采云前端团队的数据大屏搭建系统 Big 的拆解说明,为大家提供一种此类系统的设计和实施方案。


Big 是什么


Big 是基于政采云前端搭建系统 鲁班,和数据大屏组件库,进行快速搭建数据大屏的可视化系统。

为什么叫 Big 呢? 打开百度翻译,输入大屏,英文翻译是 Big screen,四舍五入叫 Big


自己做一套系统的优势


  • 可定制性:内部产品,组件和展示形式私人订制

  • 支持本地化部署:业务需要决定部分业务只能在内网访问,无法访问外网(包括阿里云)

  • 解决 DataV 需要维护两套数仓的问题

  • 节约公司成本,增强公司数据产品能力,助力营收


总览


数据大屏是用可视化的方式展示庞杂数据的产品,经常会用在会议展览、业务监控、风险预警、地理信息分析等多种业务场景。下图是阿里云 DataV 的一个模板:



从前端实现来看,大屏是由线图、柱状图、饼图、标题、背景、边框等基本元素组成。实现思路是以这些基本元素为组件,通过选择组件、拖拽方式布局,配置样式、数据来源,将这些数据保存在数据库中。展示页面获取依赖的组件、样式和数据信息,呈现给用户。


大屏按场景划分,可分为编辑和查看。

编辑:指的是大屏制作者制作大屏。

查看:包含两种情况,大屏制作者预览和实际用户查看大屏。


编辑


编辑大屏是数据可视化系统核心,页面布局参考 DataV:

拆解为 4 个部分:顶部、组件区、画布、数据配置区。先讲下设计思路,再依次分解各区。


设计思路


  • 页面数据和依赖的组件由 SSR (https://juejin.im/post/5b063962f265da0ddb63dac3) 注入到 HTML 文件中

  • App 数据保存在 App state 中,未使用 Vuex(后续会考虑使用 Vuex)

  • 数据用 props 传递给子组件

  • 数据从子组件采用事件中心传递给祖父级组件

顶部


顶部区域包含三部分:左侧开关区、控制图层、组件列表、数据配置区的显示隐藏;中间是大屏的标题;右侧是保存和预览。

组件区


组件区分为左侧图层(已添加的组件)和右侧组件列表,具备添加组件、选择操作图层、分组对齐的功能。

图层

  • 图层支持上移、下移、置顶、删除的操作,支持右键显示操作菜单(暂不支持多选和分组)。实现原理是使用数组的基本方法改变数组

  • 单击组件选择该组件,画布区选中组件,数据配置区显示配置项

组件列表

  • 所有组件展示所有大屏组件,点击或拖动添加组件

  • 添加组件采用异步获取组件的 JS、CSS 、配置 Schema,将 CSS、JS 插入 DOM 中,配置传入属性配置区

  • 支持按组件类型分组,便于用户使用。


画布


画布用于实时展示大屏组件的位置、尺寸、属性和数据修改后的效果。


位置和尺寸改变通过注册组件 vue-draggable-resizable 的 drag 和 resize 方法,改变对应组件的属性。组件采用绝对定位,拖动时修改 top 和 left 的值。


属性改变通过修改对应组件的 props.models 的值修改。


数据分为静态数据和接口数据。启用静态数据时,数据从用户填写的数据获取。否则组件 watch 接口 id ,每次改变时重新发送请求获取数据。


画布上边和左边是标尺,画布缩放时标尺要跟随变动。在标尺上移动时显示一条移动的参考线。点击时增加一条参考线。双击参考线删除。标尺用 Canvas 画出,旋转 90 度可获得 Y 轴。


右下是缩放滑块,方便用户缩放查看。进入页面默认缩放到可查看全屏大小。缩放实现使用 CSS3 的transform: scale(${this.scale})


画布上未选择组件时,显示页面的基本配置,包括大屏的宽高、背景图。


选择组件后,高亮显示当前组件,标识位置,右侧数据配置区显示组件 Schema 定义的配置项。


核心代码


<div  v-for="item in preCompList"  :class="[    'data-com',    item.info.previewId === activePreviewId ? 'data-com-active' : ''  ]"  :key="item.info.activePreviewId">  <vue-draggable-resizable    :w="item.models.width || 100"    :h="item.models.height || 100"    :x="item.models.x || 0"    :y="item.models.y || 0"    :active="item.info.previewId === activePreviewId"    @dragging="onDrag"    @resizing="onResize"    @activated="      () => {        onCompActivated(item.info.previewId);      }"      :prevent-deactivation="true">    <navigator-line      :x="item.models.x"      :y="item.models.y"      :scale="scale"    />    <div       :is="item.info.name"       :models="item.models"       :extraProps="extraProps">    </div>    </vue-draggable-resizable></div>
复制代码

vue-draggable-resizable (https://npm.taobao.org/package/vue-draggable-resizable) 用于选择组件、缩放组件大小,可参考官方文档。这个组件不支持分组和多选对齐场景,需要定制开发。


navigator-line 显示组件当前的标尺位置。这里要注意避免因为画布缩小导致坐标看不清,除以缩放比例即可。

使用 Vue 动态组件 is (https://cn.vuejs.org/v2/api/#is) 控制组件显示。


数据配置区


数据配置区有 2 种情况:


  • 未选中组件展示页面级配置:大屏宽高、背景色、背景图等

  • 选中组件:展示组件配置信息


实现逻辑:根据当前用户的选择来动态渲染出组件的属性编辑域,并回填属性的初始值,从而达到良好的编辑交互效果。用户拖拽组件时同步更新编辑域中的属性值,在属性编辑域修改属性时通知大屏触发组件的刷新动作,达到实时编辑的效果。


数据配置区界面由组件 Schema 定义,props 定义展示,models 表示默认数据,详细介绍见下面 Schema。


编辑类型由 fileds 里的 type 决定,实现 Input、Select、Image、Border 等各种类型组件,再利用 Vue 的动态组件 is 属性来展示。


数据回传:每个子组件值的修改会通知父组件 <Setting /> 更新回传给父组件 App,这里采用全量回传,避免 App 对 models 查找更新数据。


查看


查看是将数据库里保存的数据,配合组件渲染出来。实现原理是通过页面 id 获取组件、数据渲染。代码如下:


<div class="preview">  <div class="layout">    <div      :class="[        'preview-line',        preComp.info.name + '-' + preComp.info.previewId      ]"      v-for="(preComp, index) in preCompList"      :key="preComp.info.previewId"      :style="formatCompStyle(preComp, index)"    >      <div        :is="preComp.info.name"        :models="preComp.models"        :isPreview="isPreview"        :extraProps="extraProps"></div>    </div>  </div></div>
复制代码

全屏展示


需要注意大屏是全屏展示,根据大屏配置的屏幕宽高、背景图、背景色设置 body 样式,设置 <meta name="viewport" content="width=' + window.screen.width + '"/> viewport 的 width 让屏幕占满全屏,再监听屏幕的变化设置压缩比例。自适应关键代码如下:


// 获取设置的大屏宽高、背景图、背景色if (window.__INITIAL_STATE__) {  const { width, height, backgroundImage, backgroundColor } =        __INITIAL_STATE__.preview.pageConfig.models;  window.scr = {    width: width,    height: height,    backgroundImage: `url(${backgroundImage})`,    backgroundColor: backgroundColor,  };} else {  window.scr = {    width: window.screen.width,    height: window.screen.height,  };}
// 全屏展示function resizeFull() { if (!window.scr.height || !window.scr.width) return resizeFullBak(); var ratioX = $(window).width() / window.scr.width; var ratioY = $(window).height() / window.scr.height; $('body').css({ transform: "scale(" + ratioX + ", " + ratioY + ")", transformOrigin: "left top", backgroundSize: "100% 100%", });}function resizeFullBak() { var ratioX = $(window).width() / $('body').width(); var ratioY = $(window).height() / $('body').height(); $('body').css({ transform: "scale(" + ratioX + ", " + ratioY + ")", transformOrigin: "left top", backgroundSize: "100% " + ratioY * 100 + "%", });}
复制代码

组件设计


组件是整个大屏设计的基础。组件由组件模板来初始化,模板提供了两个主要功能,一是实现一个可开发的简单 Demo,二是提供打包发布功能。


模板代码很简单,通过传入的 props 控制组件的展示和业务逻辑。组件自动安装,这样在异步加载组件的时候页面可以识别组件。重点讲下组件的 Schema 设计。


schema.json


schema.json 是用来定义组件的可编辑项和默认配置。决定组件哪些东西可以配置,配置的形式是什么样子的(Input、Select 等有默认值)。所以 Schema 包含 props 和 models 两个属性。


props: 数组,每个元素是 tab 的一项。info 是 tab 头部信息,fields 是配置项。fields 的 name 对应 models 的属性名,type 决定了配置的类型,title 是中文名。还可以定义其他属性,比如下拉框选择项、数字输入框最大最小值等。


models: 默认数据,props.fileds 里每个 name 的默认值。

下面是一个简单 Schema 的定义:


{  "props": [    {      "info": {        "title": "配置",        "icon": "icon-setting"      },      "fields": [        {          "title": "组件宽度",          "name": "width",          "description": "组件宽度",          "type": "number"        },        {          "title": "组件高度",          "name": "height",          "description": "组件高度",          "type": "number"        },        {          "title": "x轴坐标",          "name": "x",          "description": "组件x轴坐标",          "type": "number"        },        {          "title": "y轴坐标",          "name": "y",          "description": "组件y轴坐标",          "type": "number"        }      ]    }  ],  "models": {    "width": 300,    "height": 200,    "x": 0,    "y": 0  }}
复制代码


碰到的问题

通信

大屏组件之间如何通信?要确保大屏组件可以通信。

采用事件中心来处理组件间的通信。核心代码如下:

// 全局事件中心Vue.prototype.$eventBus = new Vue();// 触发, 在组件内部this.$eventBus.$emit('eventName', '这里传值');// 监听, 获取值this.$eventBus.on('eventName', v => {  console.log(v);})
// 组件通知父组件区划变动或其他变动this.$eventBus.$emit('component__update-extraProps', { dist: '选择的区划' });
复制代码

App 统一管理通信对象 extraProps,以 props 形式注入到每个组件。组件可以监听 extraProps 的属性变化。

// 组件代码{  ...,  props: {    extraProps: {      type: Object,      default: () => {}    }  },  computed: {    dist() {      return (this.extraProps && this.extraProps.dist) || '';    }  },  watch: {    dist(val, oldVal){      // 添加区划改变时获取新数据的逻辑    }  }}
复制代码


权限


大屏数据需要做权限控制,有权限的人才能查看大屏,而鲁班原来页面访问逻辑是没有权限的。实现方案是编辑、预览页面调用的免登接口访问中间 Server,中间 Server 实现登录,去 Server 请求数据。用户的查看页面内嵌鲁班 iframe,该地址由实际服务器提供并带上权限 token。访问该鲁班地址时先去 Server 鉴权,有权限返回大屏页面,否则返回 401。



待优化


Big 处于初级阶段,还有好多地方需要完善:


  • 分组:像 PS、Sketch 里一样分组,方便归类和操作

  • 多选:多选后选择对齐方式。也是方便用户操作

  • 代码优化

  • 体验优化


总结


DT 时代,数据可视化将会越来越重要。相信有越来越多的同学会遇到大屏的场景。通过可视化搭建大屏系统,可以赋能相关的业务方,让非专业人士做出专业的大屏效果,同时满足公司的一些定制化需求。这里做了一个比较浅的大屏构建方案,目前还在开发阶段,希望抛砖引玉,有更多的可视化数据搭建方案分享出来,谢谢阅读。



头图:Unsplash

作者:明明

原文:https://mp.weixin.qq.com/s/j2dx5S2TWXpznfh3zPthYA

原文:可视化搭建数据大屏系统的前端实现

来源:政采云前端团队 - 微信公众号 [ID:Zoo-Team]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021-03-17 00:446169

评论 1 条评论

发布
用户头像
感谢分享,推荐一个好用的接口管理工具apipost,支持mac,windows,linux,多个平台。特别方便
2021-09-01 18:02
回复
没有更多了
发现更多内容

智慧社区管理平台建设,智慧平安小区整体解决方案

t13823115967

智慧社区安防系统平台开发

这道面试题,出错率90%

田维常

面试

Python的GIL

yunson

Python GIL

区块链钱包开发的功能与特点

程序员修炼之路:你该知道的 7 个必经阶段

阿里巴巴云原生

阿里云 程序员 云原生 自我思考 成长笔记

纵观 ActiveX 平台的兴衰史,看开发控件的技术演变

葡萄城技术团队

SpreadJS activex

区块链数字货币交易所开发的简介

2020年11期券商App行情刷新及交易体验评测报告

博睿数据

APM 数据 AIOPS 证券

Flink SQL 实战:双流 join 场景应用

Apache Flink

flink 流计算

我参与阿里巴巴 ASoC-Seata 的一些感悟

阿里巴巴云原生

阿里云 开发者 云原生 感悟 seata

甲方日常 79

句子

工作 随笔杂谈 日常

RocketMQ消息模型

废材姑娘

Java RocketMQ

7 天开发后台系统技术小结

老魚

程序员 全栈 建站

国外低代码平台趟过那些坑,对国内低代码企业有哪些启示?

DT极客

有没有听说过通达快递?

escray

极客时间 极客大学 课程作业 大作业 架构师训练营第 1 期

数字货币交易所开发的功能与特点

对冲基金的子基金模式vs集中管理

9527

区块链钱包开发的核心优势

漫画 | 带你领略前端发展史的江湖恩怨情仇

苏南

程序员 大前端 漫画 时代发展

智慧公安防控管理平台搭建,重点人员管控系统解决方案

t13823115967

智慧公安

LINUX SHELL脚本攻略

田维常

Ubuntu 使用 Iptables 做网络转发

wong

iptables Ubuntu20.04

区块链商城系统开发技术详解

千里公路建设尽收眼底,3D可视化监测管养运,领导都惊呆了

一只数据鲸鱼

物联网 数据可视化 3D可视化 公路建设 智慧交通

数仓缓慢变化维深层讲解

大数据老哥

大数据 数据仓库 数仓

mysql binlog轻量同步工具binlog portal

dothetrick

Java MySQL springboot Binlog spring Boot Starter

币币交易所系统开发详情说明

区块链app开发要多少钱?如何根据项目需求了解价格?

《数据挖掘:实用的机器学习工具和技术,第4版》PDF版免费下载

计算机与AI

数据挖掘 机器学习 数据科学

大作业1

蓝黑

区块链挖矿系统开发功能方案

可视化搭建数据大屏系统的前端实现_语言 & 开发_政采云前端团队_InfoQ精选文章