乐趣区

关于vue3:vue封装x6为原生组件

antv-x6-vue

github 地址:antv-x6-vue

核心思想

  1. 因为 x6 次要面向编辑场景,所以对每一个节点有更多的交互逻辑。所以,将 x6 的 Shape 形象成组件,每一个组件负责管理本人的生命周期。
  2. 针对简单的自定义图形,利用 x6 反对渲染 vue 组件 @antv/x6-vue-shape 的性能,同时利用 slots 将节点渲染交给以后组件,将图形相干逻辑交给 x6。

    import {VueShape as VueShapeContainer} from '@antv/x6-vue-shape';
    
    cell.value = new VueShapeContainer({
      id, width, height,
      primer, useForeignObject,
      // 这里将本人的 slots 中的内容强行放到画布中去
      // 这样图构造的交互还有一些操作逻辑交给 x6
      // 通过 vue 绘制的组件渲染和组件外部交互逻辑交给用户
      component: component
     ? component
     : () => h('div', {key: id, class: 'vue-shape'}, slots.default ? slots.default({props, item: cell}) : null),
      ...otherOptions,
    })
    graph.addCell(cell.value)
    

  1. 提供useVueShape,能够很容易的自定义一个 vue 组件定制进去的节点。
  2. 提供useCellEvent,能够比拟不便的给以后节点绑定事件。

    const CustomNode = defineComponent({
      name: 'CustomNode',
      props: [...VueShapeProps, 'otherOptions'],
      inject: [contextSymbol],
      setup(props, context) {
     // 间接传递 props 给 useVueShape,watch 的时候不能监听到变动
     const cell = useVueShape(() => props, context)
     useCellEvent('node:click', (e) => context.emit('click', e), {cell})
     return () => null}
    })
  3. 提供 useTeleport,优化x6-vue-shape 默认创立多个 App 导致渲染性能问题。同时避免出现节点数据更新不及时问题。

装置

yarn add antv-x6-vue

Components

  • [x] 提供 Graph 容器以及 GraphContext.useContext 获取 x6graph对象。能够利用这个对象操作画布,绑定事件。
  • [x] 包装 Shape 作为 vue 组件+应用 x6-vue-shape 封装自定义组件,裸露的组件有:
shape 名称 形容
Node rect 等同于 Shape.Rect
Edge edge 等同于 Shape.Edge
VueShape vue-shape 应用 @antv/x6-vue-shape 渲染的自定义 vue 组件的容器,能够将 slots.default 内容渲染到节点内。
Shape.Rect rect 矩形。
Shape.Circle circle 圆形。
Shape.Ellipse ellipse 椭圆。
Shape.Polygon polygon 多边形。
Shape.Polyline polyline 折线。
Shape.Path path 门路。
Shape.Image image 图片。
Shape.HTML html HTML 节点,应用 foreignObject 渲染 HTML 片段。
Shape.TextBlock text-block 文本节点,应用 foreignObject 渲染文本。
Shape.BorderedImage image-bordered 带边框的图片。
Shape.EmbeddedImage image-embedded 内嵌入矩形的图片。
Shape.InscribedImage image-inscribed 内嵌入椭圆的图片。
Shape.Cylinder cylinder 圆柱。
Shape.Edge edge 边。
Shape.DoubleEdge double-edge 双线边。
Shape.ShadowEdge shadow-edge 暗影边。

另外提供帮忙函数

名称 形容
useCell 应用这个函数能够通过传递 markup 之类的参数自定义节点
useVueShape 应用这个函数自定义 vue 的渲染内容定制更加简单的节点
useCellEvent 通过这个函数绑定事件到 cell 下面
  • [x] 形象连贯桩为组件应用
名称 形容
PortGroup 提供 ports/groups/<group_name> 相干的配置,同时也作为 Port 组件的容器,提供一个默认的 group 名称
Port 调用 addPort/removePort 操作以后连贯桩,比 x6 官网多提供一个 magnet 参数(默认状况须要应用 attrs/circle/magnet 进行配置)。另外,Port 也能够独立应用。

应用 Port 和 PortGroup 的时候,能够放在一个以 port 命名的 slot 外面(思考到默认的 VueShape 会将默认的 slot 认为是用户自定义的节点,这里应用 slots.port 辨别一下),也能够间接应用默认的 slot

