记一期@antv/x6的踩坑使用
概述
X6 是 AntV 旗下的图编辑引擎,提供了一系列开箱即用的交互组件和简单易用的节点定制能力,方便我们快速搭建流程图、DAG 图、ER 图等图应用,下面记录几个使用过程中遇到的几个坑.
坑1
使用X6的时候一定要和官网示例所给的版本号保持一致,如果直接无脑下载最新版使用,会发现最后很多接口没有提供或者已经在高版本弃用,而官方文档所给示例还是以前旧版本的,详情见使用 HTML/React/Vue/Angular 渲染中提供的vue结合使用的demon
坑2
流程图中除了官网所给的基础的节点和边,在实际项目中必然涉及到非常高的自定义扩展,特别是ui方面,因此需要使用对应x6所提供的扩展节点和自定义节点的相关方法,详情见:使用 HTML/React/Vue/Angular 渲染
示例
文章以vue2版本为例
- APP.vue
<template>
<div>
<el-button @click="addHTMLNode">追加HTML节点</el-button>
<el-button @click="addElButtonNode">追加ElButton节点</el-button>
<el-button @click="addELDatePickerNode">追加DatePicker节点</el-button>
<el-button @click="download">下载</el-button>
<div class="container"></div>
<div class="container-mini-map" ref="containerMiniMap"></div>
</div>
</template>
<script>
import { Graph, DataUri } from "@antv/x6";
import "@antv/x6-vue-shape";
import Button from "./components/Button.vue";
import DatePicker from "./components/DatePicker.vue";
Graph.registerNode("el-button", {
inherit: "vue-shape",
x: 200,
y: 150,
width: 150,
height: 100,
component: {
render: (h) => h(Button),
},
});
Graph.registerNode("el-date-picker", {
inherit: "vue-shape",
x: 200,
y: 150,
width: 150,
height: 100,
component: {
render: (h) => h(DatePicker),
},
});
export default {
data() {
return {
graph: null,
};
},
mounted() {
this.init();
},
methods: {
addElButtonNode() {
this.graph.addNode({
x: 40,
y: 40,
width: 100,
height: 40,
shape: "el-button",
});
},
addELDatePickerNode() {
this.graph.addNode({
x: 40,
y: 40,
width: 100,
height: 40,
shape: "el-date-picker",
});
},
addHTMLNode() {
const source = this.graph.addNode({
x: 40,
y: 40,
width: 100,
height: 40,
shape: "html",
html() {
const wrap = document.createElement("div");
wrap.style.width = "100%";
wrap.style.height = "100%";
wrap.style.background = "#008c8c";
wrap.style.display = "flex";
wrap.style.justifyContent = "center";
wrap.style.alignItems = "center";
wrap.innerText = "html节点";
return wrap;
},
});
},
download() {
this.graph.toSVG((dataUri) => {
DataUri.downloadDataUri(DataUri.svgToDataUrl(dataUri), "chart.svg");
});
},
init() {
const data = {
// 节点
nodes: [
{
id: "node1", // String,可选,节点的唯一标识
x: 40, // Number,必选,节点位置的 x 值
y: 40, // Number,必选,节点位置的 y 值
width: 80, // Number,可选,节点大小的 width 值
height: 40, // Number,可选,节点大小的 height 值
label: "hello", // String,节点标签
},
{
id: "node2", // String,节点的唯一标识
x: 160, // Number,必选,节点位置的 x 值
y: 180, // Number,必选,节点位置的 y 值
width: 80, // Number,可选,节点大小的 width 值
height: 40, // Number,可选,节点大小的 height 值
label: "world", // String,节点标签
},
],
// 边
edges: [
{
source: "node1", // String,必须,起始节点 id
target: "node2", // String,必须,目标节点 id
},
],
};
this.graph = new Graph({
container: document.querySelector(".container"),
history: true,
selecting: {
enabled: true,
rubberband: true, // 启用框选
className: "my-selecting",
},
panning: {
// enabled: true,
},
scroller: {
enabled: true,
},
minimap: {
enabled: true,
container: this.$refs.containerMiniMap,
},
background: {
color: "#fffbe6", // 设置画布背景颜色
},
grid: {
size: 10, // 网格大小 10px
visible: true, // 渲染网格背景
},
});
this.graph.fromJSON(data);
},
},
};
</script>
<style >
.container {
width: 80% !important;
min-height: 500px !important;
}
.container-mini-map {
width: 300px;
height: 300px;
border: 1px solid red;
}
.my-selecting {
border: 1px solid red;
}
</style>
- ./component/Button.vue
<template>
<div>
<el-button type="primary" @click="handlePrimaryClick">按钮</el-button>
</div>
</template>
<script>
export default {
data() {
return {
value: "",
};
},
components: {},
methods: {
handlePrimaryClick() {
console.log("primary-click");
},
},
};
</script>
<style lang='less'>
</style>
- ./component/DatePicker.vue
<template>
<div>
<el-date-picker
type="date"
v-model="value"
placeholder="请输入"
></el-date-picker>
</div>
</template>
<script>
export default {
data() {
return {
value: "",
};
},
components: {},
methods: {
handlePrimaryClick() {
console.log("primary-click");
},
},
};
</script>
<style lang='less'>
</style>
- main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
- package.json 注意对应包的版本要保持一致
{
"name": "vue2-project-test",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"@antv/x6": "1.12.14",
"@antv/x6-vue-shape": "1.1.4",
"element-ui": "2.15.0",
"core-js": "^3.8.3",
"vue": "^2.6.14",
"vue-grid-layout": "^2.4.0",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"less": "^4.0.0",
"less-loader": "^8.0.0",
"vue-template-compiler": "^2.6.14"
}
}
最终效果
转载自:https://juejin.cn/post/7246657502842863677