Skip to content
索引

起步

logic-flow是一个开发流程图的库

搜索引擎有可能搜到的是旧版官方文档,啪的一下点进去,很快啊,照着文档一顿搞,结果各种不生效,去github一看,哎不是最新文档,去骗去偷袭我一个练习时长两年半的前端练习生

新旧版文档内容变更比较大,旧版文档的一些代码思路还是值得参考的,新版文档中可能就没有这些内容

旧版官方文档 https://07.logic-flow.cn/

官方文档 https://docs.logic-flow.cn/docs/#/zh/guide/start

用法

安装

安装核心库和插件库

sh
npm i @logicflow/core @logicflow/extension -s 
npm i @logicflow/core @logicflow/extension -s 

安装完导入jscss

js
import { LogicFlow } from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"
import { LogicFlow } from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"

创建容器

在页面中指定一个html元素作为绘图的容器,又称画布,比如一个 div 标签

html
<div id="container"></div>
<div id="container"></div>

准备数据

通过 JSON 的数据格式,来让 LogicFlow 渲染。该数据中需要有 nodes(节点) 和 edges(边) 字段,分别用数组表示:

实际开发中,用户自己创建一个流程图,前端使用LogicFlow导出如下数据格式流程图数据,保存至后端数据库,下次请求再获取并渲染流程图

js
const data = {
  // 节点
  nodes: [
    {
      id: 21,
      type: 'rect',
      x: 100,
      y: 200,
      text: {
        value: '矩形节点',
        x: 100,
        y: 200,
      },
    },
    {
      id: 50,
      type: 'circle',
      x: 300,
      y: 400,
      text: {
        value: '圆形节点',
        x: 300,
        y: 400,
      },
    },
  ],
  // 边
  edges:[
    {
      type: 'polyline',
      sourceNodeId: 50,
      targetNodeId: 21,
    }
  ]
}
const data = {
  // 节点
  nodes: [
    {
      id: 21,
      type: 'rect',
      x: 100,
      y: 200,
      text: {
        value: '矩形节点',
        x: 100,
        y: 200,
      },
    },
    {
      id: 50,
      type: 'circle',
      x: 300,
      y: 400,
      text: {
        value: '圆形节点',
        x: 300,
        y: 400,
      },
    },
  ],
  // 边
  edges:[
    {
      type: 'polyline',
      sourceNodeId: 50,
      targetNodeId: 21,
    }
  ]
}

渲染画布

创建一个 LogicFlow 的实例,此时可以传入一些参数来控制画布,比如画布的大小,最后渲染数据

js
const lf = new LogicFlow({
  container: document.querySelector('#container'),
  width: 700,
  height: 600
})
const lf = new LogicFlow({
  container: document.querySelector('#container'),
  width: 700,
  height: 600
})

通过刚才创建的实例数据渲染到画布上

js
lf.render(data)
lf.render(data)

vue完整示例代码

vue
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'
const data = {
  // 节点
  nodes: [
    {
      id: 21,
      type: 'rect',
      x: 100,
      y: 200,
      text: {
        value: '矩形节点',
        x: 100,
        y: 200
      }
    },
    {
      id: 50,
      type: 'circle',
      x: 300,
      y: 400,
      text: {
        value: '圆形节点',
        x: 300,
        y: 400
      }
    }
  ],
  // 边
  edges: [
    {
      type: 'polyline',
      sourceNodeId: 50,
      targetNodeId: 21
    }
  ]
}
onMounted(() => {
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 700,
    height: 600
  })
  lf.render(data)
})
</script>

<template>
  <div id="container"></div>
</template>

<style scoped></style>
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'
const data = {
  // 节点
  nodes: [
    {
      id: 21,
      type: 'rect',
      x: 100,
      y: 200,
      text: {
        value: '矩形节点',
        x: 100,
        y: 200
      }
    },
    {
      id: 50,
      type: 'circle',
      x: 300,
      y: 400,
      text: {
        value: '圆形节点',
        x: 300,
        y: 400
      }
    }
  ],
  // 边
  edges: [
    {
      type: 'polyline',
      sourceNodeId: 50,
      targetNodeId: 21
    }
  ]
}
onMounted(() => {
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 700,
    height: 600
  })
  lf.render(data)
})
</script>

