123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- <template>
- <div class="chart">
- <div class="chart-block">
- <div class="chart-ref" ref="ref_chart"></div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import {createVNode, getCurrentInstance, inject, nextTick, onMounted, provide, reactive, ref, render, watch} from "vue";
- import {Graph, Markup, Shape} from '@antv/x6'
- import {WorkflowFunc} from "@/views/workflow/types";
- import {lineStyle, portStyle} from "@/views/workflow/config";
- import nodeAdd from './node-add.vue'
- import {register} from "@antv/x6-vue-shape";
- import WorkflowNode from "@/views/workflow/nodes/index.vue";
- import {merge} from "lodash";
- import {handleEdge, handleNode} from "@/views/workflow/handle";
- const workflowFuncInject = inject('workflowFunc', {} as WorkflowFunc)
- register({
- shape: 'workflow-node',
- component: WorkflowNode,
- })
- let edgeTimer: any = null
- Graph.registerPortLayout('start', (portsPositionArgs, elemBBox) => {
- return portsPositionArgs.map((_, index) => {
- return {
- position: {
- x: 3,
- y: 25 + 3,
- },
- }
- })
- })
- Graph.registerPortLayout('end', (portsPositionArgs, elemBBox) => {
- if (edgeTimer) {
- clearTimeout(edgeTimer)
- }
- edgeTimer = setTimeout(() => {
- initEdges()
- }, 100)
- return portsPositionArgs.map((_, index) => {
- return {
- position: {
- x: elemBBox.width + 3,
- y: 25 + 3,
- },
- }
- })
- })
- Graph.registerPortLayout('more', (portsPositionArgs, elemBBox) => {
- return portsPositionArgs.map((_, index) => {
- nextTick(() => {
- workflowFuncInject.layoutPort(_.nodeId, _.portId)
- if (edgeTimer) {
- clearTimeout(edgeTimer)
- }
- edgeTimer = setTimeout(() => {
- initEdges()
- }, 100)
- })
- return {
- position: {
- x: elemBBox.width + 3,
- y: _.dy,
- },
- }
- })
- })
- const emits = defineEmits(['init'])
- const props = defineProps({
- data: <any>{}
- })
- const {proxy}: any = getCurrentInstance()
- const state: any = reactive({
- graph: null,
- isPort: false,
- isInitEdges: false
- })
- const ref_chart = ref()
- const initChart = () => {
- state.graph = new Graph({
- container: ref_chart.value,
- autoResize: true,
- panning: true,
- mousewheel: true,
- grid: {
- visible: true,
- type: 'doubleMesh',
- args: [
- {
- color: '#eee', // 主网格线颜色
- thickness: 1, // 主网格线宽度
- },
- {
- color: '#ddd', // 次网格线颜色
- thickness: 1, // 次网格线宽度
- factor: 4, // 主次网格线间隔
- },
- ],
- },
- connecting: {
- snap: { // 连线过程中自动吸附
- radius: 20,
- },
- allowBlank: false, // 是否允许连接到画布空白位置的点
- allowLoop: false, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点
- allowNode: false, // 是否允许边连接到节点
- allowEdge: false, // 是否允许边链接到另一个边
- allowPort: ({sourcePort, targetPort}: any) => { // 是否允许边链接到连接桩
- return !sourcePort?.includes('start') && targetPort?.includes('start')
- },
- allowMulti: 'withPort', // 当设置为 'withPort' 时,在起始和终止节点的相同连接桩之间只允许创建一条边(即,起始和终止节点之间可以创建多条边,但必须要要链接在不同的连接桩上)
- highlight: true,
- router: {
- name: 'manhattan',
- args: {
- startDirections: ['right'],
- endDirections: ['left'],
- },
- },
- connector: {
- name: 'rounded',
- args: {
- radius: 20,
- },
- },
- createEdge: () => new Shape.Edge({
- attrs: lineStyle
- })
- },
- onPortRendered: (args: any) => {
- const selectors = args.contentSelectors
- const container = selectors && selectors.foContent
- if (container) {
- render(createVNode(nodeAdd, {
- port: args.port,
- node: args.node,
- graph: state.graph,
- }), container)
- }
- }
- })
- initNodes()
- state.graph.zoomToFit({ maxScale: 1 })
- state.graph.centerContent() // 居中显示
- initWatch()
- emits('init', state.graph)
- }
- const initNodes = () => {
- props.data.nodes.forEach(v => {
- state.graph.addNode(handleNode(v))
- })
- }
- const initEdges = () => {
- if (!state.isInitEdges) {
- props.data.edges.forEach(v => {
- const targetNode = state.graph.getCellById(v.target)
- targetNode.setData({
- edgeSource: v.port || v.source
- }, {deep: false})
- state.graph.addEdge(handleEdge(v))
- })
- state.isInitEdges = true
- }
- }
- const initWatch = () => {
- state.graph.on('node:click', ({ e, x, y, node, view, port }) => {
- setTimeout(() => {
- if (!state.isPort) {
- workflowFuncInject.nodeClick(node)
- }
- }, 50)
- })
- state.graph.on('node:port:click', ({ e, x, y, node, view, port }) => {
- state.isPort = true;
- setTimeout(() => {
- state.isPort = false
- }, 100)
- })
- }
- watch(() => props.data, (n) => {
- if (n) {
- initChart()
- }
- }, {immediate: true})
- onMounted(() => {
- })
- defineExpose({
- toJSON: () => state.graph.toJSON()
- })
- </script>
- <style lang="scss" scoped>
- .chart {
- width: 100%;
- height: 100%;
- background-color: #f2f4f7;
- .chart-block {
- width: 100%;
- height: 100%;
- .chart-ref {
- width: 100%;
- height: 100%;
- }
- }
- }
- </style>
|