记一期@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>
<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>
<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>
<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>
<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>
<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>
<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')
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')
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"
}
}
{
  "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"
  }
}
{ "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" } }

最终效果

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYEU35iS' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片