mxGraph显示隐藏sizer(拖拽缩放点)
这篇文章的主题是如何自定义 mxGraph 图元的 sizer 的显示与隐藏。
显示与隐藏分两种情况,一种是在首次渲染时,就按照规则显示/隐藏 sizer,一种是更新时,让 sizer 的显示/隐藏状态发生变化。下面依次分析。
显示/隐藏 sizer 首先要搞明白 sizer 是什么。sizer 本质上还是 shape,继承自 mxShape,所以按照 shape 的显示与隐藏就可以完成 sizer 的显示与隐藏。
那接下来我们看看 mxGraph 自己是如何完成这个功能的。
代码分析
sizer 用来控制 shape 缩放,这里以块图元为例。
我们要知道这些东西(图元的缩放)都存在于 vertexHandler 中。所以我们从 vertexHanlder 的方法中,可以看到进行了初始化,调用了 init 方法。
每一个图元,都对应一个 vertexHandler。每次 new vertexHanlder 时,都会执行 init 方法,此时 sizer 就已经被创建出来了。
在 init 方法中,有这么一段代码是用来创建 sizer 的
_15var i = 0;_15_15if (resizable) {_15 if (!this.singleSizer) {_15 this.sizers.push(this.createSizer('nw-resize', i++));_15 this.sizers.push(this.createSizer('n-resize', i++));_15 this.sizers.push(this.createSizer('ne-resize', i++));_15 this.sizers.push(this.createSizer('w-resize', i++));_15 this.sizers.push(this.createSizer('e-resize', i++));_15 this.sizers.push(this.createSizer('sw-resize', i++));_15 this.sizers.push(this.createSizer('s-resize', i++));_15 }_15_15 this.sizers.push(this.createSizer('se-resize', i++));_15 }
这里创建了 8 个 sizer,分别是图元的左上,上,右上,左,右,左下 ,下,右下(如下图所示)
它们之间的顺序是从左到右,从上到下,index 从 0-7。
来看看 createSizer 的实现是什么样的,屏蔽掉一些这里不需要理解的代码。只看对我们有用的信息
_14mxVertexHandler.prototype.createSizer = function (cursor, index, size, fillColor) {_14 size = size || mxConstants.HANDLE_SIZE;_14_14 var bounds = new mxRectangle(0, 0, size, size);_14 var sizer = this.createSizerShape(bounds, index, fillColor);_14 _14 // ......_14_14 if (!this.isSizerVisible(index)) {_14 sizer.visible = false;_14 }_14_14 return sizer;_14};
看这里,sizer 实际上是一个 shape,被创建出来后,当达成某个条件后,sizer 的 visible 会被设置为 false。一旦 shape 的 visible 被设置为 false 以后,这个 shape 就不会再被渲染了
visible 控制 shape 渲染的逻辑可以参见 mxShape.redraw 方法
进入 isSizerVisible 方法可以看到 mxGraph 默认只返回了 true,入参为 index。
_3mxVertexHandler.prototype.isSizerVisible = function (index) {_3 return true;_3};
实现功能
首次渲染
我们可以按照 index 返回 false 或者 true,以达成自定义渲染 sizer 的目的。如果还需要根据图元本身做判断,那么 this 上挂载了 state,可以拿到 state 后,完成自定义渲染 sizer 的目的。
比如我们将上下左右的四个 sizer 移除,可以重写 isSizerVisible 方法。如下:
_5mxVertexHandler.prototype.isSizerVisible = function(index)_5{_5 if ([1, 3, 4, 6].includes(index)) return false;_5 return true;_5};
指定sizer进行显示/隐藏
mxGraph本身只提供了一个方法setHandlesVisible
来显示和隐藏所有的handle,这里的handle是sizer的父级,sizer本身也是handle的一种,只不过是拿来控制图元大小的一种handle,名字叫做sizer。
我们看一下setHandlesVisible
方法是如何实现的吧
_14mxVertexHandler.prototype.setHandlesVisible = function(visible)_14{_14 this.handlesVisible = visible;_14_14 if (this.sizers != null)_14 {_14 for (var i = 0; i < this.sizers.length; i++)_14 {_14 this.sizers[i].node.style.display = (visible) ? '' : 'none';_14 }_14 }_14_14 // ......_14};
依旧是省略掉一部分代码。这里 直接控制了dom上的样式,对sizer对应的dom元素的display样式进行了控制,所以如果想要实现只显示一部分的代码,可以自己写一个方法。但在此之前我们要搞明白handler的调用路径。
当我们点击一个图元时,selectionModel
会发生变化,继而引起selectionCellsHandler
中刷新handlers,所以在selectionCellsHandler
中存储了所有已被创建的handler。在这里我们可以拿到,我们想操作的cell对应的handler。继而就可以完成对指定sizer(handle)的显示隐藏。
获取handler的方法我们可以在selectionCellsHandler
中找到,即getHandler
理论可行,开始写代码
_6const hideSizerByIndex = (graph, cell, visible, index) => {_6 if (index !== null) {_6 const handler = graph.selectionCellsHandler.getHandler(cell);_6 handler.sizers[i].node.style.display = (visible) ? '' : 'none';_6 }_6}
这样就 完成了指定sizer进行显示/隐藏
至此,就可以自定义 sizer 的显示与隐藏了
后续将会写更多与mxGraph相关的文章,敬请期待。