写点什么

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

  • 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:446198

评论 1 条评论

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

应用升级SpringCloud版本时的注意事项(Dalston升级到Edgware)

程序员欣宸

spring Spring Cloud 6月月更

融云通信“三板斧”,“砍”到了银行的心坎上

融云 RongCloud

SAP Marketing Cloud 功能概述(三)

汪子熙

SaaS SAP 云应用 6月月更 Marketing Cloud

【直播回顾】战码先锋第七期:三方应用开发者如何为开源做贡献

OpenHarmony开发者

OpenHarmony

保险APP适老化服务评测分析2022第06期

易观分析

保险APP

初中级开发如何有效减少自身的工作量?

百家饭隐私计算平台创业者

开发 书籍推荐

web前端培训怎么修改 node_modules 中的文件

@零度

node.js 前端开发

详解kubernetes备份恢复利器 Velero | 深入了解Carina系列第三期

BoCloud博云

Kubernetes 云原生 数据备份

初识云原生安全:云时代的最佳保障

SEAL安全

云原生安全

「开源摘星计划之操作系统100人」发布,共建操作系统开源人才生态

腾源会

知识经济时代,教会你做好知识管理

小炮

在 Django 中呈现 HTML 表单(GET 和 POST)

海拥(haiyong.site)

Python django 6月月更

P2PDB 白皮书

Rock-李益

区块链 去中心化数据库

Linux开发_BMP图片编程(翻转、添加水印)

DS小龙哥

6月月更

LRU 原理与算法实现

Ayue、

LRU

居家办公更要高效-自动化办公完美提升摸鱼时间 | 社区征文

迷彩

Python AI 6月月更 初夏征文 Python自动化办公

4个不可不知的“安全左移”的理由

SEAL安全

安全左移 shift left

敏捷之道 | 敏捷开发真的过时了么?

LigaAI

敏捷 敏捷开发 敏捷软件开发 敏捷宣言 LigaAI

龙蜥开发者说:首次触电,原来你是这样的龙蜥社区? | 第 8 期

OpenAnolis小助手

Linux 开源 故事 龙蜥社区 开发者说

一文讲透研发效能!您关心的问题都在 ‍

思码逸研发效能

研发效能

青藤入选工信部网安中心“2021年数字技术融合创新应用典型解决方案”

青藤云安全

网络安全 工信部 主机安全

大数据培训Spark 高频面试考点分享

@零度

spark 大数据开发

SAP Marketing Cloud 功能概述(四)

汪子熙

云原生 SaaS SAP 6月月更 Marketing Cloud

《梦华录》要大结局了,看超前点映不如先来学学它!

博文视点Broadview

远程办公之:在家露营办公小工具| 社区征文

甜甜的白桃

初夏征文

保健品一物一码防窜货营销软件开发

开源直播系统源码

软件开发 app源码

java技术培训在 MySQL 中使用枚举需要注意什么

@零度

JAVA开发 枚举

如何在物联网低代码平台中进行任务管理?

AIRIOT

低代码 物联网

AS深圳站来了!参与讨论领取官方限量周边!

InfoQ写作社区官方

热门活动 ArchSummit

快手实时数仓保障体系研发实践

Apache Flink

大数据 flink 编程 流计算 实时计算

钛星数安加入龙蜥社区,共同打造网络安全生态

OpenAnolis小助手

开源 龙蜥社区 合作 CLA 钛星数安

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