可参考: https://github.com/le5le-com/topology/tree/master/packages/flow-diagram

自定义图形库,主要指自定义节点。

节点组成

  1. 形状(边框)

    image.png

  2. 图标/图片

    image.png

  3. 文字

    image.png

  4. 锚点

    image.png

自定义图形的过程,就是如何实现上面组成部分。锚点可以使用默认的上下左右4个点。

编写自定义图形组件(4步)

1. 绘制形状

  1. import { Node } from '@topology/core';
  2. export function myShape(ctx: CanvasRenderingContext2D, node: Node) {
  3. ctx.beginPath();
  4. // Make my shape.
  5. ...
  6. ...
  7. ...
  8. // 必须判空再填充
  9. (node.fillStyle || node.bkType) && ctx.fill();
  10. ctx.stroke();
  11. }

1)定义一个可导出的函数,例如:myShape

参数

名称 类型 是否必选 描述
ctx CanvasRenderingContext2D 是。 canvas的绘画上下文。
你想怎么画,你决定。
node Node 节点信息。参考 节点

2)建立一个新绘画路径,避免干扰其他图形绘画。【必须】
ctx.beginPath();

3)利用ctx和node,开始自己的canvas图形绘画

4)可选性的,总结性的,填充或涂边框
ctx.fill();
ctx.stroke();

2. 计算图标/图片位置

自定义图形库 - 图5
可省略,用默认位置。默认上面2/3为图片区域,下面1/3为文字区域。

  1. import { Node, Rect } from '@topology/core';
  2. export function myIconRect(node: Node) {
  3. node.iconRect = new Rect(node.rect.x, node.rect.y + 10, node.rect.width, (node.rect.height * 2) / 3 - 20);
  4. node.fullIconRect = node.rect;
  5. }

传入node节点参数,计算并赋值iconRect、fullIconRect。其中:

  • iconRect - 有文字存在时的区域。
  • fullIconRect - 没有文字时的区域。

3. 文字位置

可省略,用默认位置。默认为节点底部1/3的区域。

  1. import { Node, Rect } from '@topology/core';
  2. export function myTextRect(node: Node) {
  3. node.textRect = new Rect(
  4. node.rect.x + 10,
  5. node.rect.y + (node.rect.height * 2) / 3,
  6. node.rect.width - 20,
  7. node.rect.height / 3 - 5
  8. );
  9. node.fullTextRect = node.rect;
  10. }

传入node节点参数,计算并赋值textRect、fullTextRect。其中:

  • textRect- 有图片存在时的区域。
  • fullTextRect- 没有图片时的区域。

4. 计算锚点

可省略,用默认锚点,上下左右4个点。
image.png

  1. import { Point, Node, Direction } from '@topology/core';
  2. export function myAnchors(node: Node) {
  3. node.anchors.push(new Point(node.rect.x, node.rect.y + node.rect.height / 2, Direction.Left));
  4. node.anchors.push(new Point(node.rect.x + node.rect.width / 2, node.rect.y, Direction.Up));
  5. node.anchors.push(new Point(node.rect.x + node.rect.width, node.rect.y + node.rect.height / 2, Direction.Right));
  6. node.anchors.push(new Point(node.rect.x + node.rect.width / 2, node.rect.y + node.rect.height, Direction.Bottom));
  7. // demo,其他自定义锚点。这里只是示例。
  8. for (let i = 10; i < 360; i += 10) {
  9. if (i % 90 === 0) {
  10. continue;
  11. }
  12. const direction = Math.floor(i / 90);
  13. const pt = new Point(
  14. node.rect.center.x + (Math.sin((i / 180) * Math.PI) * node.rect.width) / 2,
  15. node.rect.center.y + (Math.cos((i / 180) * Math.PI) * node.rect.height) / 2,
  16. direction
  17. );
  18. pt.hidden = true;
  19. node.anchors.push(pt);
  20. }
  21. }

传入node节点参数,计算并赋值anchors。其中:如果point.hidden为true,表示鼠标移动到节点时,不显示锚点;仅到鼠标移动到锚点自身才显示。

例如上面代码:默认鼠标移动到节点,显示4个锚点,其他锚点只有鼠标在锚点位置才显示。

发布图形库 (可选)

主要指发布到npm上。

可以参考: https://github.com/le5le-com/topology/tree/master/packages/flow-diagram
配置好package.json、tsconfig.json相关配置,然后编译,用npm发布即可。

使用自定义图形库

1. 注册自定义函数

向画布注册一个自定义图形,让画布知道如何绘制你的图像。

  1. // 导入画布的注册函数
  2. import { registerNode } from '@topology/core';
  3. // 导入自己的图形库函数(前面编写的4个函数)
  4. import {
  5. myShape, // 形状
  6. myIconRect, // 图片位置区域
  7. myTextRect, //文字位置区域
  8. myAnchors //锚点
  9. } from 'topology-flow-diagram';
  10. // 注册到画布
  11. registerNode('唯一的图形名,参考node.name', myShape, myAnchors, myIconRect, myTextRect);

其中,注册函数用法:
// name - node名称.
// drawFn - node渲染函数。上面的myShape
// anchorsFn - 计算node的锚点,如果为null,表示使用缺省计算锚点方法
// iconRectFn - 计算node的图标区域,如果为null,表示使用缺省计算图标区域方法
// textRectFn - 计算node的文字区域,如果为null,表示使用缺省计算文字区域方法
// project - 如果已经存在同名node,不要覆盖.
export function registerNode(
name: string, // myShape
drawFn: (ctx: CanvasRenderingContext2D, node: Node) => void,
anchorsFn?: (node: Node) => void,
iconRectFn?: (node: Node) => void,
textRectFn?: (node: Node) => void,
project?: boolean
);

2. 调用,使用自定义图形

当向画布添加节点时,就会使用自定义图形的相关函数。例如:

  1. canvas.addNode({
  2. name: '唯一的图形名,参考node.name' // registerNode的第一个参数。
  3. text: '自定义图形',
  4. rect: {
  5. x: 100,
  6. y: 100
  7. width: 150,
  8. height: 400
  9. }
  10. })

左侧工具栏拖曳的数据,也是上面的addNode参数,参考: https://www.yuque.com/alsmile/topology/faq#O7ntD

修改默认图形锚点

例如,修改矩形锚点方法,为自己的锚点计算函数myAnchorFn。直接重新注册即可。

  1. import { registerNode, rectangle } from '@topology/core';
  2. // 覆盖已经存在节点,需要传最后一个force参数
  3. registerNode('rectangle', rectangle , myAnchorFn, null, null);
  4. // 或直接使用window对象下的注册函数
  5. window.registerTopologyNode('rectangle', rectangle , myAnchorFn, null, null);

Topology-vue企业版中自定义图形库

window.registerTopologyNode

  1. window.registerTopologyNode('thermometer', myShape)

参考示例: https://github.com/le5le-com/topology-vue-ts/tree/master/src/components