demand

Topology diagram is used to visually display the operating status and risk status of all kinds of assets (database devices, security devices, etc.), their connections, data interaction relationships, and their organizational relationships.

Implementation effect

IO/Alfredch3n /…

Introduction to GoJS

GoJS tutorial:

  1. GoJS official documentation (click to visit)

No matter what programming language, third-party libraries, frameworks, etc., the best and fastest way to learn is through the official standard introductory tutorial. Here are several columns that I often use in the official website and their corresponding functions when I study introductory knowledge. How to use GoJS to generate basic graphics

(2) GoJS case library, contains a variety of types of graphics, here to find and you want to generate graphics cases, the code down to modify is the fastest way to generate graphics

(3) Detailed explanation of all configurable item parameters in GoJS chart. If you need to find the corresponding configuration item property setting, you can find it here

(4) GoJS API lists all the implemented classes, as well as the description, attribute and method of the class. According to business requirements, the corresponding attribute and method can be found here for operation. For example, click on a Group node to collapse the elements in the Group, find the Group class, and then the collapseSubGraph method to see how to use the collapseSubGraph.

(five) make good use of the forum search function, some configuration parameters to find their own very troublesome and difficult, to believe that you have encountered the problem others have also encountered, directly in the official forum search function to search, is very convenient, as long as the keyword input is correct, The search results are satisfactory (the screenshot page is retraced from the Form TAB in the navigation bar of the official website)

  1. GoJS Super Detailed Introduction (click to visit)

GoJS tutorial Chinese translation version, at the same time the author also output their own understanding, detailed explanation of the use of GoJS and the basic principle. Here are some quotes from the article that I think are very good:

Remember that the GoJS namespace is go, and all GoJS types are in the go namespace. All GoJS classes such as Diagram, Node, Panel, Shape, and TextBlock are named GO. Is prefixed.

This article will give you an example of how to call Go.graphobject. make to create a GoJS object. For more details see Building Objects in GoJS, which is conveniently used as an abbreviation for go.graphobject.make. This is handy if you use an abbreviation for go.graphobject. make in your code. This is handy if you use an abbreviation for go.graphobject. make in your code. If your code represents another object, you can also choose another short variable, such as $$or MAKE or GO. Diagrams and models The nodes and links of a Diagram are visual data under model management. GoJS supports a model-view architecture when the model contains data (Javascript array objects) that describes nodes and links. And diagrams use views to represent nodes and linked objects in the data. We load, edit, and save models instead of diagrams. Instead of modifying the Diagram and GraphObject class prototypes, you add attributes to the model’s data objects that your APP needs.

The rest of this article assumes that you already know the basics of GoJS.

The data structure of the topology

In GoJS, once you bind a data that describes nodes and links to GoJS’s diagram Model, the diagram represents nodes and link objects in the data as views. So, as long as we build the chart data object in the specified format, we can let GoJS render the chart itself. Here is an example of a constructed chart data object:

