mxGraph显示隐藏sizer(拖拽缩放点)

这篇文章的主题是如何自定义 mxGraph 图元的 sizer 的显示与隐藏。

显示与隐藏分两种情况,一种是在首次渲染时,就按照规则显示/隐藏 sizer,一种是更新时,让 sizer 的显示/隐藏状态发生变化。下面依次分析。

显示/隐藏 sizer 首先要搞明白 sizer 是什么。sizer 本质上还是 shape,继承自 mxShape,所以按照 shape 的显示与隐藏就可以完成 sizer 的显示与隐藏。

那接下来我们看看 mxGraph 自己是如何完成这个功能的。

代码分析

sizer 用来控制 shape 缩放,这里以块图元为例。

我们要知道这些东西(图元的缩放)都存在于 vertexHandler 中。所以我们从 vertexHanlder 的方法中,可以看到进行了初始化,调用了 init 方法。

javascript 复制代码
function mxVertexHandler(state) {
  if (state != null) {
    this.state = state;
    this.init();

    // ......
  }
};

每一个图元,都对应一个 vertexHandler。每次 new vertexHanlder 时,都会执行 init 方法,此时 sizer 就已经被创建出来了。

在 init 方法中,有这么一段代码是用来创建 sizer 的

javascript 复制代码
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 的实现是什么样的,屏蔽掉一些这里不需要理解的代码。只看对我们有用的信息

javascript 复制代码
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。

javascript 复制代码
mxVertexHandler.prototype.isSizerVisible = function (index) {
  return true;
};

实现功能

首次渲染

我们可以按照 index 返回 false 或者 true,以达成自定义渲染 sizer 的目的。如果还需要根据图元本身做判断,那么 this 上挂载了 state,可以拿到 state 后,完成自定义渲染 sizer 的目的。

比如我们将上下左右的四个 sizer 移除,可以重写 isSizerVisible 方法。如下:

javascript 复制代码
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,名字叫做handle。

我们看一下setHandlesVisible方法是如何实现的吧

javascript 复制代码
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

理论可行,开始写代码

javascript 复制代码
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相关的文章,敬请期待。

相关推荐
gnip1 小时前
链式调用和延迟执行
前端·javascript
SoaringHeart1 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.1 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu1 小时前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss1 小时前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师1 小时前
React面试题
前端·javascript·react.js
木兮xg1 小时前
react基础篇
前端·react.js·前端框架
ssshooter2 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘3 小时前
HTML--最简的二级菜单页面
前端·html
yume_sibai3 小时前
HTML HTML基础(4)
前端·html