<Node id="1" :x="100" :y="100" label="node1">
  <PortGroup name="in" position="top" :attrs="{circle: {r: 6, magnet: true, stroke:'#31d0c6'}}">
    <Port id="id1" />
    <Port id="id2" :magnet="false" />
  </PortGroup>
</Node>
<Node id="2" :x="200" :y="200" label="node2">
  <Port id="id1" />
</Node>
  • [x] 提供内置的一些组件
名称 形容
Grid 渲染网格
Background 渲染背景
Scroller 滚动组件
Clipboard 剪贴板,配合 Keyboard 组件能够应用ctrl+c/ctrl+x/ctrl+v
Keyboard 键盘快捷键
MouseWheel 鼠标滚轮,反对应用滚轮实现画布放大放大
Connecting 配置连线相干参数和帮忙办法
  • [x] Widgets
名称 形容
Snapline 对齐线
Selection 点选 / 框选
MiniMap 小地图
Stencil 内置的带分组和搜寻性能的拖拽组件,还提供 StencilGroup 以实现分组性能
Contextmenu 右键菜单
TeleportContainer 一个默认和 useVueShape 绑定到同一个 view 的容器,应用这个组件的时候,能够不必手动调用 useTeleport,也不必专门指定 view

TODO

  • [] Stencil 反对默认分组(不应用 StencilGroup 的状况)
  • [] Dnd 也作为组件实现
  • [x] ContextMenu:实现一个默认的 menu,同时裸露一个 useContextMenu 不便用户定制
  • [x] 实现 Connecting,也作为组件应用
  • [x] 提供 PluginInstallFunction,反对全局注册组件(组件有 x6- 或者 X6 前缀,例如 X6Node,x6-node 都会对应后面提到的 Node 组件)

    <x6-node id="44" :x="400" :y="300" label="node4">
    <x6-port-group name="in" position="top" :attrs="{circle: {r: 6, magnet: true, stroke:'#31d0c6'}}">
      <x6-port id="id1" />
    </x6-port-group>
    </x6-node>
  • [x] 反对群组性能。UI 嵌套的时候主动调用 embed 和 unembed 函数解决父子关系

    <Node id="9" :x="500" :y="200" label="node9" :width="300" :height="200">
    <Node id="99" :x="550" :y="220" label="node99" :width="200" :height="150">
      <Node id="999" :x="580" :y="240" label="node999"></Node>
    </Node>
    </Node>
  • [x] 应用 Teleport 渲染

    默认的 x6-vue-shape 把每一个节点渲染成一个 vue 的 app 导致渲染性能问题
    通过 vue3 提供的 Teleport 性能,让以后 App 的子组件渲染到 foreignobject 外部。解决性能问题的同时,也能更好的解决 VueShape 组件外部数据及时更新的问题

DEMO

import {defineComponent, reactive} from 'vue'
import Graph, {Node, Edge, Grid, Background} from 'antv-x6-vue'


export default defineComponent({setup(props) {
    // ...
    const state = reactive({
      showGrid: true,
      y: 10,
      visible: true,
    })
    const methods = {added(e) {console.log('added', e)
      },
      click(e) {console.log('click', e)
      },
      changed(e) {console.log('changed', e)
      },
    }
    return {...toRefs(state), ...methods }
  },
})

// template
<template>
  <Graph>
    <Node id="1" :x="100" :y="100" />
    <Node id="2" :x="200" :y="200" />
    <Edge id="e1" source="1" target="2" />
    <VueShape primer="rect" id="3" :x="200" :y="300" :width="160" :attrs="{rect: {fill:'#ddd', stroke:'#333'}, label: {text:'VueShape'}}">
      <div> 这里是一个 vue 的组件 </div>
      <img style="width: 30px;height:30px;" src="https://v3.cn.vuejs.org/logo.png" />
    </VueShape>
    <CustomNode
      v-if="visible"
      primer="circle"
      id="4"
      :x="400" :y="y"
      :attrs="{circle: {fill:'#ddd', stroke:'#333'}, label: {text:'CustomNode'}}"
      @added="added"
      @click="click"
      @cell:change:position="changed"
    >
      <span>Hello</span>
    </CustomNode>
    <Edge id="e2" source="1" target="3" />
    <Background />
    <Grid :visible="showGrid" />
    <Snapline />
    <Selection />
    <Clipboard />
  </Graph>
</template>

退出移动版