3D network topology diagram based on HTML5 WebGL

Foreword

In a 2D scene with a large amount of data, it is difficult to find a specific model, and only a certain part of the model can be displayed, and the display is not intuitive enough. At this time, there is a great demand to quickly build a 3D scene. However, building 3D application scenes relies on modeling by 3ds Max or Maya professional 3D designers, and Unity 3D engine for graphics rendering, etc., which is a challenge for users! However, HT provides a one-stop solution from modeling to rendering, including 2D component rendering and data fusion. The HT.graph3dView component of HT's 3D technology based on WebGL encapsulates the underlying technology of WebGL, and like other components of HT, based on HT's unified DataModel data model to drive graphics display, greatly reducing the threshold of 3D graphics technology development, On the basis of being familiar with the HT data model, the average programmer only needs 1 hour of learning to get started with 3D graphics development.

Well, without further ado, first attach Demo: http://www.hightopo.com/demo/blog_3dedge_20170630/index.html

Of course, here I only use simple graphics to represent the device. Of course, you can replace it with a more interesting model.

3D scene construction

1. Preparation:

The design of the 3D and 2D APIs maintains a lot of consistency. The 3D view component is ht.graph3d.Graph3dView and the 2D view component is ht.graph.GraphView. Both can share the same data model DataModel. In HT, in order to obtain a visual effect close to a real three-dimensional object, we use perspective projection to make the far objects smaller and the near objects larger. The parallel lines will appear first to cross, and the visual effect is closer to the human eye:

As shown in the above figure, the content displayed by the perspective projection on the screen is only the content of the truncated vertebral body, so GraphView provides eye, center, up, far, near, fovy and aspect parameters to control the specific range of the truncated vertebral body , We use more eye and center in practical application:

  • getEye () | setEye ([x, y, z]), determine the location of the eye (or Camera), the default value is [0, 300, 1000];

  • getCenter () | setCenter ([x, y, z]), determine the location of the target center point (or Target), the default value is [0, 0, 0];

See the HT for Web 3D manual for details .

dataModel = new ht.DataModel(); 
g3d = new ht.graph3d.Graph3dView(dataModel);
g3d.setEye(1800, 800, 1000); 
g3d.setCenter(0, 100, 0); 
g3d.setDashDisabled(false); 
g3d.getView().style.background = 'rgb(10, 20, 36)'; 
g3d.addToDOM();

2. Create device:

Server, the server in Demo is actually adding pictures to the location of the server through addStyleIcon. For details, please see the HT for Web Getting Started Manual :

//注册图片 
ht.Default.setImage('server', 'server.png');  
var server = new ht.Node();         
server.s3(0, 0, 0);         
server.p3(0, 60, 0);         
server.addStyleIcon('icon', {             
    position: 0,             
    width: 200,              
    autorotate: true,             
    transparent: true,                            
    height: 200,             
    names: ['server']         
});         
dataModel.add(server);

Workbench, the workbench here is actually represented by a three-dimensional cylinder. HT is displayed on the 2D graphics of GraphView. The presentation of various graphics is determined by the shape attribute of style. Similar HT provides shape3d attributes on 3D, predefined Various 3D shapes, see HT for Web 3D manual for details . However, I did not use a predefined graphic here, but created a cylinder by ht.Default.createRingModel. This method can form a 3D model around a circle according to the curve of the xy plane, so it can be used to define a variety of circular 3D model.

var desktop = new ht.Node();
desktop.s({
    '3d.selectable': false,
    'shape3d': ht.Default.createRingModel([
                   0, 40,
                   450, 40,
                   450, 0,
                   0, 40
                ], null, 20, false, false, 50),
    'shape3d.color': '#003333'
});
desktop.s3(1, 1, 1);
dataModel.add(desktop);

For the devices on the platform, we have created a total of 32 devices:

var count = 32;
    radius = 400;
    index = count/2;
for (var i =  1; i <= count/2; i++) {
    var device1_angle1 = Math.PI * 2 * (index - i) / count,
        device1_angle2 = Math.PI * 2 * (index + i) / count,
        device1_angle3 = Math.PI * 2 * index / count;

    var device1_1 = createDevice(device1_angle1, radius, 60),
        device1_2 = createDevice(device1_angle2, radius, 60),
        device1_3 = createDevice(device1_angle3, radius, 60);

    layoutDevice1(device1_1, device1_angle1);
    var device1_edge1 = createEdge(device1_1, server, 'line1');
    device1_edge1.s({'shape3d.color': 'rgb(205, 211, 34)'});
    dataModel.add(device1_1);
    dataModel.add(device1_edge1);

    layoutDevice1(device1_2, device1_angle2);
    var device1_edge2 = createEdge(device1_2, server, 'line1');
    device1_edge2.s({'shape3d.color': 'rgb(205, 211, 34)'});
    dataModel.add(device1_2);
    dataModel.add(device1_edge2);

    layoutDevice1(device1_3, device1_angle3);
    var device1_edge3 = createEdge(device1_3, server, 'line1');
    device1_edge3.s({'shape3d.color': 'rgb(205, 211, 34)'});
    dataModel.add(device1_3);
    dataModel.add(device1_edge3);
}

In order to make the layout of the created device on the platform more reasonable, the device placement angle is calculated according to the index, and the position of each device is calculated according to the center of the cylinder, the disk radius and the angle:

function createDevice (angle, x, y) {
  var node = new ht.Node();
  cos = Math.cos(angle);
  sin = Math.sin(angle);
  node.p3(x*sin, y, x*cos);
  return node;
}

