HTML 5 3D "elastic" layout based on WebGL

Keywords: Front-end Attribute network JSON

Molecular force, also known as intermolecular force and van der Waals force, refers to the interaction between molecules. When the two molecules are far away from each other, they are mainly attractive. This force mainly comes from the interaction caused by the polarization of one molecule by the electric dipole moment of another molecule which changes rapidly with time. When the two molecules are very close, the repulsion force becomes the main one, which is the repulsion caused by the overlapping of the outer electron clouds of each molecule.

HT for Web provides the function of elastic layout (also known as force oriented layout), that is, according to the existence of mutual exclusion between nodes, there is gravity between the nodes connected with each other, after the elastic layout runs for a period of time, the overall topology network structure will gradually reach a convergence and stable balance state. This function is very interesting. Today we will show its charm.

Address: http://www.hightopo.com/demo/...

To use the elastic layout function, we need to introduce a ht-forcelayout.js elastic layout plug-in library after introducing the ht.js core library. Because form forms are also used, we need to introduce the ht-form.js form plug-in library:

<script src="../../guide/lib/core/ht.js"></script>
<script src="../../guide/lib/plugin/ht-forcelayout.js"></script>
<script src="../../guide/lib/plugin/ht-form.js"></script>

The ht.layout.Force3dLayout class provides 3D elastic layout. The constructor can pass in two parameters: DataModel and Graph3dView. By default, only unselected elements are laid out. If the constructor parameter is Graph3dView, the ismmovable and isVisible functions of the view component will affect whether the element can be laid out, and the layoutable property on the element style can also be set to false to prevent the element from participating in the layout.

After introducing the background of HT package's elastic layout, the next step is to help you achieve this effect easily.

First, we define a color array variable to store the colors of each elastic ball, and also define a random function to generate the colors in the array with random numbers:

var colorList = ['#FFAFA4', '#B887C5', '#B9EA9C', '#CFD9E7', '#4590B8', '#FF9C30'], 
    colorLen = colorList.length;
var randomColor = function() {
    var ran = Math.random() * colorLen;
    return colorList[Math.floor(ran)]; // Random 6 colors
};

Then create the elastic sphere, simply generate a 3D node, and control the display mode of the node by setting the style attribute of the node. Set "shape3d" to "sphere" to turn the ht.Node hexahedron into a 3D sphere model, and then set "shape3d" attribute to the random color defined on the front. s3 is the setSize3d function encapsulated by HT to set the size of the 3D node. Finally, add this node to the data model dataModel:

var createNode = function(dm) { // Create node circle
    var node = new ht.Node();
    node.s({ // Set style to short for setStyle
        'shape3d': 'sphere',
        'shape3d.color': randomColor() // Set random color
    });
    node.s3(40, 40, 40);
    dm.add(node);
    return node;
};

Now there is also a connection between the elastic balls in the rendering. We find this connection very unusual when we look at it. It is also through constructing a node, which is through HT for Web Modeling manual The ht.Default.createRingModel defined by setShape3dModel function is a 3D circular model formed around the curve of xy plane and named "custom":

ht.Default.setShape3dModel( // Create a 3D model around the curve of xy plane.
    'custom', ht.Default.createRingModel( [0.5, 0.5, -0.2, 0, 0.5, -0.5], [1, 3] )
);

HT divides the user-defined attribute and the default attribute calling method of HT into node.a and node.s, which can effectively distinguish them (refer to HT for Web Getting Started Guide style chapter), we used this method when creating pipelines:

var updatePipeline = function(edge) { // Style edge again
    var pipeline = edge.a('pipeline');
    pipeline.s3(1, 1, 1); // Set size
    pipeline.p3(0, 0, 0); // Set coordinates

    var node1 = edge.getSourceAgent(), // Get the start node of the connection on the drawing
    node2 = edge.getTargetAgent(); // Get target nodes connected on the drawing
    pipeline.s('mat', createMatrix(node1.p3(), node2.p3(), 20)); // Change of 3d whole graphic matrix
};

What's the most mysterious is how to make two nodes "as if they were apart"?

