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