
1618558278291.jpg
- 你可以直接查看???? 官方文檔 ????,文檔寫的很棒????;
- 你也可以簡單聽我BBLL,順便告訴你我的親身經(jīng)歷,和常用參數(shù);
遇到問題:
當(dāng)你遇到下面這幾種圖形編輯時,你可能會想:
??這不是要專門搞一套js代碼嗎,canvas我也不熟練啊??,這工程量也太大了,放棄吧?。「习逭f這個需求做不了

2021-04-16 10-46-28.gif
當(dāng)然
x1,起初我也是這么想的,而且我也嘗試了自己用canvas寫一個這個東西~當(dāng)然
x2,寫起來又是一碼事了,什么小問題各種層出不窮,然后果斷棄坑~當(dāng)然
x3,我可以百度找現(xiàn)成的代碼啊,網(wǎng)上那么多插件啥的,后來才發(fā)現(xiàn)魚目混雜,根本無從下手,萬一遇到問題找誰???♂???♂?所以,在最后朋友(
朋友多還是有那么點用的,致敬 ??木兄)的推薦下,還是遇到了它 ------???? Antv/X6????!!
步入正題:

2021-04-16 10-32-55.gif
上圖是我結(jié)合自身項目需求+ Vue,制作的類似于一個工廠智能小車工作線路圖,沒聽懂的,也可以忽略這句話??~
???? 官方文檔入口 ????
常用參數(shù):
//創(chuàng)建地圖
this.graph = new Graph({
snapline: true, //對齊線
history: {
enabled: true, //歷史記錄
ignoreChange: true //ignoreChange 是否忽略屬性變化
},
panning: true, //支持平移拖拽
container: document.getElementById('container'),
width: window.innerWidth,
height: window.innerHeight,
background: {
color: '#fffbe6' // 設(shè)置畫布背景顏色
},
grid: {
size: 10, // 網(wǎng)格大小 10px
visible: true // 渲染網(wǎng)格背景
},
connecting: {
allowPort: true, //是否允許邊鏈接到鏈接樁
allowEdge: false, //是否允許邊鏈接到另一個邊
allowNode: false, //是否允許邊鏈接到節(jié)點(非節(jié)點上的鏈接樁)
allowLoop: false, //是否允許創(chuàng)建循環(huán)連線,即邊的起始節(jié)點和終止節(jié)點為同一節(jié)點
allowMulti: false, //是否允許在相同的起始節(jié)點和終止之間創(chuàng)建多條邊
allowBlank: false, //是否允許連接到畫布空白位置的點
// 自動吸附
snap: {
radius: 20
}
}
})
//加載地圖數(shù)據(jù)
this.graph.fromJSON(this.data)
右上角工具欄:

image.png
自己寫的,主要包含 撤銷,重做,創(chuàng)建節(jié)點,圖形放大,圖形縮小,重置視圖,數(shù)據(jù)導(dǎo)出;
//撤銷操作
this.graph.undo()
//重做
this.graph.redo()
//創(chuàng)建節(jié)點
const rect = this.graph.addNode({
shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
...
})
//地圖放大縮小
this.graph.zoom(0.1)
this.graph.zoom(-0.1)
//重置視圖
this.graph.centerContent() //畫布居中
this.graph.zoom(0)
//序列化/反序列化 數(shù)據(jù)格式
// https://antv-x6.gitee.io/zh/docs/tutorial/intermediate/serialization
// graph.toJSON() 方法來導(dǎo)出圖中的節(jié)點和邊
this.graph.toJSON()
選中和工具Tools:

