参考文档
可自定义设置以下属性
- 容器宽度(width),类型:number | string,默认 ‘100%’
- 容器高度(height),类型:number | string,默认 ‘100%’
效果如下图:

安装插件
pnpm add @antv/x6
创建DAG组件DAGChart.vue
<script setup lang="ts">
import type { Edge, Graph as X6Graph, Node } from '@antv/x6'
import { Graph } from '@antv/x6'
import { useResizeObserver, debounce } from 'vue-amazing-ui'interface Props {width?: string | number height?: string | number
}
const props = withDefaults(defineProps<Props>(), {width: '100%',height: '100%'
})
const chartWidth = computed(() => {if (typeof props.width === 'number') {return `${props.width}px`}return props.width
})
const chartHeight = computed(() => {if (typeof props.height === 'number') {return `${props.height}px`}return props.height
})const chartRef = useTemplateRef('chartRef')
let graph: X6Graph | null = nulltype DagNodeData = {label: stringtype: 'source' | 'transform' | 'sink' | 'hello' | string
}function getDefaultNodePorts() {return {groups: {in: {position: 'left',zIndex: 1,attrs: {circle: { r: 4, magnet: false, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff' }}},out: {position: 'right',zIndex: 1,attrs: {circle: { r: 4, magnet: false, stroke: '#52c41a', strokeWidth: 1, fill: '#fff' }}}},items: [{ id: 'in-1', group: 'in' },{ id: 'out-1', group: 'out' }]}
}function getGraphData() {const nodes: Node.Metadata[] = [{id: 'source-1',shape: 'rect', x: 80, y: 140, width: 140, height: 42, angle: 0, data: { label: 'Source: Kafka', type: 'source' } as DagNodeData,attrs: {body: { fill: '#e6f4ff', stroke: '#91caff', rx: 6, ry: 6 },label: { text: 'Source: Kafka', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'transform-1',shape: 'rect',x: 340,y: 120,width: 160,height: 42,data: { label: 'Transform: Clean', type: 'transform' } as DagNodeData,attrs: {body: { fill: '#f6ffed', stroke: '#b7eb8f', rx: 6, ry: 6 },label: { text: 'Transform: Clean', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'transform-2',shape: 'rect',x: 340,y: 200,width: 160,height: 42,data: { label: 'Transform: Enrich', type: 'transform' } as DagNodeData,attrs: {body: { fill: '#f6ffed', stroke: '#b7eb8f', rx: 6, ry: 6 },label: { text: 'Transform: Enrich', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'sink-1',shape: 'rect',x: 620,y: 160,width: 140,height: 42,data: { label: 'Sink: ClickHouse', type: 'sink' } as DagNodeData,attrs: {body: { fill: '#fff7e6', stroke: '#ffadd2', rx: 6, ry: 6 },label: { text: 'Sink: ClickHouse', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'hello-1',shape: 'rect',x: 880,y: 60,width: 140,height: 42,data: { label: 'Hello: World', type: 'hello' } as DagNodeData,attrs: {body: { fill: '#fff0f6', stroke: '#ffadd2', rx: 6, ry: 6 },label: { text: 'Hello: World', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'hello-2',shape: 'rect',x: 880,y: 160,width: 140,height: 42,data: { label: 'Hello: Forest', type: 'hello' } as DagNodeData,attrs: {body: { fill: '#fff0f6', stroke: '#ffadd2', rx: 6, ry: 6 },label: { text: 'Hello: Forest', fill: '#1f1f1f' }},ports: getDefaultNodePorts()},{id: 'hello-3',shape: 'rect',x: 880,y: 260,width: 140,height: 42,data: { label: 'Hello: Sea', type: 'hello' } as DagNodeData,attrs: {body: { fill: '#fff0f6', stroke: '#ffadd2', rx: 6, ry: 6 },label: { text: 'Hello: Sea', fill: '#1f1f1f' }},ports: getDefaultNodePorts()}]const edges: Edge.Metadata[] = [{id: 'edge-1',source: { cell: 'source-1', port: 'out-1' },target: { cell: 'transform-1', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-2',source: { cell: 'source-1', port: 'out-1' },target: { cell: 'transform-2', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-3',source: { cell: 'transform-1', port: 'out-1' },target: { cell: 'sink-1', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-4',source: { cell: 'transform-2', port: 'out-1' },target: { cell: 'sink-1', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-5',source: { cell: 'sink-1', port: 'out-1' },target: { cell: 'hello-1', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-6',source: { cell: 'sink-1', port: 'out-1' },target: { cell: 'hello-2', port: 'in-1' },connector: { name: 'smooth' }},{id: 'edge-7',source: { cell: 'sink-1', port: 'out-1' },target: { cell: 'hello-3', port: 'in-1' },connector: { name: 'smooth' }}]return { nodes, edges }
}function initGraph() {if (!chartRef.value) returngraph = new Graph({container: chartRef.value,grid: {visible: true, size: 10, type: 'dot', args: {color: '#ddd', thickness: 1 }},background: { color: '#fafafa' }, panning: true, mousewheel: true, interacting: { nodeMovable: true, edgeMovable: false, vertexMovable: false, edgeLabelMovable: false },autoResize: true })graph.on('node:click', ({ node }) => {const data = (node.getData ? node.getData() : node.getData) as DagNodeData | undefinedconsole.log(`节点被点击:${data?.label}`)})const data = getGraphData()graph.fromJSON(data) fitView()centerView()useResizeObserver(chartRef,debounce(() => {console.log('centerView')fitView()centerView()}, 100) as ResizeObserverCallback)
}
function zoomIn() {graph?.zoom(0.1)
}
function zoomOut() {graph?.zoom(-0.1)
}
function fitView() {graph?.zoomToFit({ padding: 20, maxScale: 1 })
}
function centerView() {graph?.centerContent()
}
onMounted(() => {initGraph()
})
onBeforeUnmount(() => {graph?.dispose()graph = null
})
</script>
<template><div class="dag-container"><divref="chartRef"class="graph-container":style="`--chart-width: ${chartWidth}; --chart-height: ${chartHeight};`"></div></div>
</template>
<style lang="less" scoped>
.dag-container {.graph-container {width: var(--chart-width) !important;height: var(--chart-height) !important;padding: 16px 24px;border-radius: 4px;}
}
</style>
在要使用的页面引入
<script setup lang="ts">
import DAGChart from './DAGChart.vue'
</script>
<template><div><h1>DAGChart 参考文档</h1><ul class="m-list"><li><a class="u-file" href="https://x6.antv.antgroup.com/tutorial/about" target="_blank">AntV X6 文档</a></li></ul><DAGChart :height="500" /></div>
</template>