<template>
  <div id="container"></div>
</template>

<style scoped></style>

网格配置

https://docs.logic-flow.cn/docs/#/zh/api/logicFlowApi?id=grid

网格,若设为false不开启网格,则为 1px 移动单位,不绘制网格背景,若设置为true开启则默认为 20px 点状网格

false | Object,默认 false

js
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 700,
    height: 600,
    grid: true
  })
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 700,
    height: 600,
    grid: true
  })

画布设置

画布宽高

如果不设置画布宽高,默认是容器的宽高

html
<div id="container"></div>
<div id="container"></div>
css
#container {
  width: 100%;
  height: 100%;
  }
#container {
  width: 100%;
  height: 100%;
  }

设置画布固定宽高

js
const lf = new LogicFlow({
      container: document.querySelector("#container"),
      width: 700,
      height: 600,
    })
const lf = new LogicFlow({
      container: document.querySelector("#container"),
      width: 700,
      height: 600,
    })

主题

  • stroke 边框颜色
  • stroke-dasharray 边框间隔图案
  • stroke-width 边框宽度
  • fill 图形元素内部的颜色
  • fill-opacity 填色的不透明度或当前对象的内容物的不透明度
  • font-size 文本字体大小
  • color 文本颜色

setTheme设置主题

js
lf.setTheme({
      nodeText: {
        color: "#ffffff",
        overflowMode: "autoWrap",
        fontSize: 15
      },
      edgeText: {
        textWidth: 50,
        overflowMode: "autoWrap",
        fontSize: 12,
        background: {
          fillOpacity: 0
        }
      }
    })
lf.setTheme({
      nodeText: {
        color: "#ffffff",
        overflowMode: "autoWrap",
        fontSize: 15
      },
      edgeText: {
        textWidth: 50,
        overflowMode: "autoWrap",
        fontSize: 12,
        background: {
          fillOpacity: 0
        }
      }
    })

基础节点

矩形:rect

圆形: circle

椭圆: ellipse

多边形: polygon

菱形: diamond

文本: text

HTML: html

js
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";

const lf = new LogicFlow({
  container: document.querySelector("#app"),
  grid: true
});

lf.render({
  nodes: [
    {
      id: "1",
      type: "rect",
      x: 100,
      y: 100,
      text: "矩形"
    },
    {
      id: "2",
      type: "circle",
      x: 300,
      y: 100,
      text: "圆形"
    },
    {
      id: "3",
      type: "ellipse",
      x: 500,
      y: 100,
      text: "椭圆"
    },
    {
      id: "4",
      type: "polygon",
      x: 100,
      y: 250,
      text: "多边形"
    },
    {
      id: "5",
      type: "diamond",
      x: 300,
      y: 250,
      text: "菱形"
    },
    {
      id: "6",
      type: "text",
      x: 500,
      y: 250,
      text: "纯文本节点"
    },
    {
      id: "7",
      type: "html",
      x: 100,
      y: 400,
      text: "html节点"
    }
  ]
});
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";

const lf = new LogicFlow({
  container: document.querySelector("#app"),
  grid: true
});

lf.render({
  nodes: [
    {
      id: "1",
      type: "rect",
      x: 100,
      y: 100,
      text: "矩形"
    },
    {
      id: "2",
      type: "circle",
      x: 300,
      y: 100,
      text: "圆形"
    },
    {
      id: "3",
      type: "ellipse",
      x: 500,
      y: 100,
      text: "椭圆"
    },
    {
      id: "4",
      type: "polygon",
      x: 100,
      y: 250,
      text: "多边形"
    },
    {
      id: "5",
      type: "diamond",
      x: 300,
      y: 250,
      text: "菱形"
    },
    {
      id: "6",
      type: "text",
      x: 500,
      y: 250,
      text: "纯文本节点"
    },
    {
      id: "7",
      type: "html",
      x: 100,
      y: 400,
      text: "html节点"
    }
  ]
});

