React可视化大屏编辑器的实现方案

前言
近两年一直在做数据分析可视化的项目,我主要是负责可视化大屏编辑器和可视化组件的开发,由于历史原因技术栈用的是jQuery。本人也很喜欢这个项目于是在空闲时间把主要功能用React+ts实现了下,在这里做一个记录
编辑器主要功能是从左侧选中组件,拖入到中间画布。可以对画布中的组件进行移动,缩放,旋转,通过右侧属性栏目设置组件样式和数据。redux中存放大屏基础配置JSON和画布中所有组件JSON。这些操作都是修改redux中组件的对应的配置项
编辑器最终大概是下面这样。顶部操作按钮区域(保存,预览等),左侧组件列表区域,中间大屏画布区域,右侧组件属性设置区域
React可视化大屏编辑器的实现方案
文章图片

组件配置项

export interface Rect { left?: number top?: number width: number height: number }export interface Plugin { url: string name: string }export interface Data { type: 'static' | 'api' widgetData?: any apiUrl?: string loop?: number //s ruler?: any //数据规则 displayForm: 'table' | 'codeEdit' //数据展示插件 表格,代码编辑器 }export interface Widget { name: string plugin: Plugin rect: Rect rotate?: number img: string config: any dataConfig?: Data }

大屏配置项
interface ScreenWidget { widgetId: string zIndex: number children?: ScreenWidget[] } export interface Screen { name: string width: number height: number coverImage: string scale: number screenZoom: 'scaling' | 'Hscaling' | 'Wscaling' | 'phone' | 'none' backgroundColor: string backgroundImage: string //大屏组件列表 screenWidget: ScreenWidget[] //大屏组件层级 widgetIndex: number //选中组件id集合 activeWidgets: string[] }

组件拖入
ahooks中的useDrop & useDrag,具体用法参考官网示例
组件移动
react-moveable
刻度尺
ruler
组件移动,参数设置修改redux中组件的对应的配置项
【React可视化大屏编辑器的实现方案】immutability-helper
设置参数时都是修改当前选中组件的配置,在设置时通过json路径设置
例如:修改柱状图第一个柱子的颜色,对应的路径是 config.bars.0.color
export const getObjByPath = (field: string, value: any) => { let obj = {} if (typeof field === 'undefined' || typeof value =https://www.it610.com/article/=='undefined') { return undefined } if (typeof field === 'string' && field.indexOf('.') === -1) { obj[field] = { $set: value } return obj } const ids = field.split('.') let th = '' for (let i = 0; i < ids.length; i++) { th += "['" + ids[i] + "']" if (!eval(`obj${th}`)) { eval(`obj${th}={}`) } } eval(`obj${th}={$set: value}`) return obj }

import update from 'immutability-helper' const widget = getActiveWidget() //获取当前选中组件配置项 const path = 'config.bars.0.color' const value = 'https://www.it610.com/article/#fff' const obj = getObjByPath(path, value) const newWidgetObj = update(widget, obj) setActiveWidget(newWidgetObj)//更新当前选中组件配置项

实现方案的内容基本就是上面这些,下篇文章会写一些组件的动态加载,优化,错误处理和大屏保存后的组件定制化

    推荐阅读