Use antv/X6 to realize the flow of line animation and quickly build initial practice records such as flow chart and DAG chart


Recently, we need to display the deep learning network structure diagram on the front end in a more intuitive form. For data transmission, we plan to use the form of data path flow, because I haven't learned much about the front end. I feel that there will be many problems after I write js and css code. The beauty of the front end display and adaptive window size, The adaptation of component location is a problem. After searching the relevant tutorial recommendations, I found that the antv/X6 plug-in developed by Ali is used to make flow charts and network structure diagrams, which still has good results. Here are some of my learning operations according to the tutorial:

Start using

Next, let's create the simplest start -- > end application.

Step 1 create container

Create a container in the page to hold X6 drawings, which can be a div tag.

<html>
<head>
    <style type="text/css">
        .expa {
            width: 400px;
            height: 400px;
            //Show border
            border: 3px solid #F00;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    <div class="expa" id="container"></div>
</body>
</html>

Step 2 prepare data

X6 supports JSON format data. The object needs to have node nodes and edge edges fields, which are represented by arrays respectively:

<script>
	const data = {
            // node
        nodes: [
            {
                id: 'node1', // String, optional, unique identifier of the node
                x: 100, // Number, required, the x value of the node position
                y: 100, // Number, required, y value of node position
                width: 80, // Number, optional, the width value of the node size
                height: 40, // Number, optional, height value of node size
                label: 'start', // String, node label
        	},
        	{
                id: 'node2', // String, the unique identifier of the node
                x: 200, // Number, required, the x value of the node position
                y: 200, // Number, required, y value of node position
                width: 80, // Number, optional, the width value of the node size
                height: 40, // Number, optional, height value of node size
                label: 'end', // String, node label
             },
        ],
        // edge
        edges: [{
            source: 'node1', // String, required, starting node id
            target: 'node2', // String, required, target node id
        }, ],
    };
</script>

Step 3 render canvas

First, we need to create a Graph object and assign it a drawing container on the page, usually specifying the size of the canvas. I have specified the size of the container before, so I don't need to specify it again

//Use npm to install x6, and then refer to the following form, which can be used in vue
import { Graph } from '@antv/x6';
const graph = new Graph({
  container: document.getElementById('container'),
  //width: 800,
  //height: 600,
});

I use the introduction form of js file, which is relatively easy to operate on html pages

<script src="https://unpkg.com/@antv/x6/dist/x6.js"></script>
<script>
  const graph = new X6.Graph({
    container: document.getElementById('container'),
    //width: 800,
    //height: 600,
  });
</script>

Then, we can use the graph we just created to render our nodes and edges.

graph.fromJSON(data)

Get the following figure:

Cancel the movement of nodes

At this time, the node can be moved. Sometimes we don't want it to move. We can use the following code:

const graph = new X6.Graph({
    container: document.getElementById('container'),
    // width: 400,
    // height: 400,
    interacting: {
    	nodeMovable: false,
    }
});

Render nodes using different shapes

In the above example, we used the default graph rect to render nodes. In addition, we also built circle, ellipse, polygon and so on in X6 Basic graphics , you can specify the rendered shape for the node through the shape attribute. If you are not familiar with SVG graphics, you can refer to SVG image tutorial

const data = {
            // node
            nodes: [{
                    id: 'node1', // String, optional, unique identifier of the node
                    x: 100, // Number, required, the x value of the node position
                    y: 100, // Number, required, y value of node position
                    width: 80, // Number, optional, the width value of the node size
                    height: 40, // Number, optional, height value of node size
                    label: 'start', // String, node label
                },
                {
                    id: 'node2', // String, the unique identifier of the node
                    shape:'ellipse',
                    x: 200, // Number, required, the x value of the node position
                    y: 200, // Number, required, y value of node position
                    width: 80, // Number, optional, the width value of the node size
                    height: 40, // Number, optional, height value of node size
                    label: 'end', // Node, label, String
                },
            ],
            // edge
            edges: [{
                source: 'node1', // String, required, starting node id
                target: 'node2', // String, required, target node id
            }, ],
        };

The effect is as follows:

Center and zoom canvas

When the factor is positive, it means that the canvas is enlarged, and when the factor is negative, it means that the canvas is reduced.

Here, the factor value is 0.8 and the canvas is enlarged

graph.centerContent() //Center canvas
graph.zoom(0.8)//Canvas zoom

Modify edge style

Change edge to dashed line:

edges: [{
    source: 'node1', // String, required, starting node id
    target: 'node2', // String, required, target node id
    attrs: {
        line: {
            stroke: '#1890ff',
            strokeDasharray: 5,
            targetMarker: 'classic',
    	}
    },
 }, ],

Add flow effect to dotted line

In order to add flow effect to the dotted line, I'm steaming hard. The official tutorial gives ts code. There are always problems in using it. Alas, it's still my own dish, and it's not a rookie. You should learn more!

Use style style to realize the flow effect of lines

edges: [{
        source: 'node1', // String, required, starting node id
        target: 'node2', // String, required, target node id
        attrs: {
            line: {
                stroke: '#1890ff',
                strokeDasharray: 5,
                targetMarker: 'classic',
                style: {
                	animation: 'ant-line 30s infinite linear',
                },
            }
        },
}, ],
<style>
  @keyframes ant-line {
    to {
      stroke-dashoffset: -1000
    }
  }
</style>

The code effect is shown in the figure below:

Modify the attributes of nodes and edges

//Get all the nodes and edges of the canvas
const nodes = graph.getNodes()
const edges = graph.getEdges()
//Modify the properties of no node
nodes.forEach((node) => {
    node.attr(
            'body', 
            {
                stroke: '#1890ff ', / / node color
                fill: 'white'//Node fill color
    		}
   	)
    node.attr('label', {
            // text: 'rect', / / text
            // fill: '#333', / / text color
            // fontSize: 13, / / text size
    	})
    node.resize(40, 20) //Reset node size
})
edges.forEach((edge) => {
    edge.attr('line', {
        stroke: '#1890ff ', / / edge color
        strokeDasharray: 5,//Edge line thickness
        targetMarker: 'classic',
        style: {
        	animation: 'ant-line 30s infinite linear',
        },
    })
})

The modified effect drawing is as follows:

Mouse hover highlight

graph.on('node:mouseenter', 
	({node}) => {
        node.attr('body', {
        stroke: 'orange',
        fill: 'orange'
    })
})

The effect is as follows:

The complete code is as follows:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Network visualization</title>
    <meta name="keywords" content="HTML,CSS,XML,JavaScript">
    <meta name="author" content="anliu">
    <meta http-equiv="refresh" content="60">
    <!-- <script src="./x6.js"></script> -->
    <script src="https://unpkg.com/@antv/x6/dist/x6.js"></script>
    <style type="text/css">
        .expa {
            width: 400px;
            height: 400px;
            border: 3px solid #F00;
            margin: 0 auto;
        }

        @keyframes ant-line {
            to {
                stroke-dashoffset: -1000
            }
        }
    </style>
</head>

<body>
    <div class="expa" id="container"></div>
    <script>
        const data = {
            // node
            nodes: [{
                    id: 'node1', // String, optional, unique identifier of the node
                    x: 100, // Number, required, the x value of the node position
                    y: 100, // Number, required, y value of node position
                    width: 80, // Number, optional, the width value of the node size
                    height: 40, // Number, optional, height value of node size
                    label: 'start', // String, node label
                },
                {
                    id: 'node2', // String, the unique identifier of the node
                    shape: 'ellipse',
                    x: 200, // Number, required, the x value of the node position
                    y: 200, // Number, required, y value of node position
                    width: 80, // Number, optional, the width value of the node size
                    height: 40, // Number, optional, height value of node size
                    label: 'end', // String, node label
                },
            ],
            // edge
            edges: [{
                source: 'node1', // String, required, starting node id
                target: 'node2', // String, required, target node id
                attrs: {
                    line: {
                        stroke: '#1890ff',
                        strokeDasharray: 5,
                        targetMarker: 'classic',
                        style: {
                            animation: 'ant-line 30s infinite linear',
                        },
                    }
                },
            }, ],
        };
        const graph = new X6.Graph({
            container: document.getElementById('container'),
            // width: 400,
            // height: 400,
            interacting: {
                nodeMovable: false,
            }
        });

        graph.fromJSON(data)

        function reset() {
            const nodes = graph.getNodes()
            const edges = graph.getEdges()
            nodes.forEach((node) => {
                node.attr(
                    'body', {
                        stroke: '#1890ff',
                        fill: 'white'
                    })
                node.attr('label', {
                    // text: 'rect', / / text
                    // fill: '#333', / / text color
                    // fontSize: 13, / / text size
                })
                node.resize(40, 20)
            })
            edges.forEach((edge) => {
                edge.attr('line', {
                    stroke: '#1890ff',
                    strokeDasharray: 5,
                    targetMarker: 'classic',
                    style: {
                        animation: 'ant-line 30s infinite linear',
                    },
                })
            })
        }
        reset()
        graph.centerContent()
        graph.zoom(0.5)

        graph.on('node:mouseenter', ({
            node
        }) => {
            node.attr('body', {
                stroke: 'orange',
                fill: 'orange'
            })
        })
        graph.on('node:mouseleave', ({
            node
        }) => {
            reset()
        })
    </script>
</body>
</html>

If you plan to use the code in vue, you only need to modify a small number of code statements, which is very convenient!

Keywords: Javascript Vue html css canvas

Added by mkr on Wed, 09 Feb 2022 16:49:24 +0200