自定义节点

LogicFlow 是基于继承来实现自定义节点

开发者可以继承 LogicFlow 内置的节点,然后利用面向对象的重写机制。重写节点样式相关的方法,来达到自定义节点样式的效果

js
// 矩形
import { RectNode, RectNodeModel } from "@logicflow/core";
// 圆形
import { CircleNode, CircleNodeModel } from "@logicflow/core";
// 椭圆
import { EllipseNode, EllipseNodeModel } from "@logicflow/core";
// 多边形
import { PolygonNode, PolygonNodeModel } from "@logicflow/core";
// 菱形
import { DiamondNode, DiamondNodeModel } from "@logicflow/core";
// 文本
import { TextNode, TextNodeModel } from "@logicflow/core";
// HTML
import { HtmlNode, HtmlNodeModel } from "@logicflow/core";
// 矩形
import { RectNode, RectNodeModel } from "@logicflow/core";
// 圆形
import { CircleNode, CircleNodeModel } from "@logicflow/core";
// 椭圆
import { EllipseNode, EllipseNodeModel } from "@logicflow/core";
// 多边形
import { PolygonNode, PolygonNodeModel } from "@logicflow/core";
// 菱形
import { DiamondNode, DiamondNodeModel } from "@logicflow/core";
// 文本
import { TextNode, TextNodeModel } from "@logicflow/core";
// HTML
import { HtmlNode, HtmlNodeModel } from "@logicflow/core";

例如,自定义一个继承矩形节点的自定义节点

需要继承矩形节点的view和model类,取一个type名

js
import { RectNode, RectNodeModel } from "@logicflow/core";

class UserTaskModel extends RectNodeModel {}

class UserTaskView extends RectNode {}

export default {
  type: "UserTask",
  view: UserTaskView,
  model: UserTaskModel,
};
import { RectNode, RectNodeModel } from "@logicflow/core";

class UserTaskModel extends RectNodeModel {}

class UserTaskView extends RectNode {}

export default {
  type: "UserTask",
  view: UserTaskView,
  model: UserTaskModel,
};

lf.register中注册自定义节点,render函数的nodes数组中type名指定为自定义节点的type名

js
import UserTask from "./UserTaskNode.js";

const lf = new LogicFlow({
  container: document.querySelector("#container"),
});
lf.register(UserTask);

lf.render({
  nodes: [
    {
      type: "UserTask",
      x: 100,
      y: 100,
    },
  ],
});
import UserTask from "./UserTaskNode.js";

const lf = new LogicFlow({
  container: document.querySelector("#container"),
});
lf.register(UserTask);

lf.render({
  nodes: [
    {
      type: "UserTask",
      x: 100,
      y: 100,
    },
  ],
});

自定义节点样式

在 LogicFlow 中,外观属性表示控制着节点边框颜色这类偏外观的属性。这些属性是可以直接通过主题配置来控制。自定义节点样式可以看做在主题的基础上基于当前节点的类型进行再次定义。例如在主题中对所有rect节点都定义其边框颜色为红色stroke: red。 那么可以在自定义节点UserTask的时候,重新定义UserTask边框为蓝色stroke: blue

示例:

js
class UserTaskModel extends RectNodeModel {
  getNodeStyle() {
    const style = super.getNodeStyle();
    style.stroke = "blue";
    style.strokeDasharray = "3 3";
    return style;
  }
}
class rectRadiusModel extends RectNodeModel {
    getNodeStyle() {
      const style = super.getNodeStyle();
      const { fill } = this.properties;
      style.fill = fill;
      style.strokeWidth = 0;
      return style;
    }
  }
