从 G6 3.0 正式对外放出 beta 版以来,询问量居高不下的问题就是:G6 是否还支持 html 类型的节点?这个问题,我们一直有思考,讨论,但是始终无法达成一致意见着手去做。

为什么考虑加 html 节点

相对于canvas,HTML存在很大优势:

  • 节点上存在多个热区,需要监听多个部分的事件做交互的情况;
  • 使用 html 布局可以很方便的实现文字居中,自动换行,内容溢出自动省略等;
  • 用 css 伪类可以很方便的实现一些节点状态的样式切换;
  • 节点结构比较复杂时,可以降低定制节点时间。

G6 中支持 html 节点的方案

html 置于canvas下层

在 G6 容器节点下创建一个 html 节点的容器,所有 html 节点置于 canvas 下方。结构如下:

  1. <div>
  2. <div id="g6-html-container">
  3. <div class="g6-node">...</div>
  4. <div class="g6-node">...</div>
  5. </div>
  6. <canvas />
  7. </div>

优点:

  • 能支持html节点外观方面的各种features;
  • 实现便捷,支持视口的各种操作。

缺点:

  • 缺少 html 事件机制;
  • 有 G6 内置事件事件捕获与实际节点错位的可能性。

html 在 canvas 上层

在canvas之后创建一个个节点,所有html 节点在 canvas 上方,结构如下:

  1. <div>
  2. <canvas />
  3. <div class="g6-node">...</div>
  4. <div class="g6-node">...</div>
  5. </div>

优点:

  • 能支持 html 节点外观;
  • 能支持 html 事件;

缺点:

  • 视口操作(画布拖拽,平移等)很难实现和维护;
  • 对目前架构侵入较大,原本G6事件系统需要大量改造。

总结

曾经有人和我说过:“与其提供一个 60 分的替代方案,不如专心做一个 90 分的标准方案。”无论是以上哪种方式都无法完全满足我们想要的节点效果,因此G6不会在全局下支持 html 节点。
如果 html 节点是个强需求,可以在定义实例时指定用 SVG 渲染,利用 SVG 特有的 foreignObject 实现。

  1. const graph = new G6.Graph({
  2. renderer: 'svg',
  3. ...cfgs
  4. });

SVG 版的 G 已支持此标签。定制节点时,按照如下方式:

  1. G6.regiterNode('html', {
  2. draw(cfg, group) {
  3. const htmlShape = group.addShape('dom', {
  4. attrs: {
  5. html: '<div class="custom-node">your customized node</div>',
  6. ...attrs
  7. }
  8. });
  9. return htmlShape;
  10. }
  11. });

note: 最好不要在 html 节点中嵌入表单元素。在用户输入信息时,偶尔会导致画布闪烁。