|
@@ -0,0 +1,436 @@
|
|
|
+<template lang="">
|
|
|
+ <div class="vueFlow">
|
|
|
+ <div id="container"></div>
|
|
|
+ <div id="stencil"></div>
|
|
|
+ <div id="graph-container"></div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script lang="ts" setup>
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ onUnmounted,
|
|
|
+ watch,
|
|
|
+ reactive,
|
|
|
+ toRefs,
|
|
|
+ computed,
|
|
|
+ nextTick,
|
|
|
+} from 'vue'
|
|
|
+import { Graph, Shape } from '@antv/x6'
|
|
|
+import { Stencil } from '@antv/x6-plugin-stencil'
|
|
|
+import { Transform } from '@antv/x6-plugin-transform'
|
|
|
+import { Selection } from '@antv/x6-plugin-selection'
|
|
|
+import { Snapline } from '@antv/x6-plugin-snapline'
|
|
|
+import { Keyboard } from '@antv/x6-plugin-keyboard'
|
|
|
+import { Clipboard } from '@antv/x6-plugin-clipboard'
|
|
|
+import { History } from '@antv/x6-plugin-history'
|
|
|
+const aaa = (port: any) => {
|
|
|
+ console.log(port)
|
|
|
+}
|
|
|
+const antvInit = () => {
|
|
|
+ const graph = new Graph({
|
|
|
+ height:700,
|
|
|
+ container: document.getElementById('graph-container')!,
|
|
|
+ grid: true,
|
|
|
+ onPortRendered:aaa,
|
|
|
+ mousewheel: {
|
|
|
+ enabled: true,
|
|
|
+ zoomAtMousePosition: true,
|
|
|
+ modifiers: 'ctrl',
|
|
|
+ minScale: 0.5,
|
|
|
+ maxScale: 3,
|
|
|
+ },
|
|
|
+ connecting: {
|
|
|
+ router: 'manhattan',
|
|
|
+ connector: {
|
|
|
+ name: 'rounded',
|
|
|
+ args: {
|
|
|
+ radius: 8,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ anchor: 'center',
|
|
|
+ connectionPoint: 'anchor',
|
|
|
+ allowBlank: false,
|
|
|
+ snap: {
|
|
|
+ radius: 20,
|
|
|
+ },
|
|
|
+ createEdge() {
|
|
|
+ return new Shape.Edge({
|
|
|
+ attrs: {
|
|
|
+ line: {
|
|
|
+ stroke: '#A2B1C3',
|
|
|
+ strokeWidth: 2,
|
|
|
+ targetMarker: {
|
|
|
+ name: 'block',
|
|
|
+ width: 12,
|
|
|
+ height: 8,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ zIndex: 0,
|
|
|
+ })
|
|
|
+ },
|
|
|
+ validateConnection({ targetMagnet }) {
|
|
|
+ return !!targetMagnet
|
|
|
+ },
|
|
|
+ },
|
|
|
+ highlighting: {
|
|
|
+ magnetAdsorbed: {
|
|
|
+ name: 'stroke',
|
|
|
+ args: {
|
|
|
+ attrs: {
|
|
|
+ fill: '#5F95FF',
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+ const stencil = new Stencil({
|
|
|
+ title: '流程图',
|
|
|
+ target: graph,
|
|
|
+ stencilGraphWidth: 200,
|
|
|
+ stencilGraphHeight: 180,
|
|
|
+ collapsable: true,
|
|
|
+ groups: [
|
|
|
+ {
|
|
|
+ title: '基础流程图',
|
|
|
+ name: 'group1',
|
|
|
+ },
|
|
|
+
|
|
|
+ ],
|
|
|
+ layoutOptions: {
|
|
|
+ columns: 2,
|
|
|
+ columnWidth: 80,
|
|
|
+ rowHeight: 55,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ document.getElementById('stencil')!.appendChild(stencil.container)
|
|
|
+ // #region 使用插件
|
|
|
+ graph
|
|
|
+ .use(
|
|
|
+ new Transform({
|
|
|
+ resizing: true,
|
|
|
+ rotating: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ .use(
|
|
|
+ new Selection({
|
|
|
+ enabled: true,
|
|
|
+ rubberband: true,
|
|
|
+ showNodeSelectionBox: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ .use(
|
|
|
+ new Snapline({
|
|
|
+ enabled: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ .use(
|
|
|
+ new Keyboard({
|
|
|
+ enabled: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ .use(
|
|
|
+ new Clipboard({
|
|
|
+ enabled: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ .use(
|
|
|
+ new History({
|
|
|
+ enabled: true,
|
|
|
+ })
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ // 控制连接桩显示/隐藏
|
|
|
+ const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
|
|
|
+ for (let i = 0, len = ports.length; i < len; i += 1) {
|
|
|
+ ports[i].style.visibility = show ? 'visible' : 'hidden'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ graph.on('node:mouseenter', () => {
|
|
|
+ const container = document.getElementById('graph-container')!
|
|
|
+ const ports = container.querySelectorAll(
|
|
|
+ '.x6-port-body'
|
|
|
+ ) as NodeListOf<SVGElement>
|
|
|
+ showPorts(ports, true)
|
|
|
+ })
|
|
|
+ graph.on('node:mouseleave', () => {
|
|
|
+ const container = document.getElementById('graph-container')!
|
|
|
+ const ports = container.querySelectorAll(
|
|
|
+ '.x6-port-body'
|
|
|
+ ) as NodeListOf<SVGElement>
|
|
|
+ showPorts(ports, false)
|
|
|
+ })
|
|
|
+ // #endregion
|
|
|
+
|
|
|
+ // #region 初始化图形
|
|
|
+ const ports = {
|
|
|
+ groups: {
|
|
|
+ top: {
|
|
|
+ position: 'top',
|
|
|
+ attrs: {
|
|
|
+ circle: {
|
|
|
+ r: 4,
|
|
|
+ magnet: true,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ strokeWidth: 1,
|
|
|
+ fill: '#fff',
|
|
|
+ style: {
|
|
|
+ visibility: 'hidden',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ right: {
|
|
|
+ position: 'right',
|
|
|
+ attrs: {
|
|
|
+ circle: {
|
|
|
+ r: 4,
|
|
|
+ magnet: true,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ strokeWidth: 1,
|
|
|
+ fill: '#fff',
|
|
|
+ style: {
|
|
|
+ visibility: 'hidden',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ bottom: {
|
|
|
+ position: 'bottom',
|
|
|
+ attrs: {
|
|
|
+ circle: {
|
|
|
+ r: 4,
|
|
|
+ magnet: true,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ strokeWidth: 1,
|
|
|
+ fill: '#fff',
|
|
|
+ style: {
|
|
|
+ visibility: 'hidden',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ left: {
|
|
|
+ position: 'left',
|
|
|
+ attrs: {
|
|
|
+ circle: {
|
|
|
+ r: 4,
|
|
|
+ magnet: true,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ strokeWidth: 1,
|
|
|
+ fill: '#fff',
|
|
|
+ style: {
|
|
|
+ visibility: 'hidden',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ items: [
|
|
|
+ {
|
|
|
+ group: 'top',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ group: 'right',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ group: 'bottom',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ group: 'left',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ }
|
|
|
+ Graph.registerNode(
|
|
|
+ 'custom-rect',
|
|
|
+ {
|
|
|
+ inherit: 'rect',
|
|
|
+ width: 66,
|
|
|
+ height: 36,
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ strokeWidth: 1,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ fill: '#EFF4FF',
|
|
|
+ },
|
|
|
+ text: {
|
|
|
+ fontSize: 12,
|
|
|
+ fill: '#262626',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ports: { ...ports },
|
|
|
+ },
|
|
|
+ true
|
|
|
+ )
|
|
|
+
|
|
|
+ Graph.registerNode(
|
|
|
+ 'custom-polygon',
|
|
|
+ {
|
|
|
+ inherit: 'polygon',
|
|
|
+ width: 66,
|
|
|
+ height: 36,
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ strokeWidth: 1,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ fill: '#EFF4FF',
|
|
|
+ },
|
|
|
+ text: {
|
|
|
+ fontSize: 12,
|
|
|
+ fill: '#262626',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ports: {
|
|
|
+ ...ports,
|
|
|
+ items: [
|
|
|
+ {
|
|
|
+ group: 'top',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ group: 'bottom',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ true
|
|
|
+ )
|
|
|
+
|
|
|
+ Graph.registerNode(
|
|
|
+ 'custom-circle',
|
|
|
+ {
|
|
|
+ inherit: 'circle',
|
|
|
+ width: 45,
|
|
|
+ height: 45,
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ strokeWidth: 1,
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ fill: '#EFF4FF',
|
|
|
+ },
|
|
|
+ text: {
|
|
|
+ fontSize: 12,
|
|
|
+ fill: '#262626',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ports: { ...ports },
|
|
|
+ },
|
|
|
+ true
|
|
|
+ )
|
|
|
+
|
|
|
+ Graph.registerNode(
|
|
|
+ 'custom-image',
|
|
|
+ {
|
|
|
+ inherit: 'rect',
|
|
|
+ width: 52,
|
|
|
+ height: 52,
|
|
|
+ markup: [
|
|
|
+ {
|
|
|
+ tagName: 'rect',
|
|
|
+ selector: 'body',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tagName: 'image',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tagName: 'text',
|
|
|
+ selector: 'label',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ stroke: '#5F95FF',
|
|
|
+ fill: '#5F95FF',
|
|
|
+ },
|
|
|
+ image: {
|
|
|
+ width: 26,
|
|
|
+ height: 26,
|
|
|
+ refX: 13,
|
|
|
+ refY: 16,
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ refX: 3,
|
|
|
+ refY: 2,
|
|
|
+ textAnchor: 'left',
|
|
|
+ textVerticalAnchor: 'top',
|
|
|
+ fontSize: 12,
|
|
|
+ fill: '#fff',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ports: { ...ports },
|
|
|
+ },
|
|
|
+ true
|
|
|
+ )
|
|
|
+ const r1 = graph.createNode({
|
|
|
+ shape: 'custom-rect',
|
|
|
+ label: '开始',
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ rx: 20,
|
|
|
+ ry: 26,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+ const r2 = graph.createNode({
|
|
|
+ shape: 'custom-rect',
|
|
|
+ label: '办理',
|
|
|
+ })
|
|
|
+ const r3 = graph.createNode({
|
|
|
+ shape: 'custom-rect',
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ rx: 6,
|
|
|
+ ry: 6,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ label: '分支',
|
|
|
+ })
|
|
|
+ const r4 = graph.createNode({
|
|
|
+ shape: 'custom-polygon',
|
|
|
+ attrs: {
|
|
|
+ body: {
|
|
|
+ refPoints: '0,10 10,0 20,10 10,20',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ label: '结束',
|
|
|
+ })
|
|
|
+ stencil.load([r1, r2, r3, r4], 'group1')
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+onMounted(() => {
|
|
|
+ antvInit()
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style lang="scss">
|
|
|
+.vueFlow {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ #stencil {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ z-index: 100;
|
|
|
+ width: 200px;
|
|
|
+ height: 500px;
|
|
|
+ background: #fff;
|
|
|
+ border-right: 1px solid #e8e8e8;
|
|
|
+ }
|
|
|
+ #container {
|
|
|
+ height: 800px;
|
|
|
+ width: 800px;
|
|
|
+ }
|
|
|
+ #graph-container{
|
|
|
+ width: 100%;
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|