class UserTaskModel extends RectNodeModel {
  getNodeStyle() {
    const style = super.getNodeStyle();
    style.stroke = "blue";
    style.strokeDasharray = "3 3";
    return style;
  }
}
class rectRadiusModel extends RectNodeModel {
    getNodeStyle() {
      const style = super.getNodeStyle();
      const { fill } = this.properties;
      style.fill = fill;
      style.strokeWidth = 0;
      return style;
    }
  }

自定义节点形状

在 LogicFlow 中,形状属性表示节点的宽width、高height,矩形的圆角radius, 圆形的半径r, 多边形的顶点points等这些控制着节点最终形状的属性。因为 LogicFlow 在计算节点的锚点、连线的起点终点的时候,会基于形状属性进行计算。对于形状属性的自定义,需要在setAttributes方法或initNodeData方法中进行

属性文档 https://docs.logic-flow.cn/docs/#/zh/api/nodeModelApi?id=形状属性

js
class customRectModel extends RectNodeModel {
  initNodeData(data) {
    super.initNodeData(data);
    this.width = 200;
    this.height = 80;
    this.radius = 50;
  }
}
class customRectModel extends RectNodeModel {
  initNodeData(data) {
    super.initNodeData(data);
    this.width = 200;
    this.height = 80;
    this.radius = 50;
  }
}

示例:自定义rect

js
<template>
  <div>
    <div id="container"></div>
  </div>
</template>

<script>
import LogicFlow from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"
import { RectNode, RectNodeModel } from "@logicflow/core"

export default {
  name: "home",
  mounted() {
    const data = {
      nodes: [
        {
          id: 1,
          type: "rectRadiusModel",
          x: 260,
          y: 60,
          text: "蓝色",
          properties: {
            fill: "#4F87BA"
          }
        },
        {
          id: 2,
          type: "rectRadiusModel",
          x: 260,
          y: 150,
          text: "绿色",
          properties: {
            fill: "#6FAC46"
          }
        },
        {
          id: 5,
          type: "rectRadiusModel",
          x: 260,
          y: 250,
          text: "橙色",
          properties: {
            fill: "#EC7C30"
          }
        }
      ]
    }
    const lf = new LogicFlow({
      container: document.querySelector("#container"),
      width: 700,
      height: 600,
      grid: {}
    })

    // 自定义model
    class rectRadiusModel extends RectNodeModel {
      // 样式属性
      getNodeStyle() {
        const style = super.getNodeStyle()
        const { fill } = this.properties
        style.fill = fill
        style.strokeWidth = 0
        return style
      }
      // 形状属性
      initNodeData(data) {
        super.initNodeData(data)
        this.width = 150
        this.height = 50
        this.radius = 25
      }
    }
    class rectNoRadiusModel extends rectRadiusModel {
      initNodeData(data) {
        super.initNodeData(data)
        this.radius = 0
      }
    }
    lf.register({
      type: "rectRadiusModel",
      view: RectNode,
      model: rectRadiusModel
    })
    lf.register({
      type: "rectRadiusModel",
      view: RectNode,
      model: rectNoRadiusModel
    })

    lf.setTheme({
      nodeText: {
        color: "#ffffff",
        overflowMode: "autoWrap",
        fontSize: 15
      }
    })
    lf.render(data)
  }
}
</script>
<template>
  <div>
    <div id="container"></div>
  </div>
</template>

<script>
import LogicFlow from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"
import { RectNode, RectNodeModel } from "@logicflow/core"