other devices,

var num = 18;
var h = [800, 900, 1000, 1100, 1200];
var v = [40, 60, 80, 100];
var colors = ['#fcfc63', '#00E1E4'];
for (var j = 0; j < num; j++) {
  var device2_angle = Math.PI * j / num;
  var device2 = createDevice(device2_angle, h[Math.floor(Math.random()*5)], v[Math.floor(Math.random()*4)]);
  device2.s3(100, 20, 100); 
  device2.s({
    'shape3d': 'cylinder',
    'shape3d.color': colors[Math.floor(Math.random()*2)]
    });
  var device2_edge = createEdge(device2, desktop , 'line2');
  device2_edge.s({'shape3d.color': 'rgb(0, 203, 94)'});

  dataModel.add(device2);
  dataModel.add(device2_edge);         
}

3. Connect

HT for Web provides default straight line and multi-point connection types that can meet most basic topological graphics applications, but here we need to draw curves according to actual needs, so we need to use custom connection types, see HT for details Web connection type manual :

Use the ht.Default.setEdgeType (type, func, mutual) function to customize the new connection type:

  • type: the connection type of the string type, corresponding to the edge.type attribute of style;

  • func: Function type, according to the incoming parameters (edge, gap, graphView, sameSourceWithFirstEdge) return the connection trend information

1. edge: current connection object;

2. gap: When multiple connections are bundled, the distance between the corresponding connection object and the center connection;

3. graphView: the current corresponding topology component object;

4. sameSourceWithFirstEdge: boolean type, change whether the connection is the same as the first one in the same group;

5. The return value is {points: new ht.List (…), segments: new ht.List (…)} structure connection direction information, segments can take the following values:

1), moveTo, occupy 1 point information;

2), lineTo, occupy 1 point information;

3), quadraticCurveTo, occupies 2 points of information;

4), bezierCurveTo, occupies 3 points of information;

5), closePath, do not occupy point information;

  • mutual: This parameter determines whether the connection affects all connections on the start or end node. The default is false, which only affects the connections in the EdgeGroup with the same source and target. Among the predefined connection types of HT , the suffix is ​​2. The types are all complex connection types whose mutural is true.

Two types of connections are defined in Demo, line1 and line:

ht.Default.setEdgeType('line1', function(edge){
  var sourcePoint1 = edge.getSourceAgent().getPosition(),
    targetPoint1 = edge.getTargetAgent().getPosition(),
    points1 = new ht.List();       
  points1.add(sourcePoint1);
  points1.add({
    x: (sourcePoint1.x + targetPoint1.x)/2 + 200,
    e: sourcePoint1.e,
    y: (sourcePoint1.y + targetPoint1.y)/2
  });
  points1.add(targetPoint1);                          
  return {
    points: points1,
    segments: new ht.List([1, 3])
  };
});
ht.Default.setEdgeType('line2', function(edge){
  var sourcePoint = edge.getSourceAgent().getPosition(),
    targetPoint = edge.getTargetAgent().getPosition(),
    points = new ht.List();       
  points.add(sourcePoint);
  points.add({
    x: (sourcePoint.x + targetPoint.x)/2,
    e: ((sourcePoint.e + targetPoint.e)/2 || 0) - 300,
    y: (sourcePoint.y + targetPoint.y)/2
  });
  points.add({
    x: targetPoint.x,
    e: targetPoint.e -80, 
    y: targetPoint.y                            
  });
  return {
    points: points,
    segments: new ht.List([1, 3])
  };
});

The connection type is well defined. The next step is to create a connection, but there is still a flow effect on the connection. Our HT has an extension flow line plug-in, which can increase the flow effect on ht.Shape and ht.Edge. It supports internal flow elements or user-defined flow elements to step along the path. It is also very convenient to use, only need to introduce ht- The flow.js file, the details can be found in the HT for Web flow line manual , but the plug-in is not suitable for the 3D model, so what should I do in the 3D model? Even if we can not use the ready-made plug-ins, we can achieve the flow effect. You can see the connection part in the HT for Web Getting Started Manual . We can set the connection style to be a dotted line through edge.dash, and dynamically change the edge of the dotted line.offset Move, you can achieve the flow effect, so when we create a connection:

function createEdge (source, target , type) {
  var edge = new ht.Edge(source, target);
  edge.s({
    'edge.color': 'yellow',
    'edge.dash': true,
    'edge.dash.3d': true,
    'edge.dash.width': 4,
    'edge.type': type,                    
    'edge.dash.color': 'rgb(10, 20, 36)',                    
    'edge.dash.pattern': [20, 25]
  });
  edge.a({
    'flow.enabled': true,
    'flow.direction': -1,
    'flow.step': 4
  });
  return edge;
}

Finally, to make the dotted line flow, you can use the scheduling in HT. For details, see the HT for Web scheduling manual :

flowTask = {
  interval: 50,
  action: function(data){
    if(data.a('flow.enabled')){
      var offset = data.s('edge.dash.offset') + data.a('flow.step') * data.a('flow.direction');
      data.s('edge.dash.offset', offset);                        
    }
  }
};
dataModel.addScheduleTask(flowTask);

At this point, the main technical points in the Demo have been introduced once, and we can see the strength of our HT . Of course, we have many interesting effects on our official website. You can also take a look and play with us. HT feels its power, and attach the Demo address again: http://www.hightopo.com/demo/blog_3dedge_20170630/index.html .

Published 314 original articles · Like 138 · Visit 390,000+

Guess you like

Origin blog.csdn.net/u013161495/article/details/102816068