hi, 各人好, 我是徐小夕.
5年前就开始动手设计和研发可视化大屏编辑器, 其时低代码在国内还没有现在那么火, 有人欢喜有人哀, 那个时间我就比力坚定的认为无码化搭建未来一定是个趋势, 能极大的资助企业提高研发服从和低沉研发成本, 所以 all in 做了2年, 上线了一个相对闭环的MVP可视化大屏搭建平台——V6.Dooring.
通过在技能社区不断的分享可视化搭建的技能实践和设计思路, 也参与了很多线上线下的技能分享, 慢慢市场终于“热了”起来.(机缘巧合)
从V6.Dooring的技能架构的设计, 到团队组建, 再到资助企业做解决方案, 其时险些所有的周末都花在这上面了, 想想劳绩还是挺大的, 接触到了形形色色的企业需求, 也不断完整着可视化大屏编辑器的功能, 最后推出了一个还算通用的解决方案:
固然上面介绍的还都不是这篇文章的重点.
重点是, 时隔4年, 我们打算把通用的可视化大屏解决方案, 开源!
一方面是供各人学习参考, 更好的解决企业自身的业务需求, 另一方面可以提供一个技能交换的平台, 各人可以对可视化搭建领域的技能实践, 提出本身的想法和观点, 共同打造智能化, 体验更好的搭建产品.
先上github地址: https://github.com/MrXujiang/v6.dooring.public
V6.Dooring开源大屏编辑器演示
其实最近几年我在公众号分享了很多零代码和可视化搭建的技能实现和产品设计:
这里为了让各人更近一步了解V6-Dooring可视化大屏编辑器, 我还是会从技能设计到产品解决方案设计的角度, 和各人详细分享一下, 让各人在学习我们可视化大屏开源方案的过程中, 对可视化搭建技能产品, 有更深入的明白.
假如各人以为有资助, 不要忘记点赞 + 收藏哦, 后面我会持续分享最干的互联网干货.
你将劳绩
- 可视化大屏产品设计思路
- 主流可视化图表库技能选型
- 大屏编辑器设计思路
- 大屏可视化编辑器Schema设计
- 用户数据自治探索
方案实现
1.可视化大屏产品设计思路
现在很多企业或多或少的面临“信息孤岛”标题,各个系统平台之间的数据无法实现互通共享,难以实现一体化的数据分析和实时呈现。
相比于传统手工定制的图表与数据仪表盘,可视化大屏制作平台的出现,可以冲破抵消的定制开辟, 数据分散的标题,通过数据采集、清洗、分析到直观实时的数据可视化展现,能够多方位、多角度、全景展现各项指标,实时监控,动态一目了然。
针对以上需求, 我们设计了一套可视化大屏解决方案, 详细包含如下几点:
上图是笔者4个月前设计的根本草图, 后期会持续更新. 通过以上的设计分解, 我们根本可以搭建一个可本身定制的数据大屏.
2.主流可视化图表库技能选型
现在我调研的已知主流可视化库有:
- echart 一个基于 JavaScript 的老牌开源可视化图表库
- D3.js 一个数据驱动的可视化库, 可以不需要其他任何框架独立运行在现代浏览器中,它结合强大的可视化组件来驱动 DOM 操作
- antv 包含一套完整的可视化组件体系
- Chart.js 基于 HTML5 的 简单易用的 JavaScript 图表库
- metrics-graphics 创建在D3之上的可视化库, 针对可视化和布置时间序列数据进行了优化
- C3.js 通过包装构造整个图表所需的代码,使生成基于D3的图表变得容易
我们利用以上任何一个库都可以实现我们的可视化大屏搭建的需求, 各位可以根据喜好来选择.
3.大屏编辑器设计思路
在上面的分析中我们知道一个大屏编辑器需要有个编辑器核心, 主要包含以下部门:
组件库
拖拽(自由拖拽, 参考线, 自动提示)
画布渲染器
属性编辑器
如下图所示:
组件库我们可以用任何组件封装方式(react/vue等), 这里沿用H5-Dooring的可视化组件设计方式, 对组件模子进行优化和设计.
雷同的代码如下:
- import { Chart } from '@antv/f2';
- import React, { memo, useEffect, useRef } from 'react';
- import styles from './index.less';
- import { IChartConfig } from './schema';
- const XChart = (props:IChartConfig) => {
- const { data, color, size, paddingTop, title } = props;
- const chartRef = useRef(null);
- useEffect(() => {
- const chart = new Chart({
- el: chartRef.current || undefined,
- pixelRatio: window.devicePixelRatio, // 指定分辨率
- });
- // step 2: 处理数据
- const dataX = data.map(item => ({ ...item, value: Number(item.value) }));
- // Step 2: 载入数据源
- chart.source(dataX);
- // Step 3:创建图形语法,绘制柱状图,由 genre 和 sold 两个属性决定图形位置,genre 映射至 x 轴,sold 映射至 y 轴
- chart
- .interval()
- .position('name*value')
- .color('name');
- // Step 4: 渲染图表
- chart.render();
- }, [data]);
- return (
- <div className={styles.chartWrap}>
- <div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
- {title}
- </div>
- <canvas ref={chartRef}></canvas>
- </div>
- );
- };
- export default memo(XChart);
复制代码 以上只是一个简单的例子, 更具业务需求的复杂度我们每每会做更多的控制, 比如动画(animation), 变乱(event), 数据获取(data inject)等.
固然现实应用中大屏展现的内容和形式远比这复杂, 我们从上图可以提炼出大屏页面的2个直观特征:
因为我们可视化大屏载体是页面, 是html, 所以尚有另外一个特征: 变乱/交互。综上我们总结出了可视化大屏的必备要素:
我们只要充实的明白了可视化大屏的组成和特征, 我们才气更好的设计可视化大屏搭建引擎, 基于以上分析, 我设计了一张基础引擎的架构图:
接下来我就带各人一起来拆解并实现上面的搭建引擎。
大屏搭建引擎核心功能实现
俗话说: “好的拆解是成功的一半”, 任何一个复杂使命或者系统, 我们只要能将其拆解成很多细小的子模块, 就能很好的解决并实现它. (学习也是一样)
接下来我们就逐一解决上述基础引擎的几个核心子模块:
- 拖拽器实现
- 物料中心设计
- 动态渲染器实现
- 配置面板设计
- 控制中心概述
- 功能辅助设计
1.拖拽器实现
拖拽器是可视化搭建引擎的核心模块, 也是用来解决上述提到的大屏页面特征中的“空间坐标关系”这一标题。我们先来看一下实现效果:
组件拖拽可以采用市面已有的 Dragable 等插件, 也可以采用 H5-Dooring 的智能网格拖拽. 这里笔者选择自由拖拽来实现. 已有的有:
- rc-drag
- sortablejs
- react-dnd
- react-dragable
- vue-dragable
等等. 详细拖拽呈现流程如下:
详细拖拽流程就是:
- 利用H5 dragable API拖拽左侧组件(component data)进入目的容器(targetBox)
- 监听拖拽竣事变乱拿到拖拽变乱传递的data来渲染真实的可视化组件
- 可视化组件挂载, schema注入编辑面板, 编辑面板渲染组件属性编辑器
- 拖拽, 属性修改, 更新
- 预览, 发布
组件的schema参考H5-Dooring DSL设计.
2.物料中心设计
物料中心主要为大屏页面提供“原质料”。为了设计结实且通用的物料, 我们需要设计一套标准组件结构和属性协议。并且为了方便物料管理和查询, 我们还需要对物料进行分类, 我的分类如下:
- 可视化组件 (柱状图, 饼图, 条形图, 地图可视化等)
- 修饰型组件 (图片, 轮播图, 修饰素材等)
- 文字类组件 (文本, 文本赛马灯, 文字看板)
详细的物料库演示如下:
这里我拿一个可视化组件的实现来举例阐明:
- import React, { memo, useEffect } from 'react'
- import { Chart } from '@antv/g2'
- import { colors } from '@/components/BasicShop/common'
- import { ChartConfigType } from './schema'
- interface ChartComponentProps extends ChartConfigType {
- id: string
- }
- const ChartComponent: React.FC<ChartComponentProps> = ({
- id, data, width, height,
- toggle, legendPosition, legendLayout, legendShape,
- labelColor, axisColor, multiColor, tipEvent, titleEvent,
- dataType, apiAddress, apiMethod, apiData, refreshTime,
- }) => {
- useEffect(() => {
- let timer:any = null;
- const chart = new Chart({
- container: `chart-${id}`,
- autoFit: true,
- width,
- height
- })
- // 数据过滤, 接入
- const dataX = data.map(item => ({ ...item, value: Number(item.value) }))
- chart.data(dataX)
-
- // 图表属性组装
- chart.legend(
- toggle
- ? {
- position: legendPosition,
- layout: legendLayout,
- marker: {
- symbol: legendShape
- },
- }
- : false,
- )
- chart.tooltip({
- showTitle: false,
- showMarkers: false,
- })
- // 其他图表信息源配置, 方法雷同, 此处省略
- // ...
- chart.render()
- }, [])
- return <div id={`chart-${id}`} />
- }
- export default memo(ChartComponent)
复制代码 以上就是我们的基础物料的实现模式, 可视化组件采用了g2, 固然各人也可以利用熟悉的echart, D3.js等. 差异物料既有通用的 props , 也有专有的 props, 取决于我们怎样界说物料的Schema。
在设计 Schema 前我们需要明白组件的属性划分, 为了满足组件配置的机动性和通用性, 我做了如下划分:
- 外观属性 (组件宽高, 颜色, 标签, 展现模式等)
- 数据配置 (静态数据, 动态数据)
- 变乱/交互 (如单击, 跳转等)
有了以上划分, 我们就可以轻松设计想要的通用Schema了。我们先来看看实现后的配置面板:
这些属性项都是基于我们界说的schema配置项, 通过 剖析引擎 动态渲染出来的, 有关 剖析引擎 和配置面板, 我会在下面的章节和各人介绍。我们先看看组件的 schema 结构:
- const Chart: ChartSchema = {
- editAttrs: [
- {
- key: 'layerName',
- type: 'Text',
- cate: 'base',
- },
- {
- key: 'y',
- type: 'Number',
- cate: 'base',
- },
- ...DataConfig, // 数据配置项
- ...eventConfig, // 事件配置项
-
- ],
- config: {
- width: 200,
- height: 200,
- zIndex: 1,
- layerName: '柱状图',
- labelColor: 'rgba(188,200,212,1)',
- // ... 其他配置初始值
- multiColor: ['rgba(91, 143, 249, 1)', 'rgba(91, 143, 249, 1)', 'rgba(91, 143, 249,,1)', 'rgba(91, 143, 249, 1)'],
- data: [
- {
- name: 'A',
- value: 25,
- },
- {
- name: 'B',
- value: 66,
- }
- ],
- },
- }
复制代码 其中 editAttrs 表现可编辑的属性列表, config 为属性的初始值, 固然各人也可以根据本身的喜好, 设计雷同的通用schema。
我们通过以上设计的标准组件和标准schema, 就可以批量且高效的生产各种物料, 还可以轻松集成任何第三方可视化组件库。
3.动态渲染器实现
我们都知道, 一个页面中元素很多时会影响页面团体的加载速率, 因为浏览器渲染页面需要消耗CPU / GPU。对于可视化页面来说, 每一个可视化组件都需要渲染大量的信息元, 这无疑会对页面性能造成不小的影响, 所以我们需要设计一种机制, 让组件异步加载到画布上, 而不是一次性加载几十个几百个组件(这样的话页面会有大量的白屏时间, 用户体验极度下降)。
动态加载器就是提供了这样一种机制, 保证组件的加载都是异步的, 一方面可以减少页面体积, 另一方面用户可以更早的看到页面元素。现在我们熟的动态加载机制也有很多, Vue 和 React 生态都提供了开箱即用的解决方案(虽然我们可以用 webpack 自行设计这样的动态模子, 此处为了提高行文服从, 我们直接基于现成方案封装)。我们先看一下动态渲染组件的过程:
上面的演示可以细微的看出从左侧组件菜单拖动某个组件图标到画布上后, 真正的组件才开始加载渲染。
这里我们以 umi3.0 提供的 dynamic 函数来最小化实现一个动态渲染器. 假如不熟悉 umi 生态的朋侪, 也不用发急, 看完我的实现过程和原理之后, 就可以利用任何熟悉的动态加载机制实现它了。实现如下:
- import React, { useMemo, memo, FC } from 'react'
- import { dynamic } from 'umi'
- import LoadingComponent from '@/components/LoadingComponent'
- const DynamicFunc = (cpName: string, category: string) => {
- return dynamic({
- async loader() {
- // 动态加载组件
- const { default: Graph } = await import(`@/components/materies/${cpName}`)
- return (props: DynamicType) => {
- const { config, id } = props
- return <Graph {...config} id={id} />
- }
- },
- loading: () => <LoadingComponent />
- })
- }
- const DynamicRenderEngine: FC<DynamicType> = memo((props) => {
- const {
- type,
- config,
- // 其他配置...
- } = props
- const Dynamic = useMemo(() => {
- return DynamicFunc(config)
- }, [config])
- return <Dynamic {...props} />
- })
- export default DynamicRenderEngine
复制代码 是不是很简单? 固然我们也可以根据自身业务需要, 设计更复杂强大的动态渲染器。
4.配置面板设计
实现配置面板的条件是对组件 Schema 结构有一个系统的设计, 在介绍组件库实现中我们介绍了通用组件 schema 的一个设计案例, 我们基于这样的案例结构, 来实现 动态配置面板。
由上图可以知道, 动态配置面板的一个核心要素就是 表单渲染器。表单渲染器的目的就是基于属性配置列表 attrs 来动态渲染出对应的表单项。我之前写了一篇文章详细的介绍了表单设计器的技能实现的文章, 各人感爱好也可以参考一下: Dooring可视化之从零实现动态表单设计器。
我这里来简单实现一个基础的表单渲染器模子:
- const FormEditor = (props: FormEditorProps) => {
- const { attrs, defaultValue, onSave } = props;
- const onFinish = (values: Store) => {
- // 保存配置项数据
- onSave && onSave(values);
- };
-
- const handlechange = (value) => {
- // 更新逻辑
- }
- const [form] = Form.useForm();
- return (
- <Form
- form={form}
- {...formItemLayout}
- onFinish={onFinish}
- initialValues={defaultValue}
- onValuesChange={handlechange}
- >
- {
- attrs.map((item, i) => {
- return (
- <React.Fragment key={i}>
- {item.type === 'Number' && (
- <Form.Item label={item.name} name={item.key}>
- <InputNumber />
- </Form.Item>
- )}
- {item.type === 'Text' && (
- <Form.Item label={item.name} name={item.key}>
- <Input placeholder={item.placeholder} />
- </Form.Item>
- )}
- {item.type === 'TextArea' && (
- <Form.Item label={item.name} name={item.key}>
- <TextArea rows={4} />
- </Form.Item>
- )}
- // 其他配置类型
- </React.Fragment>
- );
- })}
- </Form>
- );
- };
复制代码 假如各人想看更完整的配置面板实现, 可以参考开源项目 H5-Dooring | H5可视化编辑器
我们可以看看最终的配置面板实现效果:
5.控制中心概述 & 功能辅助设计
控制中心的实现主要是业务层的, 没有涉及太多复杂的技能, 所以这里我简单介绍一下。因为可视化大屏页面展示的信息有些可能是私密数据, 只渴望一部门人看到, 所以我们需要对页面的访问进行控制。其次由于企业内部业务战略需求, 可能会对页面进行各种验证, 状态校验, 数据更新频率等, 所以我们需要设计一套控制中心来管理。最根本的就是访问控制, 如下:
功能辅助设计 主要是一些用户操作上的优化, 比如快捷键, 画布缩放, 大屏快捷导航, 打消重做等操作, 这块可以根据详细的产品需求来美满。各人后期设计搭建产品时也可以参考实现。
可视化大屏数据自治探索
现在我们实现的搭建平台可以静态的设计数据源, 也可以注入第三方接口, 如下:
我们可以调用内部接口来实时获取数据, 这块在可视化监控平台用的场景比力多, 方式如下:
参数(params)编辑区可以自界说接口参数. 代码编辑器笔者这里保举两款, 各人可以选用:
- react-monaco-editor
- react-codemirror2
利用以上之一可以实现mini版vscode, 各人也可以尝试一下.
辅助功能
可视化大屏一键截图 一键截图功能还是沿用H5-Dooring 的快捷截图方案, 主要用于对大屏的分享, 海报制作等需求, 我们可以利用以下任何一个组件实现:
打消重做
打消重做功能我们可以利用已有的库比如react-undo, 也可以本身实现, 实现原理:
有点链表的意思, 我们将每一个状态存储到数组中, 通过指针来实现打消重做的功能, 假如要想更结实一点, 我们可以设计一套“状态镌汰机制”, 设置可保留的最大状态数, 之前的自动镌汰(删除, 更高大上一点的叫出栈). 这样可以避免复杂操作中的大量状态存储, 节省浏览器内存.
标尺参考线 标尺和参考线这里我们本身实现, 通过动态dom渲染来实现参考线在缩放后的动态紧缩, 实现方案核心如下:
- arr.forEach(el => {
- let dom = [...Array.from(el.querySelectorAll('.calibrationNumber'))][0] as HTMLElement;
- if (dom) {
- dom.style.transform = `translate3d(-4px, -8px, 0px) scale(${(multiple + 0.1).toFixed(
- 1,
- )})`;
- }
- });
复制代码 详细源码可参考: H5-Dooring | 参考线设计源码
假如各人有好的建议也欢迎随时交换反馈, 开源不易, 别忘了star哦~
github地址: https://github.com/MrXujiang/v6.dooring.public
往期出色:
分享10款开源工作流+思维导图项目
安利一款支持多人协同的多模态文档编辑器
又做了一款新产品!多模态文档Saas平台
点个在看你最好看
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |