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

相关推荐
Setsuna_F_Seiei3 小时前
前端转型 Agent 开发 04 之 MCP 与 Skill(赋予 Agent 更广工作能力)
前端·agent
刘发财4 小时前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
郑州光合科技余经理5 小时前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
梦想平凡5 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai6 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
计算机魔术师8 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy1288 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师8 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen9 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
IT_陈寒9 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端