3D network topology diagram based on HTML5 WebGL

Now, 3D models have been used in a variety of different fields. They are used in the medical industry to make accurate models of organs; the film industry uses them for moving characters, objects, and real-life movies; the video game industry uses them as resources in computers and video games; and the science industry uses them as accurate models of chemical compounds ; the construction industry uses them to present proposed representations of buildings or landscapes; the engineering community uses them to design new equipment, vehicles, structures, and other applications; in recent decades, the field of earth sciences has begun to build 3D geological models, Also, 3D models are often animated, for example, they are used extensively in feature films, as well as in computer and video games. They can be used in 3D modeling tools or alone. In order to easily form animation, some additional data is usually added to the model. For example, some 3D models of humans or animals have a complete skeletal system, so that the movement will look more realistic, and the movement can be controlled by joints and bones.

All of these make us front-end developers feel that if we can achieve 3D effects without learning unity3d or other game development tools, and can accurately control movement or direction by code. . . So I used   the  3D components in HT For Web  to implement a small example, using  most of the functions  of the  3D components in HT  , and doing this example is to  master the 3D components and try to put them into an example. You can refer to it if necessary.

Let's take a look at the overall effect diagram:

Using  HT for Web , it is not a problem to create a three-layer backplane from the existing 3d template, the problem is how to put the "computer" and "cabinet components" on the first layer in the picture? I downloaded the obj format file from the Internet, and then I used   the ht.Default.loadObj(objUrl, mtlUrl, params) function in  HT to load the model, and the params part can refer to http://www.hightopo. com/guide/guide/plugin/obj/ht-obj-guide.html , the code is as follows:

ht.Default.loadObj('obj/cabinet assembly 1.obj', 'obj/cabinet assembly 1.mtl', { //Load obj file
    cube: true, //Whether to scale the model to the size range of unit 1, the default is false
    center: true, //Whether the model is centered, the default is false, setting it to true will move the model position to center its content
    shape3d: 'box', //If the shape3d name is specified, HT will automatically build all the parsed material models into an array and register with this name
    finishFunc: function(modelMap, array, rawS3){ //For callback processing after loading
      if(modelMap){  
        device2 = createNode('box', floor1); //Create a node on the first floor "floor"
    device2.p3([x1-120, y1+13, z1+60]); //Set the coordinates of this node
    device2.s3(rawS3); //Set the size of this node
    createEdge(device1, device2); //Create a connection
    device3 = createNode('box', floor1);  
    device3.s3(rawS3);  
    device3.p3([x1+120, y1+13, z1+60]);  
    createEdge(device1, device3);  
      }  
    }  
});

The three parameters in the finishFunc function are defined as follows:

  • modelMap: The return value after calling ht.Default.parseObj parsing, if the loading or parsing fails, the return value is empty
  • array: an array of all material models
  • rawS3: contains the original size of all models

Generally, in practical applications, we will set the size of the primitive to the original size of the model.

There is a red "warning" above the "computer" that the stereo can be rotated, which depends on the ht.Default.setShape3dModel function (HT for Web Modeling Manual  http://www.hightopo.com/guide/guide/plugin/modeling/ht -modeling-guide.html ) registered a 3d model, in ht, there are many encapsulated modeling functions, the more basic ones are spheres, cylinders, cubes, etc. Here I use the method createRingModel to construct a ring Generate the outermost ring of "warning", the upper part of the exclamation mark is the sphere constructed with createSmoothSphereModel, and the lower part of the exclamation mark is the cylinder constructed with createSmoothCylinderModel. I directly used the functions encapsulated in the 3d model at first, so I didn't know what the parameters used in the function were used for, and I didn't understand how the 3d model was composed, and then I re-read the previous "" "Model foundation", only to know that a surface used in the original 3d model, the most basic is the triangular surface, and then the complex surface is also formed by multiple triangular surfaces, and then formed by rotating around a specific axis, of course, This axis is up to you. Different axes can generate different shapes. For style settings such as colors, please refer to the HT for Web Style Manual ( http://www.hightopo.com/guide/guide/core/theme/ ht-theme-guide.html ). As for how to rotate the 3d model, the addScheduleTask(Task) method is encapsulated in ht. I call a rotation function setRotation encapsulated in ht in the third-layer Task to set the order and direction of rotation, and specify the object to be rotated. Here's how to customize the "warning" 3d model (note: because the model in this example is a custom combination, if you want to set the color of the overall model, use the "all.blend" style property):

function createAlarm(device, formPane) {
    var ringModel = ht.Default.createRingModel([ 8, 1, 10, 1, 10, -1, 8, -1, 8, 1 ], null, null, false, false, 100);//According to the xy plane Curves, wrapping around to form a 3D model.
    var sphereModel = ht.Default.createSmoothSphereModel(8, 8, 0, Math.PI*2, 0, Math.PI, 2);//Build a smooth sphere model
    var cylinderModel = ht.Default.createSmoothCylinderModel(8, true, true, 1, 2, 0, Math.PI*2, 8);//Build a smooth cylinder model
    
    var alarmArr = [//The combined model is composed of three models ringModel, sphereModel, cylinderModel
        {
          shape3d: ringModel,//Define the model type
          r3: [Math.PI/2, 0, 0],//Set the rotation angle
          color: {//Set the model color
            func: '[email protected]',//The all.blend attribute in the data binding style style, which can be obtained and set through data.s()
          }
        },{
          shape3d: sphereModel,
          t3: [0, 4, 0],
          color: {
            func: '[email protected]',
          }
        },{
          shape3d: cylinderModel,
          t3: [0, -3, 0],
          color: {
            func: '[email protected]',
          }
        }
    ];
    ht.Default.setShape3dModel('alarm', {//Register custom 3D model
      shape3d: alarmArr
    });

    var alarmTip = createNode('alarm', device);//Create a node whose shape3d is alarm
    alarmTip.s3([2, 2, 2]);//Set the node size
    alarmTip.p3(device.p3()[0], device.p3()[1]+60, device.p3()[2]);
    alarmTip.s('all.blend', 'red');//Change this property to change the color of the model, because the model is already data bound when it is created

    return alarmTip;
}

Next, let's see how to make this "alarm" node "flicker". I directly bind this animation to the node, so that the animation can be controlled directly through the node. So when we create the model of the alarm above, we can directly bind the animation to the node:

if(formPane){
    alarmNode.scaleFunc = function() {//Set size change animation
        var size = alarmNode.s3();//Get the size of the node
        if (size[0] === 2 && size[1] === 2 && size[2] === 2) alarmNode.s3([1, 1, 1]);
        else alarmNode.s3 ([2, 2, 2]);
        alarmNode.scaleTimer = setTimeout(alarmNode.scaleFunc, formPane.v('scaleInterval'));//Set animation
    }
    alarmNode.blinkFunc = function(){//Set the blinking animation
        var color = alarmNode.s('all.blend');//Get the style of the node
        if (color === 'red') alarmNode.s({'all.blend': 'yellow'});//If the node color is red, set it to yellow
        else alarmNode.s({'all.blend': 'red'});
        alarmNode.blinkTimer = setTimeout (alarmNode.blinkFunc, formPane.v ('blinkInterval'));
    }
    alarmNode.rotateFunc = function() {//Set the rotation animation
        alarmNode.setRotation(alarmNode.getRotation() + Math.PI/20);//Get the current rotation angle of the node, add Math.PI/20 angles on top of this rotation angle
        alarmNode.rotateTimer = setTimeout (alarmNode.rotateFunc, formPane.v ('rotInterval'));
    }
}

In the animation above, I set the speed of the node flickering, the animation of the flickering node, etc., which can be controlled by the properties on the form form panel, mainly to talk about the implementation of this function on the form form:

formPane.addRow([//Add a row of elements to the form panel
    {
        checkBox: {//Check box
            label: 'Enable Blink',//The text content corresponding to the checkbox
            selected: true,//Set the selected checkbox
            onValueChanged: function(){//The function of the callback when the checkbox value changes
                var data = dataModel.getDataByTag('colorAlarm');//Get the node through the tag tag
                if (this.getValue()) {//Get the current value of the checkbox true/false
                    data.blinkTimer = setTimeout(data.blinkFunc, formPane.v('blinkInterval'));//Set the animation directly by setting the blinkTimer of the node
                }
                else {
                    clearTimeout(data.blinkTimer);//Clear animation
                }
            }
        }
    },
    {
        id: 'blinkInterval',//form can get the value of this item through getValue (abbreviated as v)
        slider: {//After setting this HTproperty ht.widget.Slider, the object will be automatically constructed according to the property value and saved on the elementproperty
            min: 0,//slider minimum value
            max: 1000, //the maximum value of the slider
            step: 50,//slider step
            value: 500,//The value of the current slider
        }
    }
], [0.1, 0.1]);//Set the value of the width of the two item elements in this line is less than 1 to the ratio

Finally, let's talk about the part where the balls flow on the 3D pipeline. This function is really very practical, and the effect is really good. I want to share it with you~

First, create a line to connect the start node and end node and set the style of the line. Use ht.Edge to attach the line to the start node and end node, so that any one of the two nodes can be moved. The connection will change with the position of the node movement, which is very convenient:

var polyline = new ht.Edge(source, target);//Create a connection
dataModel.add(polyline);//Add the connection to the data container
polyline.s({
    'edge.width': 5,//connection width
    'edge.type': 'points',//When the connection type is points, the direction of the connection will be determined by the edge.points property, which is used to draw polylines
    'edge.points': [//The array of point objects in {x:100, y:100} format of type ht.List can be set, which works when edge.type is points
        {x: source.getPosition3d()[0]+200, y: source.getPosition3d()[2], e: source.getPosition3d()[1]},
        {x: target.getPosition3d()[0]+400, y: target.getPosition3d()[2], e: target.getPosition3d()[1]}
    ],
    'edge.segments': [1, 4], // used to describe the point connection style, the array element is an integer value
    'shape3d': 'cylinder',//cylinder
    'shape3d.color': 'rgba(242, 200, 40, 0.4)',
    'shape3d.resolution': 30,//Number of micro-segments, which can determine the smoothness of the curve
    'edge.source.t3': [20, 0, 0],//connection source end offset, [tx, ty, tz] format, default is empty
    'edge.target.t3': [20, 0, 0]//connection target end offset, [tx, ty, tz] format, default is empty
});

Because the points we set when creating the connection are only two points on the curve, so if we want to obtain the points currently formed by the curve, the two points of source and target are missing. We reset an array and put these two points. Points are added, which will be used later to obtain all points on the curve:

var list = new ht.List();
list.push({x: source.getPosition3d()[0], y: source.getPosition3d()[2], e: source.getPosition3d()[1]});//Add source points to the array
polyline.s('edge.points').each(function(item){//Add the two points that have been set in the style attribute
    list.push(item);
});
list.push({x: target.getPosition3d()[0], y: target.getPosition3d()[2], e: target.getPosition3d()[1]});//添加target点

Then create a ball node that slides on the pipeline. This is only a setting node. When it is actually added to the data container dataModel, it needs to be added when the coordinates of the ball need to be set. If the position is not set for the node, add the node to the data container. , the initial position of the node is the position of the center [0, 0, 0] of the 3D scene. The animation code of the ball sliding is as follows:

var ball = new ht.Node();//Create a ball node
ball.s({//Set the style of the ball node
    'shape3d': 'sphere',//Set the 3d model of the ball to spherical
    'shape3d.color': 'rgba(40, 90, 240, 0.4)'//Set the color of the 3d model
});

var delta = 10, flag = 0;
setInterval(function(){
    flag++;
    var length = (polyline.a('total') || 0) % polyline.a('length') + delta;//The length of the curve that the ball currently travels
    var cache = ht.Default.getLineCacheInfo(list, polyline.s('edge.segments'));//Get the information of the points on the curve
    var lineLength = ht.Default.getLineLength(cache);//Get the total length of the curve
    polyline.a('length', lineLength - 50);//Because I set the edge's t3 (equivalent to the offset in 2d), the line length is actually not that long
    var offset = ht.Default.getLineOffset(cache, length);//The offset of the curve according to the information of the points on the curve
    ball.setPosition3d(offset.point.x + 10, offset.point.y, offset.point.z);//Set the coordinates of the node
    polyline.a('total', length);
    if(flag === 1) dataModel.add(ball);//The node already has coordinates and can be added to the data container
}, 10);

We can also see that there are two special polygons "parallelogram" and "trapezoid" on the second layer. The parallelogram is based on the createParallelogramModel model function, which is relatively simple, createExtrusionModel(array, segments, top, bottom, resolution, repeatUVLength , tall, elevation), array is the coordinate point of the graph you want to form, this is just for the plane graph drawn on the xz axis, segments refers to how to connect these coordinate points, please refer to the HT for Web shape manual ( http://hightopo.com/guide/guide/core/shape/ht-shape-guide.html ), top and bottom are to let you choose whether there is a top or bottom, the resolution is the number of micro-segments, when we draw a curve, we may only need Confirm a few individual points and then divide it into multiple segments on the line between each two points, so that this line segment will become smooth, ht encapsulates this parameter so that users can easily manipulate these line segments , repeatUVLength is empty by default. After setting the value, the top and bottom textures will be repeated according to the specified length value. The height of the tall model is 5 by default. The y-axis position of the elevation model center is 0 by default. Setting this value can make xz The plane on is rotated around the y-axis.

The effect of a ring at the bottom is achieved through an algorithm. The ring has to confirm how many elements there are on the ring, and then calculate the angle between each two, and calculate the position of each element through sin and cos, and get the following code:

names = ['Device 2', 'Device 3', 'Device 4', 'Device 5', 'Device 6', 'Device 7', 'Device 8', 'Device 9'];  
names.forEach(function(name, index) {  
    x = 400, y = 200, angle = 45, r = 120;  
    x = x3 + Math.sin((2 * Math.PI / 360) * angle * index) * r;  
    y = z3 + Math.cos((2 * Math.PI / 360) * angle * index) * r;  
    device = createRect([x, y3 + 15, y], [w * 0.1, 15, h * 0.1], '', '', floor3);  
    createEdge(device5, device);  
});

If there are other parts that you don't understand, you can go to the official website ( http://hightopo.com ) to check the corresponding manual, or leave a private message.

An example of this article is attached: http://www.hightopo.com/demo/3DTopology/index.html

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324375091&siteId=291194637