introduce

AntV G6 is an out-of-the-box visualization engine, and its high customization ability made me choose antV G6 based on my customization requirements. Next, I will talk about my trip to step on pits. This article may require a certain threshold, so IT is recommended to read it after learning the Graph corresponding to G6 and relevant documents of custom nodes. Without further ado, let’s take a look at Dagre flowcharts.

  • The language is Vue2.0+ Element +G6

Environment set up

  • The installation

    npm install –save @antv/g6

  • The introduction of

    import G6 from ‘@antv/g6’;

demand

G6 User-defined node

// Instantiate grid plugin const grid = new g6.grid () g6.registerNode ('card-node', {draw: function drawShape (cfg, group) { const r = 2 const strokeColor = '#DCDEE2' const color = '#0090FF' const w = cfg.size[0] const h = cfg.size[1] Let shape = null / / the end of the if (CFG) label = = = 'start' | | CFG. Label = = = 'end') {shape = group. AddShape (' the rect, {attrs: {x: -w / 2, y: -h / 2, width: w / 2, height: h, stroke: strokeColor, radius: r, fill: '#fff', cursor: 'pointer' }, name: 'main-box', draggable: true }) group.addShape('text', { attrs: { textBaseline: 'top', x: -w / 2 + 25, y: -h / 2 + 28, fontSize: 20, lineHeight: h, text: cfg.label, fill: '#0090FF', cursor: 'pointer' }, name: 'title' }) } else { shape = group.addShape('rect', { attrs: { x: -w / 2, y: -h / 2, width: w, // 200, height: h, // 60 stroke: strokeColor, radius: r, fill: '#fff' }, name: 'main-box', draggable: true }) group.addShape('rect', { attrs: { x: -w / 2, y: -h / 2, width: w, // 200, height: h / 2 - 6, // 60 fill: color, radius: [r, r, 0, 0] }, name: 'title-box', draggable: true }) // title text group.addShape('text', { attrs: { textBaseline: 'top', x: -w / 2 + 20, y: -h / 2 + 8, fontSize: 18, text: cfg.label, fill: '#fff' }, name: 'title' }) group.addShape('text', { attrs: { textBaseline: 'top', x: -w / 2 + 20, y: -h / 2 + 40, fontSize: 17, lineHeight: 20, text: cfg.description, fill: 'rgba(0,0,0, 1)'}, name: 'description'})} return shape}, getAnchorPoints () {return [[0, 0.5], [1, 0.5]]}, setState (name, value, item) { if (name === 'active') { console.log('setState -> value', value) const marker = item.get('group').find(ele => ele.get('name') === 'main-box') if (value) { that.chooseNode = item.get('model') marker.attr('stroke', 'red') } else { marker.attr('stroke', '#DCDEE2') that.chooseNode = {} } } } })Copy the code

Custom behavior

G6. RegisterBehavior ('activate-node', {getDefaultCfg () {return {multiple: true } }, getEvents () { return { 'node:click': 'onNodeClick', 'canvas:click': 'onCanvasClick' } }, removeNodesState () { graph.findAllByState('node', 'active').forEach(node => { graph.setItemState(node, 'active', false) // const marker = node.get('group').find(ele => ele.get('name') === 'main-box') // marker.attr('stroke', '#DCDEE2') }) }, onNodeClick (e) { console.log('onNodeClick -> e', e) const graph = this.graph const item = e.item console.log('onNodeClick -> item', If (item.hasState('active')) {// graph.setitemState (item, 'active', False) // return //} // if multiple 'active' is not allowed, This.removenodesstate () // Set 'active' to true graph.setitemState (item, 'active', true) const tapList = ['main-box', 'title-box', 'title', 'description'] const name = e.target.get('name') if (taplist.indexof (name) > -1) {// Click card-node console.log(' click card-node') // const marker = item.get('group').find(ele => ele.get('name') === 'main-box') // marker.attr('stroke', Select node // const id = item.get('id') // that.choosenode = item.get('model')}}, OnCanvasClick (e) {// shouldUpdate can be overridden by the user, return true to cancel the 'active' state of all nodes, If (this.shouldupDate (e)) {this.removenodesState ()}})Copy the code

Configure cables between nodes

G6.registerEdge( 'line-arrow', { getPath (points) { const startPoint = points[0] const endPoint = points[1] const leftPointX = startPoint.x + 25 return  [ ['M', startPoint.x, startPoint.y], ['L', leftPointX, startPoint.y], ['L', leftPointX, endPoint.y], ['L', endPoint.x, endPoint.y] ] }, getShapeStyle (cfg) { const startPoint = cfg.startPoint const endPoint = cfg.endPoint const controlPoints = this.getControlPoints(cfg) let points = [startPoint] // the start point // the control points if (controlPoints) { points = points.concat(controlPoints) } // the end point points.push(endPoint) const path = this.getPath(points) const style = Object.assign( {}, G6.Global.defaultEdge.style, { stroke: '#B0B6B8', lineWidth: 4, path }, cfg.style ) return style } }, 'line' )Copy the code

Look at the picture first

All processes share the same beginning and end, and a “rule” is generated for each node added. There is operation logic of “and” and “deletion” between nodes. (The actual business scenario has “no” logic, just add the identifier)

Simulated data

// Simulate data lineData: {nodes: [{ID: '0', label: 'start ', description: 'description'}, {id: '9', label:' end ', description: 'description' } ], edges: [ { source: '0', target: '9' } ] }Copy the code
  • Demand for resolution
  1. From the node view, the “and” rule adds A node after the node ** (for example, node A corresponds to rule A) **. From the perspective of rule group, in fact, A rule is inserted into the rule chain where rule A is located. Each rule chain presents A ‘and’ relationship with each other, and the rule chains form A ‘or’ relationship with each other.
  2. ‘or’ rule, that is, add A rule to all rules **(excluding rule A)** in front of the rule chain following rule A and connect to the end; From the view layer, the new rule node has an ‘and’ relationship with rule A.
  3. “Delete” operation, delete is different from the traditional sense of delete, can be adjusted according to the application scenario. The deletion operation here refers to the deletion of a rule node in the rule chain, but does not affect the whole rule, which can be understood asslice(index,1), unless only ‘Start’ and ‘end’ are left in the rule chain after deleting the rule, delete the rule chain.

Business code, in git repository, need to fetch. (The business code is a little rough, you show mercy)

The point that

  • For highlighting selected nodes, we use graph.setitemState (item,name, value) to customize the removeNodesState() method to remove the highlighting of other selected nodes when clicking on a rule node.

  • The custom node uses getAnchorPoints() method to control the inflection point of the connection line, and you can configure parameters for debugging.

    GetAnchorPoints () {return [[0, 0.5], [1, 0.5]]}.Copy the code
  • Customize the setState method in the node to control the processing logic after the node is selected.

Have any problem, can pass private letter, the way that leave a message tells me, welcome everybody big guy points out a problem, thank!

Git warehouse address

https://github.com/lsCloud109/vue-antv-g6-lineArrow
Copy the code