export default {
  name: "home",
  mounted() {
    const data = {
      nodes: [
        {
          id: 1,
          type: "rectRadiusModel",
          x: 260,
          y: 60,
          text: "蓝色",
          properties: {
            fill: "#4F87BA"
          }
        },
        {
          id: 2,
          type: "rectRadiusModel",
          x: 260,
          y: 150,
          text: "绿色",
          properties: {
            fill: "#6FAC46"
          }
        },
        {
          id: 5,
          type: "rectRadiusModel",
          x: 260,
          y: 250,
          text: "橙色",
          properties: {
            fill: "#EC7C30"
          }
        }
      ]
    }
    const lf = new LogicFlow({
      container: document.querySelector("#container"),
      width: 700,
      height: 600,
      grid: {}
    })

    // 自定义model
    class rectRadiusModel extends RectNodeModel {
      // 样式属性
      getNodeStyle() {
        const style = super.getNodeStyle()
        const { fill } = this.properties
        style.fill = fill
        style.strokeWidth = 0
        return style
      }
      // 形状属性
      initNodeData(data) {
        super.initNodeData(data)
        this.width = 150
        this.height = 50
        this.radius = 25
      }
    }
    class rectNoRadiusModel extends rectRadiusModel {
      initNodeData(data) {
        super.initNodeData(data)
        this.radius = 0
      }
    }
    lf.register({
      type: "rectRadiusModel",
      view: RectNode,
      model: rectRadiusModel
    })
    lf.register({
      type: "rectRadiusModel",
      view: RectNode,
      model: rectNoRadiusModel
    })

    lf.setTheme({
      nodeText: {
        color: "#ffffff",
        overflowMode: "autoWrap",
        fontSize: 15
      }
    })
    lf.render(data)
  }
}
</script>

拖拽创建节点

示例代码,给画布绑定一个mousedown事件,触发时调用lf.dnd.startDrag在画布鼠标位置创建指定类型的节点和文本

js
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";
import customCircle from "./customCircle";

const lf = new LogicFlow({
  container: document.querySelector("#app"),
  grid: true
});
lf.register(customCircle);
lf.render({
  nodes: [
    {
      type: "customCircle",
      x: 100,
      y: 200
    }
  ]
});

document.querySelector("#js_custom-dnd").addEventListener("mousedown", (e) => {
  const type = e.target.getAttribute("data-type");
  if (type) {
    lf.dnd.startDrag({
      type,
      text: `${type}节点`
    });
  }
});
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";
import customCircle from "./customCircle";

const lf = new LogicFlow({
  container: document.querySelector("#app"),
  grid: true
});
lf.register(customCircle);
lf.render({
  nodes: [
    {
      type: "customCircle",
      x: 100,
      y: 200
    }
  ]
});

document.querySelector("#js_custom-dnd").addEventListener("mousedown", (e) => {
  const type = e.target.getAttribute("data-type");
  if (type) {
    lf.dnd.startDrag({
      type,
      text: `${type}节点`
    });
  }
});

自定义img节点

js
import { h, RectNode } from '@logicflow/core'

// 图片-基础节点
class ImageModel extends RectNode.model {
  initNodeData(data) {
    super.initNodeData(data)
    this.width = 80
    this.height = 60
  }
}


class ImageNode extends RectNode.view {
  // 这里不用实现,继承的节点再进行实现
  getImageHref () {
    return;
  }
  getResizeShape() {
    const { x, y, width, height } = this.props.model
    const href = this.getImageHref()
    const attrs = {
      x: x- 1/2 * width,
      y: y - 1/2 * height,
      width,
      height,
      href,
      // 根据宽高缩放
      preserveAspectRatio: 'none meet'
    }
    return h('g', {}, [
       h('image', { ...attrs })
    ]
    );
  }
}

export default {
  type: 'image-node',
  view: ImageNode,
  model: ImageModel
}
import { h, RectNode } from '@logicflow/core'

// 图片-基础节点
class ImageModel extends RectNode.model {
  initNodeData(data) {
    super.initNodeData(data)
    this.width = 80
    this.height = 60
  }
}


