Recently, the company needed to make a flow chart. After looking at antv/X6, I felt it was very appropriate, so I studied it for half a month. There is no information on the Internet, and I'm afraid I'll forget. I'll record some events and methods I use, so that I can check them later.
1: The most important thing to implement the flow chart is the canvas. There are documents on the official website, which can easily implement the canvas. Let's take a look at the canvas code I wrote with VUE.
First, the most important thing is to download dependencies. If x6 is downloaded in vue, you need to download two dependencies;
npm install @antv/x6 --save npm install @antv/x6-vue-shape Download these two dependencies and you can vue Used in X6 Yes First, introduce dependencies in the page import "@antv/x6-vue-shape"; import { Graph } from '@antv/x6'; Let's start writing code
stay methods Define a initX6 Method, and then get mounted Call in initX6() { this.graph = new Graph({ container: document.getElementById("containerChart"), //This is the ID name that the canvas needs to be mounted width: 1000, //Canvas width height: 500, //Canvas height grid: this.grid, //The canvas style is defined in the modou layer and called with this autoResize: true, //Automatically change size with the window }); },
If you need to define the canvas background grid, you can define it yourself. The following is a background grid I defined myself. You can call it directly with this. Name after the grid.
data(){ return{ grid: { // grid settings size: 20, // Grid size 10px visible: true, // Render mesh background type: "mesh", args: { color: "#D0D0D0", thickness: 1, // Grid line width / grid point size factor: 10, }, }, } }
At this time, define a width and height for your mount container in css, and you can see a canvas on the page. Adjust his position and start writing nodes.
Create a new JS file to define nodes and write drag and drop code.
import '@antv/x6-vue-shape'; import { Addon} from '@antv/x6'; // Drag to generate quadrilateral export const startDragToGraph = (graph,type,e) =>{ const node = graph.createNode({ width: 100, //Width of node height: 60, //Height of node attrs: { label: { text: type, fill: '#000000', fontSize: 14, textWrap: { width: -10 , height: -10, ellipsis: true, }, }, body: { stroke: '#000000', strokeWidth: 1, fill: '#ffffff', } }, ports: ports }) const dnd = new Addon.Dnd({target:graph}) dnd.start(node,e) } //The following is the code of the anchor point. Just know, I won't write them one by one. const ports = { groups: { // Enter linked pile group definition top: { position: 'top', attrs: { circle: { r: 4, magnet: true, stroke: '#2D8CF0', strokeWidth: 2, fill: '#fff', }, }, }, // Output link pile group definition bottom: { position: 'bottom', attrs: { circle: { r: 4, magnet: true, stroke: '#2D8CF0', strokeWidth: 2, fill: '#fff', }, }, }, left: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#2D8CF0', strokeWidth: 2, fill: '#fff', }, }, }, right: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#2D8CF0', strokeWidth: 2, fill: '#fff', }, }, }, }, items: [ { id: 'port1', group: 'top', }, { id: 'port2', group: 'bottom', }, { id: 'port3', group: 'left', }, { id: 'port4', group: 'right', } ], }
After defining the nodes and anchors, return to the vue page and import the JS file
import { startDragToGraph } from "../methods.js"; //Import the defined JS file go HTML Add manually dragged node content to the layer. <template> <div class="warp"> <div id="containerchart"></div> <div v-for="(item, index) in List" :key="index" class="btn" :title="item" @mousedown="startDrag(item, $event)" > <span> {{ item }} </span> </div> </div> </template> //The list of loops is written by yourself data() { return { List: ["Built in node"], grid: { // grid settings size: 20, // Grid size 10px visible: true, // Render mesh background type: "mesh", args: { color: "#D0D0D0", thickness: 1, // Grid line width / grid point size factor: 10, }, }, }; }, Then in methods Define the method in the type Spread js In the file. startDrag(type, e) { startDragToGraph(this.graph, type, e); },
After completing the above, you can get the following effects. Drag the node from the right to the canvas to display it.
But now there are still problems with dragging and lines. Next, solve the connection problem.
data() { return { List: ["Built in node"], grid: { // grid settings size: 20, // Grid size 10px visible: true, // Render mesh background type: "mesh", args: { color: "#D0D0D0", thickness: 1, // Grid line width / grid point size factor: 10, }, }, connectEdgeType: { //Connection mode connector: "normal", router: { name: "", }, }, //First, define the following three contents in data, which need to be used below graph: "", type: "grid", selectCell: "", }; }, //Then add the following methods to the initX6 method in methods connecting: { // Node connection anchor: "center", connectionPoint: "anchor", allowBlank: false, snap: true, }, createEdge() { return new Shape.Edge({ attrs: { line: { stroke: "#1890ff", strokeWidth: 1, targetMarker: { name: "classic", size: 8, }, strokeDasharray: 0, //Dotted line style: { animation: "ant-line 30s infinite linear", }, }, }, label: { text: "", }, connector: _that.connectEdgeType.connector, router: { name: _that.connectEdgeType.router.name || "", }, zIndex: 0, }); }, //Note that these two methods are written to the Graph instance of new. //Then write a drag event to the node. This method is written to the initX6 method, outside the Graph instance of new. this.graph.on("selection:changed", (args) => { args.added.forEach((cell) => { this.selectCell = cell; if (cell.isEdge()) { cell.isEdge() && cell.attr("line/strokeDasharray", 5); //Dotted ant line cell.addTools([ { name: "vertices", args: { padding: 4, attrs: { strokeWidth: 0.1, stroke: "#2d8cf0", fill: "#ffffff", }, }, }, ]); } }); args.removed.forEach((cell) => { cell.isEdge() && cell.attr("line/strokeDasharray", 0); //normal line cell.removeTools(); }); });
Now you can see that the anchor point on the built-in node on the canvas is always displayed. Let's deal with it.
//You need to add a method to the introduced X6 method first import { Graph,FunctionExt } from "@antv/x6"; stay methods Define a traversal method in and call it when the mouse moves in and out.. showPorts(ports, show) { for (let i = 0, len = ports.length; i < len; i = i + 1) { ports[i].style.visibility = show ? "visible" : "hidden"; } }, Then give it in the method this.garph.on()Add two mouse in and out events. Move in to make the anchor visible and move out to make the anchor hidden. This will make the nodes of the canvas look better. //Mouse in this.graph.on( "node:mouseenter", FunctionExt.debounce(() => { const container = document.getElementById("containerchart"); const ports = container.querySelectorAll(".x6-port-body"); this.showPorts(ports, true); }), 500 ); //Mouse out this.graph.on("node:mouseleave", () => { const container = document.getElementById("containerchart"); const ports = container.querySelectorAll(".x6-port-body"); this.showPorts(ports, false); });
Here's all the code
<template> <div class="container_warp"> <div id="containerChart"></div> <div v-for="(item, index) in List" :key="index" class="btn" :title="item" @mousedown="startDrag(item, $event)" > <span> {{ item }} </span> </div> </div> </template> <script> import "@antv/x6-vue-shape"; import { Graph, Shape, FunctionExt } from "@antv/x6"; import { startDragToGraph } from "../methods.js"; export default { data() { return { List: [ "Directory listening", "data organization ", "Image Publishing", "object detection ", "change detection ", "Feature classification", "Expert pending trial", "Sample warehousing", "Image storage", "Target warehousing", "Sheet finishing", "Package download", ], graph: "", type: "grid", selectCell: "", connectEdgeType: { //Connection mode connector: "normal", router: { name: "", }, }, grid: { // grid settings size: 20, // Grid size 10px visible: true, // Render mesh background type: "mesh", args: { color: "#D0D0D0", thickness: 1, // Grid line width / grid point size factor: 10, }, }, }; }, methods: { initX6() { this.graph = new Graph({ container: document.getElementById("containerChart"), width: 1000, height: 500, grid: this.grid, connecting: { // Node connection anchor: "center", connectionPoint: "anchor", allowBlank: false, snap: true, }, createEdge() { return new Shape.Edge({ attrs: { line: { stroke: "#1890ff", strokeWidth: 1, targetMarker: { name: "classic", size: 8, }, strokeDasharray: 0, //Dotted line style: { animation: "ant-line 30s infinite linear", }, }, }, label: { text: "", }, connector: _that.connectEdgeType.connector, router: { name: _that.connectEdgeType.router.name || "", }, zIndex: 0, }); }, }); // Move the mouse in and out of the node this.graph.on( "node:mouseenter", FunctionExt.debounce(() => { const container = document.getElementById("containerChart"); const ports = container.querySelectorAll(".x6-port-body"); this.showPorts(ports, true); }), 500 ); this.graph.on("node:mouseleave", () => { const container = document.getElementById("containerChart"); const ports = container.querySelectorAll(".x6-port-body"); this.showPorts(ports, false); }); this.graph.on("selection:changed", (args) => { args.added.forEach((cell) => { this.selectCell = cell; if (cell.isEdge()) { cell.isEdge() && cell.attr("line/strokeDasharray", 5); //Dotted ant line cell.addTools([ { name: "vertices", args: { padding: 4, attrs: { strokeWidth: 0.1, stroke: "#2d8cf0", fill: "#ffffff", }, }, }, ]); } }); args.removed.forEach((cell) => { cell.isEdge() && cell.attr("line/strokeDasharray", 0); //normal line cell.removeTools(); }); }); }, showPorts(ports, show) { for (let i = 0, len = ports.length; i < len; i = i + 1) { ports[i].style.visibility = show ? "visible" : "hidden"; } }, // Drag to generate a square or circle startDrag(type, e) { console.log(type, e); console.log(this.graph); startDragToGraph(this.graph, type, e); }, }, mounted() { this.initX6(); }, }; </script> <style lang="less"> #containerChart { width: 1000px; height: 500px; border: 1px solid red; float: left; } .btn { width: 400px; float: right; margin-right: 500px; } </style>
This completes an X6 that manually generates nodes to the canvas What's left is some CSS problems. Here are a few X6 events. Convenient for later use or reference
this.garph.on('node:click',()=>{ //This is the click node event }) this.graph.on("blank:click", () => { //This is the background event of clicking on the canvas }); this.graph.on("cell:click", () => { //This is a click on the connector event }); // Delete node deleteNode() { const cell = this.graph.getSelectedCells(); this.graph.removeCells(cell); this.type = "grid"; }, //Empty canvas deleteAll() { this.graph.clearCells(); }, //Destroy canvas GraphDelete() { this.graph.dispose(); }, // Save png saveToPNG() { //Save the picture below this.$nextTick(() => { this.graph.toPNG( (dataUri) => { console.log(dataUri); // download DataUri.downloadDataUri(dataUri, "Asset topology.png"); }, { backgroundColor: "white", padding: { top: 50, right: 50, bottom: 50, left: 50, }, quality: 1, copyStyles: false, } ); }); }, this.graph.toJSON()Get all the contents of the node in the current canvas JSON.stringify(this.graph.toJSON())You can convert all the node contents of the current canvas into JSON String save to local or background JSON.parse(json); hold json The data is shaped into a data format and then passed fromJSON Method is then rendered onto the canvas. this.graph.fromJSON(json); You can get it from the background or locally json The data is shaped and rendered on the canvas.
The following is some personal experience. Due to the limited information on the Internet, record it for easy reference in the future. Don't spray it if it's not well written. If you have any questions, you can also leave a message to me.