写点什么

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

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

评论 1 条评论

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

没有性能指标,无法开展性能测试吗?

老张

性能测试 需求分析 质量保障

蓝易云 - STL算法大全

百度搜索:蓝易云

c++ 云计算 Linux 运维 云服务器

蓝易云 - 编写的Snort规则不报警怎么办?

百度搜索:蓝易云

运维 云服务器 规则 服务器租用 Snort

线上签约哪家强?9款热门系统全面评测

爱吃小舅的鱼

电子合同 企业管理软件 电子签名软件 线上签约系统

软通动力入选“北京市通用人工智能产业创新伙伴计划(第三批)”

财见

百度2024高考大数据出炉:这所西南高校受欢迎度逆袭清华

Geek_2d6073

1688商品详情数据接口

tbapi

1688 1688API 1688商品详情数据接口 1688商品数据采集

文本生成模型API比拼!KimiGPT 和 GLM-4 哪个更适合你?

幂简集成

AI API

蓝易云 - Django数据库类库MySQLdb使用详解

百度搜索:蓝易云

django Linux 运维 云服务器 mysqldb

揭秘MySQL TLS:通过抓包了解真实的加密通信

张俭

MySQL

GaussDB(DWS)性能调优,解决DM区大内存占用问题

华为云开发者联盟

大数据 华为云 华为云开发者联盟 华为云GaussDB(DWS) 企业号2024年7月PK榜

中小企业数字化转型低代码开发平台使用指南

快乐非自愿限量之名

低代码 数字化

StarRocks 3.3 重磅发布,Lakehouse 架构发展进入快车道!

StarRocks

英特尔至强处理器助力Aible优化AI解决方案,大幅降低生成式AI成本

E科讯

彻底解决大模型训练集群的网络哈希冲突,百度百舸的高性能网络 HPN 落地实践

Baidu AICLOUD

哈希冲突 网络加速 大模型训练 GPU通信

AR没前景?我不相信!

AR玩家

AR Rokid Vision pro 炬目AR

快手Vision Pro版实测体验!沉浸模式,刷视频绝了!

快手技术

客户端 快手 Vision pro

蓝易云 - uniapp的u-album组件自定义删除功能

百度搜索:蓝易云

Linux 运维 App 云服务器 album

蓝易云 - 怎样在国内使用国外服务器

百度搜索:蓝易云

云计算 运维 服务器 云服务器 服务器租用

清凉必备!天翼云夏季科学防暑指南请查收

编程猫

看电影,学项目管理

凌晞

项目管理 项目经理

WAVE SUMMIT产业论坛圆满落地,百度安全护航大模型产业平稳健康发展

百度安全

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