We know that a matrix can describe any linear transformation. The linear transformation preserves the straight line and parallel line, while the linear transformation preserves the straight line, other geometric properties such as length, angle, area and volume may be changed by the transformation. Simply put, a linear transform may "stretch" the coordinate system, but it will not "bend" or "roll" the coordinate system. This function is mainly to perform a "change matrix" operation on the connection line dragged after dragging the elastic ball. The change matrix is also the ht.Default.createMatrix function encapsulated by HT. By setting the style attribute mat of the node as a custom function, the coordinates of the node are multiplied by the corresponding value of the "mat" attribute, that is to say If the current rotation angle of this pipeline is [Math.PI/6, 0, 0], suppose we set r3 to [Math.PI/3, 0, 0] in the createMatrix function, then this node will rotate 90 degrees. It's very easy to create a change matrix:

var createMatrix = function(p1, p2, width) { // createMatrix(array, matrix) transforms a set of zoom, move and rotate operations described by JSON into corresponding change matrix
    var vec = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]],
        dist = ht.Default.getDistance(p1, p2); // Get the distance between two points, or vector length
    return ht.Default.createMatrix({
        s3: [width, dist, width],
    r3: [Math.PI/2 - Math.asin(vec[1]/dist), Math.atan2(vec[0], vec[2]), 0],
    rotationMode: 'xyz',
    t3: [(p1[0]+p2[0])/2, (p1[1]+p2[1])/2, (p1[2]+p2[2])/2]
    });
};

After all the basic accessories are defined, set the "shape3d" attribute to the custom 3D model, and set the "layoutable" attribute to "false" to prevent the elements from participating in the layout, and re brush the lines between the points through edge.a('pipeline', node), and add them to the data model dataModel:

var createEdge = function(dm, node1, node2) { // Create edge of 'custom' model
    var node = new ht.Node();
    node.s({
        'shape3d': 'custom',
        'shape3d.color': '#ECE0D4',
        'layoutable': false
    });
    dm.add(node);

    var edge = new ht.Edge(node1, node2);
    edge.a('pipeline', node);
    edge.s('edge.color', 'rgba(0, 0, 0, 0)');
    dm.add(edge);
    return edge;
};

Plug in: we can also use HeatMap heat map in industry to do articles, the effect is still very dazzling, specific address http://hightopo.com/guide/gui...

After all the graphics on the interface have been drawn, only the form form is left. First, add the form form to the HTML page, using the ht.widget.FormPane function encapsulated by HT:

var formPane = new ht.widget.FormPane();
formPane.setWidth(230);
formPane.setHeight(125);
formPane.addToDOM();

Remember to set the width and height of the form form, otherwise it will not be displayed.

The form form adds lines through the addRow function. Let's focus on the following lines: Color, Range and Intensity. These three names are mainly used to control the "headlights". In HT, the three functions of setHeadlightColor/setHeadlightRange/setHeadlightIntensity are directly used to control the Color, Range and Intensity of "headlight". The onValueChanged property, as the name implies, is the event triggered after the property value changes:

['Color', 'Range', 'Intensity'].forEach(function(name) {
    var obj = { id: name },
    func = function(oV, nV) {
        g3d['setHeadlight' + name](nV); // === g3d.setHeadlightColor(nV)/g3d.setHeadlightRange(nV)/g3d.setHeadlightIntensity(nV)
    };
    if (name === 'Color')
        obj.colorPicker = { // ht.widget.ColorPicker is the color selection box 
        instant: true,
        value: g3d['getHeadlight' + name](), // === g3d.getHeadlightColor()
        onValueChanged: func
    };
    else 
        obj.slider = { // Slider bar
            min: 0,
        max: name === 'Range' ? 20000 : 3,
        step: 0.1,
        value: g3d['getHeadlight' + name](),
        onValueChanged: func
        };
    formPane.addRow([ name, obj ], [ 70, 0.1 ]);
});

Sliders and colorpickers are custom slider s and color selectors for HT. Please refer to HT for Web Forms Manual.

If you still don't know, please consult me, or you can go directly. HT for Web Refer to the manual on the official website.

Posted by CaptainChainsaw on Tue, 15 Oct 2019 20:23:43 -0700