// Topology data
var topoChartData = {
	// All node data
    "nodeDataArray": [{"key": "root".// The unique identifier of a node
            "category": "root".// Node type
			// Treat the node type as the attribute name, and the corresponding attribute value is some data unique to the node
            "root": {
                "name": "Root node".// Node unique data -- name}}],// All connection data
    "linkDataArray": [{"from": "52d59c8d-1f8b-4405-8036-dfe51e8419f1".// Connect the source node of the line
            "to": "node67".// Connect the target node of the line
            "category": "layerThreeLinkInfo".// Cable type}]};Copy the code

Once we have defined the data for the chart Model, we can use that data object as a basis to configure the chart parameters step by step to make the chart look like we want.

The specific implementation

Initialization chart

To initialize the chart, you need to specify a DOM element for mounting, and configure the basic parameters of the chart as required. The specific code is as follows:

let vm = this;
let dom = document.getElementById('topo-chart');
// Instantiate a GoJS diagram class and configure the basic parameters
vm.diagram = $(go.Diagram, dom,
    {
        layout: $(go.TreeLayout), // The main layout is a tree structure
        maxSelectionCount: 1.// A maximum of one node can be selected
        'toolManager.hoverDelay': 10.// Mouse hover prompt box displays the delay time
        // allowMove: false, // Dragging elements is not allowed
        allowClipboard: false.// Copy and paste is not allowed
        allowDelete: false.// Delete is not allowed
    });
Copy the code

Custom node template styles

This part is a relatively boring but time-consuming part of the development process. In order to configure the style of nodes in accordance with the UI diagram, a lot of debugging is needed to find the correct node template attribute configuration, and it is necessary to have a considerable understanding of the node attributes of various types.

This section lists only the node template that needs to be configured, the root node, and the configuration method. Other node templates have similar configuration methods.

First, add a custom template type using the nodeTemplatemap. add method. The first parameter matches and applies to nodes in the chart data object whose category value is ‘root’. The second argument, the $function go.graphobject. make, is used to generate all the node elements in the template. Go.graphobject. make is used to configure the node element style and bind the node name data in the graph data object using the go.binding method.

// Root node template (template is the API provided by Gojs to control the node display style)
// Using the add method to add a template matches the category attribute of the node data with the first parameter of the method. Only matched node templates take effect
vm.diagram.nodeTemplateMap.add('root', $(go.Node, 'Auto',
    { selectionAdorned: false,},// Image background
    $(go.Picture,
        {
            desiredSize: new go.Size(153.133),
            source: '/static/images/topo-manage/root-icon.svg',},),/ / text
    $(go.TextBlock,
        {
            margin: new go.Margin(0.0.10.0),
            stroke: '#fff'.width: 90.font: '14px Microsoft YaHei'.alignment: go.Spot.BottomCenter,
            textAlign: 'center'.maxLines: 2.overflow: go.TextBlock.OverflowEllipsis,
            toolTip: $('ToolTip',
                {
                    'Border.fill': '# 021026'.'Border.stroke': '#12409E'.'Border.parameter1': 4,
                },
                $(go.TextBlock,
                    { margin: 4.stroke: 'white',},new go.Binding('text'.' '.model= > model[model.category].name),
                ),
            ),
        },
        // Use the Binding method to bind the node data to an attribute of the node, where the text attribute is bound
        new go.Binding('text'.' '.model= > model[model.category].name),
    ),
));
Copy the code

Custom connector template styles

This section is similar to the node template style configuration above and will not be described in detail.

// Connect to the default template
vm.diagram.linkTemplate = $(go.Link,
    {
        selectable: false.routing: go.Link.Orthogonal,
    },
    $(go.Shape, { stroke: '#3386FF',}));Copy the code

Dynamic highlighting and display of connections

Dynamic display cables used GoJS API, probably operation logic goes like this: first to chart to add nodes selected to monitor events, if you click on a node, put all the hidden nodes to cancel the highlighting, line, and then according to click on the node, highlights the need to highlight the node, display need to display the connections.

// Add node to select listening events
this.diagram.addDiagramListener('ChangedSelection'.() = > {
    vm.updateHighlights();
});

// Draw the connected node styles and lines
updateHighlights() {
    let vm = this;
    // Get the selected node (the diagram is set to select at most one node, i.e. first() takes the node that is currently selected)
    let sel = vm.diagram.selection.first();
    if (sel === null) return false;
    // Set all nodes to unselected
    if (sel.data.category === 'devInfo' || sel.data.category === 'devNotConfigInfo' || sel.data.category === 'dbInfo') {
        vm.diagram.nodes.each(node= > {
            node.isHighlighted = false;
        });
        // Set the initial value of the power unit connection to hidden
        vm.diagram.links.each(link= > {
            if (link.data.category === 'devInfo' || link.data.category === 'devNotConfigInfo') {
                let shp1 = link.findObject('dev-link-shape');
                let shp2 = link.findObject('dev-link-toArrow');
                shp1.visible = false;
                shp2.visible = false; }}); }// Set the associated node and cable highlighting according to the selected node
    vm.showDevLink(sel);
    vm.highlightNode(sel);
},

/** * shows the hidden power unit connection line, x is the currently selected node *@param x* /
showDevLink(x) {
    if (x instanceof go.Node) {
        // Select the capability unit node
        if (x.data.category === 'devInfo' || x.data.category === 'devNotConfigInfo') {
            // All lines from this node are set to display
            x.findLinksOutOf().each(link= > {
                let shp1 = link.findObject('dev-link-shape');
                let shp2 = link.findObject('dev-link-toArrow');
                shp1.visible = true;
                shp2.visible = true;
            });
        }
        // Select the asset node
        if (x.data.category === 'dbInfo') {
            x.findLinksInto().each(link= > {
                // All lines pointing to the node are set to display
                let shp1 = link.findObject('dev-link-shape');
                let shp2 = link.findObject('dev-link-toArrow');
                shp1.visible = true;
                shp2.visible = true; }); }}},// Highlight the node background to which the selected node is connected
highlightNode(x) {
    if (x instanceof go.Node) {
        // Select the capability unit node
        if (x.data.category === 'devInfo' || x.data.category === 'devNotConfigInfo') {
            // All target nodes are set to highlight styles
            x.findNodesOutOf().each(node= > {
                node.isHighlighted = true;
            });
        }
        // Select the asset node
        if (x.data.category === 'dbInfo') {
            // All source nodes are set to highlight styles
            x.findNodesInto().each(node= > {
                node.isHighlighted = true; }); }}},Copy the code

Expand and collapse the Group node

Expand and collapse the Group node, also using GoJS API, through diagram.commandHandler method, first determine whether the node can expand and collapse, if so, CollapseSubGraph and expandSubGraph instructions in the method collapse the Group node.

/** * Expands/collapses the clicked secondary department node *@param E Input event, mouse or keyboard triggered *@param Obj The currently clicked node object *@param Type specifies the expansion/collapse operation */
clickDepartTwo(e, obj, type) {
    let group = obj.part;
    // Check whether the node is a Group node
    if (group instanceof go.Adornment) group = group.adornedPart;
    if(! (groupinstanceof go.Group)) return;

    // Check if there are layers
    let diagram = group.diagram;
    if (diagram === null) return;

    // Determine whether the node can collapse/expand
    let cmd = diagram.commandHandler; // Get the layer instruction
    if (group.isSubGraphExpanded) {
        if(! cmd.canCollapseSubGraph(group))return; // If the group cannot be closed, return
    } else {
        if(! cmd.canExpandSubGraph(group))return; // If group cannot be expanded, return
    }

    // If type is specified, expansion/collapse is determined by type and the current expansion state of the node
    if (type) {
        if (type === 'collapse' && group.isSubGraphExpanded) {
            cmd.collapseSubGraph(group); Pack up / /
        } else if (type === 'expand' && !group.isSubGraphExpanded) {
            cmd.expandSubGraph(group); / /}}else { // If type is not specified, expansion/collapse is determined by the current expansion state of the node
        if (group.isSubGraphExpanded) {
            cmd.collapseSubGraph(group); Pack up / /
        } else {
            cmd.expandSubGraph(group); / /}}},Copy the code

Binding diagram Model

After the above configuration, the custom style and behavior of the chart is complete. The last step is to bind the chart data object to the chart Model and you are done!

// Update topology data
updateModel: function (val) {
    let vm = this;
    // Gojs official website binding model sample code
    if (val instanceof go.Model) {
        // If val is passed in as the go.Model class, you can bind directly to Model
        vm.diagram.model = val;
    } else {
        // Build a Model object to which the topology data is bound
        let m = new go.GraphLinksModel();
        if (val) {
            for (let p in val) {
                if(val.hasOwnProperty(p)) { m[p] = val[p]; }}}// Bind to modelvm.diagram.model = m; }},Copy the code

conclusion

In this paper, GoJS is used to realize topology graph requirements. After learning the introductory knowledge of GoJS, the graph data object is constructed according to the requirements, the template styles of various nodes and connecting lines are configured, and the method of dynamically highlighting nodes and displaying connecting lines and expanding and shutting down Group nodes is realized. Finally, the graph data object is bound to the graph Model to realize the topology function.

The requirements and assumptions for topology diagrams were very complex and ambitious, not only to present complex data, but also to change the connections, dependencies, and other relationships between nodes in a drag-and-drop manner, just like network topologies. The current version of the topology, only the realization of the data visual, and did not achieve drag save function. If you want to continue to develop, in fact, GoJS is completely possible to implement, the website itself has topology related examples, as long as you master the relevant API interface, can implement.