preface

Telecom network topology practicality is very strong indeed, a recent project is based on this, in order to write a little rich, also with the automatic layout has part and but this Demo is really very attentively, a little change can be directly applied to the project, also can undertake data interaction, anyhow hope can help to you.

rendering

The topology

As you can see from the above illustration, the whole page is divided into three parts: graphView topological part on the left, tableView table part on the lower right, and propertyView property part on the upper right. Let’s break down the scene and then add concrete content to each part:

gv = new ht.graph.GraphView(); var tablePane = new ht.widget.TablePane(gv.dm()); // Form panel component propertyView = new hT.widget.propertyView (gv.dm())); //formPane is in the propertyView, so define var rightView = new hT.Widget. SplitView(propertyView, tablePane,'v', 0.4); Rightview.getview ().style.borderLeft = // Split components, v into upper and lower layers, with a ratio of 0.4:0.6'1px solid #000'; var borderPane = new ht.widget.BorderPane(); // BorderPane.setrightView (rightView, 400); // Set the right component of the borderPane to rightView with a width of 400 borderpane.setCenterView (gV); // Set the borderPane intermediate component to gv Borderpane.addTodom (); // Add the borderPane component to the bodyCopy the code

SplitView SplitView SplitView SplitView SplitView SplitView SplitView SplitView SplitView SplitView SplitView SplitView The sub-components are absolutely positioned in position. The parameters in this component are (left component or upper component, right component or lower component, H represents left-right partition and V represents upper and lower partition. The default value of the partition position is 0.5. Greater than 1 represents the absolute width or height of the left component or upper component, less than 1 represents the absolute width or height of the right component or lower component); BorderPane is a layout container that can place sub-components in five areas: up, down, left, right and middle. Sub-components can be components provided by HT framework or native HTML components. Sub-components are absolutely positioned in position. Here I’ve combined SplitView and BorderPane to divide the scene into three sections. Finally, be sure to add the final layout container to the body or any HTML tag to display in the interface, where addToDOM is defined as follows:

addToDOM = function(){var self = this, view = self.getView(), // get the bottom div of this component; / / get the underlying div style style property for the document. The body. The appendChild (view); // Add the underlying div to the body. Left ='0'; //HT defines components to be absolute by default, so you need to set position style.right ='0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize'.function () { self.iv(); }, false);            
}
Copy the code

While HT components are typically embedded in containers such as BorderPane, SplitView, and TabView, the outermost HT components require the user to manually add the underlying div element returned by getView() to the DOM element of the page. When the parent container size changes, if the parent container is a predefined container component such as BorderPane and SplitView, the HT container automatically recursively calls the child component invalidate function to notify the update. However, if the parent container is a native HTML element, the HT component cannot know that it needs to be updated. Therefore, the outermost HT component usually needs to listen for the window size change event and call the invalidate function of the outermost component to update.

The scenario is created. To show the difference in attributes of different nodes, we added seven nodes to the topology:

function initModel(){
    var name = "Equipment"; var count = 0; var root = createNode(name + count++, name + (++count)); // Parameter 1 is name, parameter 2 is tag root.setimage ('./symbols/ computer/server.json ');
    root.setName('server');
    root.s('label.position', 3); gv.sm().ss(root); // The root node is selected by defaultfor(var i = 0; i < 2; i++) { var iNode = createNode(name + count++, name + (++count)); CreateEdge (root, iNode); createEdge(root, iNode);for(var j = 0; j < 2; j++) { var jNode = createNode(name + count++, name + (++count)); createEdge(iNode, jNode); }}}Copy the code

The createNode function is declared as follows:

functionCreateNode (name, tag){// createNode flag++; var node = new ht.Node(); node.setName(name); node.setTag(tag); node.setImage('./symbols/ computer /XX system.json ');
    node.a('hidden'.false); // Custom properties to control Node. a('hidden') to control the explicit node.a('Interface type'.'SATA');
    node.a('graphics'.'Nvidia');
    if(flag % 2 === 0){
        node.a('Interface type'.'IDE');
        node.a('graphics'.'ATI');
    }
    node.s('label.position'11); gv.dm().add(node); Node. tablePane1 = createTableView(serviceType, dataModel1); Node. tablePane2 = createTableView(serviceSize, dataModel2); node.tablePane3 = createTableView(version, dataModel3); node.formPane1 = createFormPane(node.tablePane1); // Create the forms panel node.formPane1.title ='type'; Node.formpane2 = createFormPane(node.tablepane2); node.formPane2.title ='memory';
    node.formPane3 = createFormPane(node.tablePane3);
    node.formPane3.title = 'model';

    if(flag % 3 === 0){
        node.formPane3.v('tag'.'Lenovo server X3650M5 8871');
    }else{
        node.formPane3.v('tag'.'Lenovo IBM X3250 5458I21');
    }
    node.a('model', node.formPane3.v('tag'));
    return node;
}
Copy the code

We control the hidden property of the node and use the setVisibleFunc function of the visual filter in the graphView to control the hidden property of the node:

gv.setVisibleFunc(function(data){
    if(data.a('hidden')) {return false;
    }
    return true;
});
Copy the code

Properties pane

With nodes, you naturally need to display properties, and add the following values in the tablePane tablePane to add seven properties:

function createProperty() {/ / create a properties propertyView. AddProperties ([{name:'name'AccessType the default value of accessType is null. If name is age, use getAge() andsetGet/Age (98)setOr is /setGetName () displayName:'name'// Set the display text value of the attribute name}, {name:'hidden',// Get the hidden property displayName:'Hide this node',
            accessType: 'attr'// If name is hidden, use getAttr('hidden') andsetAttr('hidden'.false) to access icon:'images/alert.gif'// Set the icon valueType displayed to the left of the property name:'boolean',// Used to prompt the component to provide a suitable renderer render Boolean type, displayed as a check box editable:true// Set the property to editable}, {name:'grade',
            displayName: 'type',
            accessType: 'attr',
            drawPropertyValue: function(g, property, value, rowIndex, x, y, w, h, data, view){// Custom property values render function var cb =function(v) {
                    data.a('grade', v);
                }
                return fillFormPane(data.formPane1, w, h, data.tablePane1, serviceType, cb);
            }
        },
        {
            name: 'number',
            displayName: 'memory',
            accessType: 'attr',
            drawPropertyValue: function(g, property, value, rowIndex, x, y, w, h, data, view){
                var cb = function(v) {
                    data.a('number', v);
                }
                return fillFormPane(data.formPane2, w, h, data.tablePane2, serviceSize, cb);
            }
        },
        {
            name: 'Interface type',
            accessType: 'attr',
            displayName: 'Interface type'
        },
        {
            name: 'graphics',
            accessType: 'attr',
            displayName: 'graphics'
        },
        {
            name: 'model',
            accessType: 'attr',
            displayName: 'model',}]); }Copy the code

The drawPropertyValue property of the third and fourth properties returns the fillFormPane function, which takes the following parameters: (Form component formP, form component width W, form component height H, button click in the form component tableP in the pop-up box, The cb function assigns the value returned by double-clicking on a row in the table component to the HT.Widget.textField text box in the form form.

The first parameter, formP, creates a form component. Creating a form component is to create a form component and add a text box and a button to the form component. This step is also fairly simple in HT:

functionCreateFormPane (tPane) {var formPane = new ht.widget.formpane (); formPane.setPadding(0); Var tField = new ht.widget.textField (); var tField = new ht.widget.textField (); // Create a textbox tfield.settext (' '); // The contents of the text box are empty tfield.setdisabled (true); Formpane.addrow ([// add a line to the form {id:'tag'Formpane.getitembyid (id); // Uniquely identifies attributes that can be added to the corresponding element of the item object: The tField// attribute values can be HTML native elements, self-drawn text information in FormPane, and HT built-in components such as Button, CheckBox, and ComboBox}. {button:{// After setting this property, HT will automatically build the hT.widget. button object based on the property value and store it on the element property.'... ',// Text content onClicked on the button:function(){// Button click eventfor(var i = 0; i < tPane.dm().size(); I ++){// Set tablePane to default to formPane var data = tpane.dm ().getDatas().get(I);if(data.a('value') === formPane.v('tag')){ tPane.sm().ss(data); }}returncreateDialog(tPane, formPane); // Create a dialog box with the contents of the table panel}}}], [0.5, 0.1]); // Sets the display ratio of the first and second elements in the table component. The table component has only two elements, a text box and a button, with ratios of 0.5 and 0.1, respectivelyreturn formPane;
}
Copy the code

The createDialog function is created using the setConfig(config) method to set the dialog’s title, size, and contents. I pass the tPane table component to createDialog as the contents of the dialog:

functionCreateDialog (tPane){// Create the popup dialog.setconfig ({title: gv.sm().ld().getName()+"The"+ formpane. title,// The dialog's title content: tPane, // Directly set the popup to the table pane width: 400,// Specify the dialog's width: 200, draggable:true,// Specify whether the dialog box can be dragged to adjust the position closable:true,// indicates whether to display the close button maximizable:true,// indicates whether the dialog box can be maximized:"wh"Buttons: [// Add two buttons {label:'cancel',
                action: function(){
                    dialog.hide()
                }
            },
            {
                label: 'sure',}}); dialog.show(); // Display dialog}Copy the code

Create a form component and add columns to the form component. The procedure is simple and the code is fairly simple:

functionCreateTableView (arr, dm){var tableView = new ht.widget.tableView (dm); Tableview. addColumns([// addColumns in batches using json array parameters {displayName:'ID'DrawCell: drawCell: drawCell: drawCell:function(g, data, selected, column, x, y, W, h, tableView){var id = tableView.getrowindex (data); Ht.default. drawText(g,'row' + (id + 1), null, null, x, y, w, h, 'center'); // Draw text parameters (g brush object, value text content, font text font, color text color, x start x, Y start Y, w draw width, H draw height, align text horizontal alignment, VAlign text vertical alignment)}}, {displayName:'Name',
            drawCell: function(g, data, selected, column, x, y, w, h, tableView){
                var id = tableView.getRowIndex(data);
                var info = arr[id];
                ht.Default.drawText(g, info, null, null, x, y, w, h, 'center'); }}]);return tableView;
}
Copy the code

Having explained the parameters in fillFormPane, let’s see how this function is defined, basically with the last step, click on the element in the tablePane table component and return that element to the textField text box in the formPane form component:

functionFillFormPane (formP, W, H, tableP, ARr, CB){// Formpane on the rightif(formP === undefined){
        return;
    }
    formP.setWidth(w);
    formP.setHeight(h);
    formP.setHGap(0);

    if(formP.v('tag') = = ='undefined' || formP.v('tag') = = =' ') {
        formP.v('tag', arr[0]);
    }

    tableP.onDataDoubleClicked = function(data){var v = arr[data.a()'index')];
        formP.v('tag', v); // Set the corresponding item element value according to id tosetShort for Value, the element with the id tag is the dialog.hide() text box;if(cb){cb(v); } // If cb is passed, set data.a('number')/data.a('helloName') is the value of the row in the table that was double-click, that is, assigned to the third and fourth attributes} tablep.ondataclicked =function(data){// Callback dialog.getConfig().buttons[1].action = when the row of data in the table component is clickedfunctionVar v = arr[data.a(){var v = arr[data.a();'index')];
            formP.v('tag', v);
            dialog.hide();
            if(cb){cb(v); }}};return formP.getView();
}
functionFillFormPane (formP, W, H, tableP, ARr, CB){// Formpane on the rightif(formP === undefined){
        return;
    }
    formP.setWidth(w);
    formP.setHeight(h);
    formP.setHGap(0);

    if(formP.v('tag') = = ='undefined' || formP.v('tag') = = =' ') {
        formP.v('tag', arr[0]);
    }

    tableP.onDataDoubleClicked = function(data){var v = arr[data.a()'index')];
        formP.v('tag', v); // Set the corresponding item element value according to id tosetShort for Value, the element with the id tag is the dialog.hide() text box;if(cb){cb(v); } // If cb is passed, set data.a('number')/data.a('helloName') is the value of the row in the table that was double-click, that is, assigned to the third and fourth attributes} tablep.ondataclicked =function(data){// Callback dialog.getConfig().buttons[1].action = when the row of data in the table component is clickedfunctionVar v = arr[data.a(){var v = arr[data.a();'index')];
            formP.v('tag', v);
            dialog.hide();
            if(cb){cb(v); }}};return formP.getView();
}
Copy the code

The display of the top right property bar ends here, and the table panel on the bottom right is created the same way, so you can read the code for yourself.

Automatic layout

Finally, let’s talk about the layout of the whole interface nodes. Autolayout automatic layout component in HT provides a variety of algorithms to automatically arrange node positions according to node and connection relations. Automatic layout is usually used in scenarios where there are many elements or complex connections and it is difficult to drag and drop them manually. I have presented each layout mode by button. Click the corresponding button, and the layout mode will be automatically arranged according to the arrangement mode set by the pressed button:

http://www.hightopo.com/demo/propertyEditor/index.html

First, create a new instance, pass in an object that needs to be automatically laid out, either DataModel, graphView, or graph3dView, and set the default layout:

autoLayout = new ht.layout.AutoLayout(gv);
setTimeout(function(){
    layout('towardsouth'.true); }, 200); // The default size of the node is used for automatic layout because images are not loaded.Copy the code

Then CREATE the formPane form panel, add it to the body, and place it in the upper left corner of the body. Instead of pasting all the code out, I’ll just display the first layout button:

function createDirectionForm(){ var form = new ht.widget.FormPane(); form.setWidth(200); // Set the width of the form.setheight (80); document.body.appendChild(form.getView()); form.getView().style.background ='#fff';
    form.getView().style.boxShadow = '4px 16px 16px rgba(0, 0, 0, 0.1); // Set the shadow style form.addrow ([// this line is separate, as the title {element:'Automatic Layout :',// Display text}], [0.1]); Form. addRow([{button: {icon:'Layout/South layout. Json',
                onClicked: function(){
                    layout('towardsouth'.true);
                },
                background: null,
                labelColor: '#fff',
                groupId: 'btn',
                toolTip: 'South facing layout', borderColor: null } }, //.... Next, add the remaining 6 button], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]); // If there are seven objects in the array, set the width of the seven objectsreturn form;
}
Copy the code

The more interesting part is these, thank you for reading, if there are some places I explain not clear enough, you can send me a private letter, we discuss together.