class ImageNode extends RectNode.view {
  // 这里不用实现,继承的节点再进行实现
  getImageHref () {
    return;
  }
  getResizeShape() {
    const { x, y, width, height } = this.props.model
    const href = this.getImageHref()
    const attrs = {
      x: x- 1/2 * width,
      y: y - 1/2 * height,
      width,
      height,
      href,
      // 根据宽高缩放
      preserveAspectRatio: 'none meet'
    }
    return h('g', {}, [
       h('image', { ...attrs })
    ]
    );
  }
}

export default {
  type: 'image-node',
  view: ImageNode,
  model: ImageModel
}
js
import ImageNode from './ImageNode'

// 云形状的图片节点
class CloudNode extends ImageNode.view {
  getImageHref () {
    return 'https://dpubstatic.udache.com/static/dpubimg/0oqFX1nvbD/cloud.png';
  }
}


export default {
  type: 'image-cloud',
  view: CloudNode,
  model: ImageNode.model
}
import ImageNode from './ImageNode'

// 云形状的图片节点
class CloudNode extends ImageNode.view {
  getImageHref () {
    return 'https://dpubstatic.udache.com/static/dpubimg/0oqFX1nvbD/cloud.png';
  }
}


export default {
  type: 'image-cloud',
  view: CloudNode,
  model: ImageNode.model
}

自定义可缩放节点

https://docs.logic-flow.cn/docs/#/zh/guide/extension/extension-node-resize

js
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'

class ImageModel extends RectResize.model {
  initNodeData(data) {
    super.initNodeData(data)
    this.width = 80
    this.height = 60
  }
}

class ImageNode extends RectResize.view {
  getImageHref() {
    return 'https://dpubstatic.udache.com/static/dpubimg/0oqFX1nvbD/cloud.png'
  }
  getResizeShape() {
    const { x, y, width, height } = this.props.model
    const href = this.getImageHref()
    const attrs = {
      x: x - (1 / 2) * width,
      y: y - (1 / 2) * height,
      width,
      height,
      href,
      // preserveAspectRatio: 'none meet' 是 SVG 中的一个属性,用于设置图片在视口中的对齐方式和缩放方式。在这个组件中,该属性的值是 'none meet',表示图片不按比例缩放,会被拉伸或压缩以适应视口的大小。此外,meet 还有一个对应的值 'xMaxYMax meet',表示图片会按比例缩放,但不会超出视口的范围,即保证图片完全呈现且留白最少。而在 'none' 模式下,图片会按照视口大小进行缩放,不考虑原始宽高比例。
      preserveAspectRatio: 'none meet'
    }
    return h('g', {}, [h('image', { ...attrs })])
  }
}

export default {
  type: 'image-node',
  view: ImageNode,
  model: ImageModel
}
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'

class ImageModel extends RectResize.model {
  initNodeData(data) {
    super.initNodeData(data)
    this.width = 80
    this.height = 60
  }
}

class ImageNode extends RectResize.view {
  getImageHref() {
    return 'https://dpubstatic.udache.com/static/dpubimg/0oqFX1nvbD/cloud.png'
  }
  getResizeShape() {
    const { x, y, width, height } = this.props.model
    const href = this.getImageHref()
    const attrs = {
      x: x - (1 / 2) * width,
      y: y - (1 / 2) * height,
      width,
      height,
      href,
      // preserveAspectRatio: 'none meet' 是 SVG 中的一个属性,用于设置图片在视口中的对齐方式和缩放方式。在这个组件中,该属性的值是 'none meet',表示图片不按比例缩放,会被拉伸或压缩以适应视口的大小。此外,meet 还有一个对应的值 'xMaxYMax meet',表示图片会按比例缩放,但不会超出视口的范围,即保证图片完全呈现且留白最少。而在 'none' 模式下,图片会按照视口大小进行缩放,不考虑原始宽高比例。
      preserveAspectRatio: 'none meet'
    }
    return h('g', {}, [h('image', { ...attrs })])
  }
}

export default {
  type: 'image-node',
  view: ImageNode,
  model: ImageModel
}

更改节点的text位置

比如通过properties属性设置

js
import ImageNode from './ImageNode'

