数据可视化大屏设计器开发-右键菜单操作
数据可视化大屏设计器开发-右键菜单操作
开头
本文是数据可视化开始的开发细节第三章。关于大屏中组件的一些操作,比如成组、复制粘贴、层级控制、复制样式、组件切换、前进后退等等。
本文就针对各个操作逐一讲解其实现思路。
开始之前
在正式开始之前,先预先介绍一下相关的信息。
以下讲解均只涉及PC端的逻辑。
下面所说的元素表示的是组或者组件的简称。
因为本文说的是右键菜单,所以肯定无法避免二次操作。比如先进行复制,然后进行粘贴,所以一般认为二次操作所选中的元素为最终可能需要操作的位置(比如复制了组内的元素,然后右键粘贴选择的元素在组外,那么目标元素就会被粘贴到组外)。
组件整体的数据结构。
组件在画布中的存在形式是一个树的结构,其实就是一个简单的数组形式,当然并不只是一个一层,它是一个深层嵌套的结构。
类似于下面这样:
1 |
|
- id
元素的id - parent
父级的id,如果为最上层的元素则不存在 - type
标记当前元素是组还是组件 - components
当前组的下层元素
组可以嵌套组件,也可以嵌套组,组件为最下层。
元素通过parent
来达到与父级的关联。
如此形成一个无限向下嵌套的结构。
平滑结构
虽然上述的结构可以很好的描述和直观的看到整个大屏的全貌,但是有时候操作起来相对来说还是有点不方便。
此时就需要一个临时的平滑的单层次结构来应对业务中的一些逻辑操作。
当前的想法是以对象的形式来表达。
类似于下面这样:
1 |
|
- 键名
key即为元素的id - id
与键名同意 - path
这个是此结构的关键,它是当前元素在树结构中的路径,关于他的格式可以参考lodash的get方法
比如0.components.2
表示获取第一个组的第二个子元素。
开始
首先讲一下本文所涉及的所有操作:
成组/取消成组、复制/粘贴、层级控制(置顶/置底/上一个/下一个)、删除、组件切换、复制组件样式、隐藏、锁定、恢复默认配置、前进后退。
其实本来对于上述的操作,实现逻辑并不复杂,但是因为设计器当中存在多选操作的逻辑,以及成组的逻辑,导致上面的操作实现起来并没有看上去那么简单。
成组/取消成组
一上来就是最复杂的逻辑🤷🏻♀️ 。
先讲成组是因为它对后面的逻辑或多或少会产生一定的影响。
并且成组是所有操作当中,最难实现的部分。
组即是将一个或多个元素进行包裹,组内元素的定位将不再基于画布,而是基于组。
因为多个元素成组后,免不了对组进行大小、位置调整等。
位置调整相对来说影响不大,因为内部元素均基于组来进行定位。
而大小的变动会对内部的元素影响非常大。
比如,初始组的宽度为
200px
,组内的一个组件的宽度为50px
,之后将组调整为400px
,那么组件的宽度应该调整为多少?
组的宽度放大了2倍
,所以组件的宽度同时也放大2倍
,变为100px
。
同时还要注意,组件的位置同样也需要调整,如上述的,说明组件的left
也要放大2倍
。
如此进行上述的计算调整,相对来说还是比较耗费性能的,因为他不仅仅是只有一层的结构。
最终选择的方案是,通过对每一个元素无差别带上scale
配置:scaleX
和scaleY
,默认为1
。
对于组件的操作,无须修改scale
配置,而组的大小调整时,修改尺寸和scale
配置即可。
const newScaleX = (newWidth / width) * (scaleX || 1)
,如此可以计算出新的scaleX
。
而内部的元素在实际渲染前,只需要将父级的scale
进行计算即可。
const componentWidth = width * parentScaleX
而组内组的话,则是需要将自己的scale
与父级的scale
进行相乘,因为组内组之下还有组件,是相互影响的。
成组
成组的元素有两种情况:同级成组和非同级成组。
首先需要计算出对应的元素相对于画布的位置和尺寸。(上面已经说过,组内元素是根据父级组来进行定位的,尺寸也受到了scale
配置的影响)
如果是组的话也要将scale
配置计算出来。
接着获取到对应的成组位置的父级元素的信息(可以通过上面说的parent
配置,用平滑结构获取到元素配置)。
创建新组并根据子元素信息重新计算宽高及位置。
接着递归去修改子组内的子元素(因为子组在树内的结构可能发生了变化),最重要的是子元素的parent
配置,需要指向当前的父元素。
取消成组
成组的反向操作。
相对于成组来说,简单一些,只需要去掉外层包裹的组的一些配置,比如scale
配置,定位配置,parent
配置。
因为现在是相对于原父组的再上一层父组进行定位,所以要将原父组的配置合并到对应的子元素上面。
其他
具体的代码请查看这里。
当前版本还发现一个问题:组内元素的宽高通过右侧配置进行修改,外层组的尺寸未同步。预计在下一个版本进行处理。
层级
层级控制包含四个操作:置顶、置底、上一个、下一个。
层级是指元素在画布当中显示的层级顺序。
虽然PC端和H5端显示的逻辑不一样,但是也大差不差。
PC端中画布的元素,采用的是绝对定位的布局,那么层级即是元素的
zIndex
样式
H5端中画布的元素,采用普通的流式布局,那么层级就是元素在数组中的索引顺序。
层级分成3种:1(置底)、2(正常)、3(置顶)。
元素在html的结构中也是按顺序进行渲染的,所以第一个元素和第二个元素虽然zIndex
都是2,但是第二个元素还是会在第一个元素的上面。
1 |
|
所以逻辑就很简单了:
- 置顶
将元素的zIndex
修改为3。 - 置底
将元素的zIndex
修改1。 - 上一个/下一个
修改元素在数组中的索引位置。
因为组本身也是一个容器,所以对于此部分的逻辑,基本处理都是一样的。
当多选了多个元素时,为了操作方便,统一显示的都是一个状态。
比如置顶,如果一个元素已经置顶了,那么操作按钮显示的是取消置顶,根据上面的逻辑,多个元素同时操作时,操作按钮统一显示成置顶。
删除
删除操作就很简单了,单纯的从数据结构中,删除对应的元素即可。
而在大屏中,需要弹出确认提示:是否删除xxx、xxx等组件。如果从树结构中寻找,难免显得麻烦。
此时就可以使用上面的平滑结构来进行操作,只需要简单的拿到对应元素的path
路径,接着拿到他的父级,删除即可👍 。
隐藏
隐藏操作即是将组件在画布当中隐藏。
此操作也十分简单,设置组件的样式即可,这里使用的是visibility
样式来控制,实践中因为display
可能会使部分组件的宽高计算出现问题,故使用visibility
。
需要注意的是, 因为visibility
的特性,可能会使得鼠标多选时还是能选中该元素,所以需要特别处理。
锁定
锁定操作与隐藏操作类似,不同的是锁定是正常显示元素的,但是无法对其进行相应的操作罢了,比如选中、修改配置等。
这是为了防止有人误操作,导致相关已经完成设计的元素被修改,因为整体数据是实时保存的。
组件切换
组件切换为根据数据进行组件切换。
比如当在设计完成一个组件时,突然想换成另外一种呈现形式,此时就可以通过组件切换达到目的。
当然要求是被切换的组件和切换组件的数据格式是相同的。
关于数据格式,即对应组件所需要的数据的类型,及字段。
比如柱形图,他的数据格式为:
1 |
|
折线图的数据格式同样也是上面的形式。
所以说明柱形图和折线图是可以进行相互切换的。
复制组件样式
复制组件样式类似于复制操作,当然他是把复制和粘贴操作进行了合并。
和名称一样,复制的是组件的样式配置,对于组件的数据和交互等,均为组件的初始值。
逻辑即简单使用lodash
的mergeWith
将组件配置和默认配置进行合并即可。
恢复默认配置
恢复默认配置,将组件的配置恢复成初始值,简单覆盖即可。
前进后退
前进和后退,允许操作可以前进和后退。
比如将一个组件右移100px
,后退操作可以将组件回到原来的位置。
这里使用的是自己实现的类库react-undo-component。
他可以让class
组件或者function
组件,在内部记录state
的一系列操作记录,方便进行前进和后退。
比如function
组件,可以使用useUndo
方法。
1 |
|
内部即是简单拦截了useState
方法来记录state
变化。
因为设计器使用的是dva
,所以不能简单使用上述的方法,但是他同样导出了内部class的Histroy
可以自行实现对应细节。
具体的实现代码可以查看这里
结束
以上逻辑均为本人自己的想法,如有问题或错误可指正🙏🏻 。
结束🔚。
顺便在下面附上相关的链接。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!