2021-04-16 11-13-07.gif
使用工具 Tools文檔
節(jié)點和邊選中代碼示例
節(jié)點和邊選中——事件屬性參考文檔
//在創(chuàng)建節(jié)點的時候,直接加入刪除按鈕tools
const rect = this.graph.addNode({
shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
...
attrs: {
...
},
//使用工具
tools: [
{
name: 'button-remove', // 工具名稱
args: { x: 5, y: 5 } // 工具對應(yīng)的參數(shù)
}
]})
案例代碼:
<template>
<div>
<span class="toolbar">
<div class="tool" title="撤銷" @click="toUndo()">
<i class="el-icon-refresh-left"></i>
</div>
<div class="tool" title="重做" @click="toRedo()">
<i class="el-icon-refresh-right"></i>
</div>
<div class="tool" title="創(chuàng)建節(jié)點" @click="createNodes('rect')">
<div class="rect"></div>
</div>
<div class="tool" @click="mapZoom('+')" title="放大視圖">
<i class="el-icon-zoom-in"></i>
</div>
<div class="tool" @click="mapZoom('-')" title="縮小視圖">
<i class="el-icon-zoom-out"></i>
</div>
<div class="tool" @click="mapZoom()" title="重置視圖">
<i class="el-icon-full-screen"></i>
</div>
<div class="tool" @click="save()" title="保存">
<i class="el-icon-cpu"></i>
</div>
</span>
<div id="container"></div>
</div>
</template>
<script>
import { Graph } from '@antv/x6'
export default {
data() {
return {
graph_zoom: 0, //地圖縮放比例
graph: null,
// data: {
// 節(jié)點
// nodes: [
// {
// id: 'node1', // String,可選,節(jié)點的唯一標識
// x: 40, // Number,必選,節(jié)點位置的 x 值
// y: 40, // Number,必選,節(jié)點位置的 y 值
// width: 60, // Number,可選,節(jié)點大小的 width 值
// height: 60, // Number,可選,節(jié)點大小的 height 值
// label: 'node1', // String,節(jié)點標簽
// tools: ['button-remove']
// },
// {
// id: 'node2', // String,節(jié)點的唯一標識
// x: 160, // Number,必選,節(jié)點位置的 x 值
// y: 180, // Number,必選,節(jié)點位置的 y 值
// width: 60, // Number,可選,節(jié)點大小的 width 值
// height: 60, // Number,可選,節(jié)點大小的 height 值
// label: 'node2' // String,節(jié)點標簽
// },
// {
// id: 'node3', // String,節(jié)點的唯一標識
// x: 40, // Number,必選,節(jié)點位置的 x 值
// y: 180, // Number,必選,節(jié)點位置的 y 值
// width: 60, // Number,可選,節(jié)點大小的 width 值
// height: 60, // Number,可選,節(jié)點大小的 height 值
// label: 'node3' // String,節(jié)點標簽
// }
// ],
// 邊
// edges: [
// {
// source: 'node1', // String,必須,起始節(jié)點 id
// target: 'node2' // String,必須,目標節(jié)點 id
// }
// ],
// }
data: []
}
},
mounted() {
this.init()
},
methods: {
//初始化地圖
init() {
//創(chuàng)建地圖
this.graph = new Graph({
snapline: true, //對齊線
history: {
enabled: true, //歷史記錄
ignoreChange: true //ignoreChange 是否忽略屬性變化
},
panning: true, //支持平移拖拽
container: document.getElementById('container'),
width: window.innerWidth,
height: window.innerHeight,
background: {
color: '#fffbe6' // 設(shè)置畫布背景顏色
},
grid: {
size: 10, // 網(wǎng)格大小 10px
visible: true // 渲染網(wǎng)格背景
},
connecting: {
allowPort: true, //是否允許邊鏈接到鏈接樁
allowEdge: false, //是否允許邊鏈接到另一個邊
allowNode: false, //是否允許邊鏈接到節(jié)點(非節(jié)點上的鏈接樁)
allowLoop: false, //是否允許創(chuàng)建循環(huán)連線,即邊的起始節(jié)點和終止節(jié)點為同一節(jié)點
allowMulti: false, //是否允許在相同的起始節(jié)點和終止之間創(chuàng)建多條邊
allowBlank: false, //是否允許連接到畫布空白位置的點
// 自動吸附
snap: {
radius: 20
},
// createEdge() {
// //創(chuàng)建動畫虛線邊
// return new Shape.Edge({
// attrs: {
// line: {
// stroke: '#1890ff',
// strokeDasharray: 5,
// targetMarker: 'classic',
// style: {
// animation: 'ant-line 30s infinite linear'
// }
// }
// }
// })
// }
}
})
//加載地圖數(shù)據(jù)
this.graph.fromJSON(this.data)
this.graph.centerContent() //畫布居中
//節(jié)點點擊事件
this.graph.on('node:click', ({ e, x, y, node, view }) => {
// console.log(node)
this.selectReset()
node.attr('body/stroke', 'orange')
})
//邊點擊事件
this.graph.on('edge:click', ({ e, x, y, edge, view }) => {
// console.log(edge)
this.selectReset()
edge.attr('line/stroke', 'orange')
edge.prop('labels/0', {
attrs: {
body: {
stroke: 'orange'
}
}
})
}),
//節(jié)點雙擊事件
this.graph.on('node:dblclick', ({ e, x, y, node, view }) => {
alert('節(jié)點ID:' + node.id)
console.log(node)
})
//邊雙擊事件
this.graph.on('edge:dblclick', ({ e, x, y, edge, view }) => {
console.log(edge)
alert(
`邊ID:${edge.id}, 起始節(jié)點: ${edge.source.cell},目標節(jié)點: ${edge.target.cell}`
)
})
},
//保存,獲取節(jié)點等數(shù)據(jù)
save() {
//序列化/反序列化 數(shù)據(jù)格式
// https://antv-x6.gitee.io/zh/docs/tutorial/intermediate/serialization
// graph.toJSON() 方法來導(dǎo)出圖中的節(jié)點和邊
console.log(this.graph.toJSON())
},
//撤銷操作
toUndo() {
this.graph.undo()
},
//重做
toRedo() {
this.graph.redo()
// if (this.graph.isHistoryEnabled()) {
// this.graph.disableHistory()
// } else {
// this.graph.enableHistory()
// }
},
//地圖放大縮小
mapZoom(type) {
if (type == '+') {
this.graph.zoom(0.1)
this.graph_zoom += 0.1
} else if (type == '-') {
this.graph.zoom(-0.1)
this.graph_zoom -= 0.1
} else {
this.graph.zoom(
this.graph_zoom <= 0 ? Math.abs(this.graph_zoom) : -this.graph_zoom
)
this.graph.centerContent() //畫布居中
this.graph_zoom = 0
}
},
//創(chuàng)建節(jié)點
createNodes(type) {
if (type == 'rect') {
const rect = this.graph.addNode({
shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
x: 0,
y: 0,
width: 60,
height: 60,
angle: 0,
attrs: {
body: {
fill: '#fff', // 背景顏色
stroke: '#000' // 邊框顏色
},
label: {
text: 'Node', // 文本
fill: '#333', // 文字顏色
fontSize: 13 // 文字大小
}
},
tools: [
{
name: 'button-remove', // 工具名稱
args: { x: 5, y: 5 } // 工具對應(yīng)的參數(shù)
}
],
//連接樁
// ports: [
// {
// id: 'port1',
// attrs: {
// circle: {
// r: 6,
// // magnet: true 這個特殊屬性,使鏈接樁在連線交互時可以被連接上
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff'
// }
// }
// },
// {
// id: 'port2',
// attrs: {
// circle: {
// r: 6,
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff'
// }
// }
// }
// ]
ports: {
groups: {
// 輸入鏈接樁群組定義
left: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff'
}
}
},
right: {
position: 'right',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff'
}
}
},
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff'
}
}
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff'
}
}
}
},
items: [
{
id: 'port1-1',
group: 'left'
},
{
id: 'port1-2',
group: 'left',
attrs: {
circle: {
stroke: '#e9352f'
}
}
},
{
id: 'port2-1',
group: 'right',
attrs: {
circle: {
stroke: '#e9352f'
}
}
},
{
id: 'port2-2',
group: 'right'
},
{
id: 'port3-1',
group: 'top',
attrs: {
circle: {
stroke: '#e9352f'
}
}
},
{
id: 'port3-2',
group: 'top'
},
{
id: 'port4-1',
group: 'bottom'
},
{
id: 'port4-2',
group: 'bottom',
attrs: {
circle: {
stroke: '#e9352f'
}
}
}
]
}
})
}
// console.log(this.graph)
},
//創(chuàng)建邊
createEdges(type) {
const rect = this.graph.addEdge({
shape: 'edge', // 指定使用何種圖形,默認值為 'edge'
source: 'node1',
target: 'node3'
})
},
//選擇節(jié)點,邊時重置顏色
selectReset() {
// this.graph.drawBackground({ color: '#fff' })
const nodes = this.graph.getNodes()
const edges = this.graph.getEdges()
nodes.forEach(node => {
node.attr('body/stroke', '#000')
})
edges.forEach(edge => {
edge.attr('line/stroke', 'black')
edge.prop('labels/0', {
attrs: {
body: {
stroke: 'black'
}
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
.toolbar {
// padding: 0 20px;
box-sizing: border-box;
height: 40px;
background: white;
box-shadow: 0 2px 6px #e1e1e1;
position: fixed;
right: 0;
z-index: 999;
display: flex;
align-items: center;
.tool {
cursor: pointer;
width: 40px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
&:hover {
background: #f1f1f1;
}
}
}
.rect {
width: 10px;
height: 10px;
border: 1px solid #5a5a5a;
// color: #e9352f;
}
</style>