class CloudNode extends ImageNode.view {
  getImageHref() {
    return new URL(`/src/assets/images/3.png`, import.meta.url).href
  }
}
class CloudNodeModel extends ImageNode.model {
  initNodeData(data) {
    const { labelPosition } = this.properties
    // 设置节点text位置
    if (data.text && typeof data.text === 'string') {
      data.text = {
        value: data.text || '',
        x: data.x - (labelPosition === 'left' ? 100 : -100),
        y: data.y
      }
    }
    super.initNodeData(data)
  }
}
export default {
  type: 'image-three',
  view: CloudNode,
  model: CloudNodeModel
}

import ImageNode from './ImageNode'

class CloudNode extends ImageNode.view {
  getImageHref() {
    return new URL(`/src/assets/images/3.png`, import.meta.url).href
  }
}
class CloudNodeModel extends ImageNode.model {
  initNodeData(data) {
    const { labelPosition } = this.properties
    // 设置节点text位置
    if (data.text && typeof data.text === 'string') {
      data.text = {
        value: data.text || '',
        x: data.x - (labelPosition === 'left' ? 100 : -100),
        y: data.y
      }
    }
    super.initNodeData(data)
  }
}
export default {
  type: 'image-three',
  view: CloudNode,
  model: CloudNodeModel
}

如何使用插件

sh
npm i @logicflow/extension -s
npm i @logicflow/extension -s

注意,除了导入模块,别忘了导入插件的样式

js
import { LogicFlow } from "@logicflow/core"
import { Control, Menu, DndPanel, SelectionSelect } from "@logicflow/extension"
import '@logicflow/extension/lib/style/index.css'
import { LogicFlow } from "@logicflow/core"
import { Control, Menu, DndPanel, SelectionSelect } from "@logicflow/extension"
import '@logicflow/extension/lib/style/index.css'

方法一,全局使用

js
LogicFlow.use(Control)
LogicFlow.use(Menu)
LogicFlow.use(DndPanel)
LogicFlow.use(SelectionSelect)
LogicFlow.use(Control)
LogicFlow.use(Menu)
LogicFlow.use(DndPanel)
LogicFlow.use(SelectionSelect)

方法二,实例中使用

js
 const lf = new LogicFlow({
      container: document.querySelector("#container"),
      grid: true,
      plugins: [Control, Menu, DndPanel, SelectionSelect]
    })
 const lf = new LogicFlow({
      container: document.querySelector("#container"),
      grid: true,
      plugins: [Control, Menu, DndPanel, SelectionSelect]
    })

拖拽菜单

https://docs.logic-flow.cn/docs/#/zh/guide/extension/component-dnd-panel

vue示例

vite+vue3

vue
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { Control, Menu, DndPanel, SelectionSelect, Snapshot } from '@logicflow/extension'
import '@logicflow/extension/lib/style/index.css'
LogicFlow.use(DndPanel)
import { onMounted } from 'vue'
import one from './node/one'
import two from './node/two'
import three from './node/three'
import four from './node/four'
import five from './node/five'
import six from './node/six'
const registerCustomElement = (lf) => {
  lf.register(one)
  lf.register(two)
  lf.register(three)
  lf.register(four)
  lf.register(five)
  lf.register(six)
}

