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相关的文章,敬请期待。

相关推荐
kura_tsuki5 分钟前
[Web网页] LAMP 架构与环境搭建
前端·架构
yinuo13 分钟前
UniApp+Vue3多分包引入同一 npm 库被重复打包至 vendor 的问题分析与解决
前端
码界奇点25 分钟前
Spring Web MVC构建现代Java Web应用的基石
java·前端·spring·设计规范
yinuo44 分钟前
UniApp + Vue3 使用 marked 报错:SyntaxError /[\p{L}\p{N}]/u 问题分析与解决
前端
大前端helloworld1 小时前
前端梳理体系从常问问题去完善-框架篇(Vue2&Vue3)
前端·javascript·面试
小墨宝2 小时前
web前端学习LangGraph
前端·学习
南囝coding2 小时前
React 19.2 重磅更新!这几个新特性终于来了
前端·react.js·preact
Dajiaonew2 小时前
Vue3 + TypeScript 一篇文章 后端变全栈
前端·javascript·typescript
广州华水科技2 小时前
GNSS与单北斗变形监测一体机在基础设施安全中的应用分析
前端
勤劳打代码3 小时前
妙笔生花 —— Flutter 实现飞入动画
前端·flutter·设计模式