const data = {
  // 节点
  nodes: [
    {
      id: 1,
      type: 'image-one',
      x: 300,
      y: 200,
      text: '地调一平面'
    },
    {
      id: 2,
      type: 'image-two',
      x: 300,
      y: 300,
      text: '一平面路由器'
    },
    {
      id: 3,
      type: 'image-three',
      x: 500,
      y: 600,
      text: '一平面一区纵向'
    },
    {
      id: 4,
      type: 'image-four',
      x: 300,
      y: 600,
      text: '一平面一区交换机'
    }
  ],
  // 边
  edges: [
    {
      type: 'polyline',
      sourceNodeId: 1,
      targetNodeId: 2
    }
  ]
}
onMounted(() => {
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 1300,
    height: 900,
    grid: true
  })
  lf.extension.dndPanel.setPatternItems([
    {
      label: '选区',
      icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
      callback: () => {
        lf.extension.selectionSelect.openSelectionSelect()
        lf.once('selection:selected', () => {
          lf.extension.selectionSelect.closeSelectionSelect()
        })
      }
    },
    {
      type: 'image-one',
      text: '地调一平面',
      label: '地调一平面',
      className: 'icon',
      icon: new URL(`/src/assets/images/1.png`, import.meta.url).href
    },
    {
      type: 'image-two',
      text: '一平面路由器',
      label: '一平面路由器',
      className: 'icon',
      icon: new URL(`/src/assets/images/2.png`, import.meta.url).href
    },
    {
      type: 'image-three',
      text: '一平面一区纵向',
      label: '一平面一区纵向',
      className: 'icon',
      icon: new URL(`/src/assets/images/3.png`, import.meta.url).href
    },
    {
      type: 'image-four',
      text: '一平面一区交换机',
      label: '一平面一区交换机',
      className: 'icon',
      icon: new URL(`/src/assets/images/4.png`, import.meta.url).href
    }
  ])
  registerCustomElement(lf)
  lf.render(data)
})
</script>
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { Control, Menu, DndPanel, SelectionSelect, Snapshot } from '@logicflow/extension'
import '@logicflow/extension/lib/style/index.css'
LogicFlow.use(DndPanel)
import { onMounted } from 'vue'
import one from './node/one'
import two from './node/two'
import three from './node/three'
import four from './node/four'
import five from './node/five'
import six from './node/six'
const registerCustomElement = (lf) => {
  lf.register(one)
  lf.register(two)
  lf.register(three)
  lf.register(four)
  lf.register(five)
  lf.register(six)
}

const data = {
  // 节点
  nodes: [
    {
      id: 1,
      type: 'image-one',
      x: 300,
      y: 200,
      text: '地调一平面'
    },
    {
      id: 2,
      type: 'image-two',
      x: 300,
      y: 300,
      text: '一平面路由器'
    },
    {
      id: 3,
      type: 'image-three',
      x: 500,
      y: 600,
      text: '一平面一区纵向'
    },
    {
      id: 4,
      type: 'image-four',
      x: 300,
      y: 600,
      text: '一平面一区交换机'
    }
  ],
  // 边
  edges: [
    {
      type: 'polyline',
      sourceNodeId: 1,
      targetNodeId: 2
    }
  ]
}
onMounted(() => {
  const lf = new LogicFlow({
    container: document.querySelector('#container') as HTMLElement,
    width: 1300,
    height: 900,
    grid: true
  })
  lf.extension.dndPanel.setPatternItems([
    {
      label: '选区',
      icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
      callback: () => {
        lf.extension.selectionSelect.openSelectionSelect()
        lf.once('selection:selected', () => {
          lf.extension.selectionSelect.closeSelectionSelect()
        })
      }
    },
    {
      type: 'image-one',
      text: '地调一平面',
      label: '地调一平面',
      className: 'icon',
      icon: new URL(`/src/assets/images/1.png`, import.meta.url).href
    },
    {
      type: 'image-two',
      text: '一平面路由器',
      label: '一平面路由器',
      className: 'icon',
      icon: new URL(`/src/assets/images/2.png`, import.meta.url).href
    },
    {
      type: 'image-three',
      text: '一平面一区纵向',
      label: '一平面一区纵向',
      className: 'icon',
      icon: new URL(`/src/assets/images/3.png`, import.meta.url).href
    },
    {
      type: 'image-four',
      text: '一平面一区交换机',
      label: '一平面一区交换机',
      className: 'icon',
      icon: new URL(`/src/assets/images/4.png`, import.meta.url).href
    }
  ])
  registerCustomElement(lf)
  lf.render(data)
})
</script>

Released under the MIT License.