3D computer room creation based on HTML5 canvas

Time:2020-10-2

For 3D computer rooms, monitoring is no longer difficult. Different people have different methods. Today, I tried to write an HTML5 based computer room with HT, and found that HT is easy to use. This example is a comprehensive example of lighting, atomization, maximum and minimum distance of eye in 3D computer room. Next, I will analyze the implementation of this example, which is a summary of this example. Because there is no designer’s participation, the style of the whole example may be relatively simple. However, in some details, such as the texture on the wall, the embedding of door frame and the fire extinguisher, the real scene is restored as much as possible, and some thoughts are spent on this example!

Address of this case: http://www.hightopo.com/guide…

Dynamic diagram of this example:

3D computer room creation based on HTML5 canvas

From the most basic, the layout of the scene, according to the idea of HTML, this scene is to put the whole page in a div, and then add a top div and a middle div to the Div. to be honest, if we use HTML to implement this step, we don’t need to write much code, but if we write this code several times, everyone will be bored.. 。 HT encapsulates this implementation method. The entire external div is the basic component of HT. Here we use ht.widget.BorderPane The upper div is packaged in the ht.widget.Toolbar In the toolbar class, the lower part is the 3D part ht.graph3d . graph3dview component, add two parts of the page to the borderpane component in the following way, and add Borderpane is added to the body:

toolbar = new ht.widget.Toolbar(items);                                                                                                
dataModel = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dataModel);    
g3d.getView().style.background = 'black';
g3d.setGridSize(100);
g3d.setGridGap(100); 
g3d.setFar(30000);
g3d.setOrthoWidth(5000);  
G3d. Setfognear (100); // the default value is 1, which means that the object is affected by the fog effect from this distance
g3d.setFogFar(8000);
g3d.reset = reset;
g3d.reset();
g3d.enableToolTip();                                 
borderPane = new ht.widget.BorderPane();
borderPane.setTopView(toolbar);
borderPane.setCenterView(g3d);       

view = borderPane.getView();  
view.className = 'main';
document.body.appendChild(view);
window.addEventListener('resize', function (e) {
    borderPane.invalidate();
}, false);

The code above will borderPane.getView () is added to the body because the interface DOM structure of graph3dview is composed of the lowest div element and the rendering layer canvas element. The lowest div element can be obtained through getview().

We also notice that there is a parameter items not mentioned in the code above. This item is an element of the toolbar and an array element. The code is shown below and explained briefly here. For details, please refer to the HT for web toolbar manual

Items = [// array of elements in sidebar
    {
        Label: 'white', // label text of toolbar element
        Groupid: 'headlightcolor', // group the toolbar elements. Selecting elements in the same group will automatically result in mutual exclusion
        Selected: true, // whether the toolbar element is selected, and the value is true or false, which is valid for check boxes, switch buttons, and radio buttons
        Action: function() {// function type, called when the toolbar element is clicked
            g3d.setHeadlightColor('white');
        }
    },        
    {
        label: 'Red',
        groupId: 'headLightColor',
        action: function(){                             
            g3d.setHeadlightColor('red');
        }
    }, 
    {
        label: 'Blue',
        groupId: 'headLightColor',
        action: function(){                             
            g3d.setHeadlightColor('blue');
        }
    },        
    {
        label: 'Yellow',
        groupId: 'headLightColor',        
        action: function(){                             
            g3d.setHeadlightColor('yellow');
        }
    },        
    {
        id: 'step',                        
        Unfocusable: true, // whether the toolbar element can't get focus. By default, a rectangular border will be displayed when the mouse swipes. You can set it to true to turn off this effect
        slider: {
            width: 70,
            step: 500,
            min: 0,
            max: 10000,
            value: 0,                            
            onValueChanged: function(){
                g3d.setHeadlightRange(this.getValue());
            }       
        }                
    },
    'separator ', // indicates a separator bar
    {
        label: 'Fog',
        Type: 'check' // the type of toolbar element. Check means check box, toggle means switch button, and radio means radio button                        
        action: function(){
            g3d.setFogDisabled(!this.selected);
        }
    },
    {
        label: 'White',
        groupId: 'fogColor',
        selected: true,
        action: function(){                             
            g3d.setFogColor('white');
        }
    },                     
    {
        label: 'Red',
        groupId: 'fogColor',
        action: function(){                             
            g3d.setFogColor('red');
        }
    },        
    {
        label: 'Yellow',
        groupId: 'fogColor',        
        action: function(){                             
            g3d.setFogColor('yellow');
        }
    },
    {                       
        unfocusable: true,
        label: 'FogNear',
        slider: {
            width: 70,
            min: 10,
            max: 4000,
            value: 100,                            
            onValueChanged: function(){
                g3d.setFogNear(this.getValue());
            }       
        }                
    },                        
    {                       
        unfocusable: true,
        label: 'FogFar',
        slider: {
            width: 70,
            min: 5000,
            max: 15000,
            value: 8000,                            
            onValueChanged: function(){
                g3d.setFogFar(this.getValue());
            }       
        }                
    },                    
    'separator', 
    {
        id: 'movable',
        label: 'Movable',
        type: 'check',
        selected: false                
    }, 
    {
        label: 'Editable',
        type: 'check',
        selected: false,
        action: function(item){
            g3d.setEditable(item.selected);
        }
    },
    {
        label: 'Wireframe',
        type: 'check',
        selected: false,
        action: function(item){
            if(item.selected){
                dataModel.each(function(data){
                    data.s({
                        'wf.visible': 'selected',
                        'wf.color': 'red'                                        
                    });
                });                                
            }else{
                dataModel.each(function(data){
                    data.s({
                        'wf.visible': false                                       
                    });
                });                               
            }                            
        }
    },
    {
        type: 'toggle',
        label: 'Orthographic Projection',                        
        action: function(item){  
            g3d.setOrtho(item.selected);                           
        }                    
    },
    {
        type: 'toggle',
        selected: false,
        label: 'First Person Mode',
        action: function(item){
            g3d.setFirstPersonMode(item.selected);  
            g3d.reset();
        }
    },                                                       
    'separator',                      
    {
        type: 'check',
        label: 'Origin Axis',
        selected: false,
        action: function(item){
            g3d.setOriginAxisVisible(item.selected);                           
        }
    },   
    {
        type: 'check',
        label: 'Center Axis',
        selected: false,
        action: function(item){
            g3d.setCenterAxisVisible(item.selected);                           
        }
    },                             
    {
        type: 'check',
        label: 'Grid',
        selected: false,
        action: function(item){
            g3d.setGridVisible(item.selected);                           
        }
    },                    
    {
        label: 'Export Image',
        action: function(){                             
            var w = window.open();
            w.document.open();                            
            w.document.write("<img src='" + g3d.toDataURL(g3d.getView().style.background) + "'/>");
                            w.document.close();
        }
    }                    
];

The next step is to create each model in the scene. First, there are three lights, one in the middle, one in the left and one in the rear (I marked the light source, see the picture ~), and the colors are green, red, blue, and the floor

3D computer room creation based on HTML5 canvas

redLight = new  ht.Light (); // light class
redLight.p3(-1600, 200, -2200);
redLight.s({
    'light.color': 'red',
    'light.range': 1000
});
dataModel.add(redLight);
                
blueLight = new ht.Light();
blueLight.p3(1600, 200, -2200);
blueLight.s({
    'light.color': 'blue',
    'light.range': 1000
});
dataModel.add(blueLight);                                   
                
greenLight = new ht.Light();
greenLight.p3(-800, 400, -200);
greenLight.s({
    'light.center': [-300, 0, -900],
    'light.type': 'spot',
    'light.color': 'green',
    'light.range': 4000,
    'light.exponent': 10
});
dataModel.add(greenLight);                
                
floor = createNode([0, -5, -1500], [5200, 10, 4200]);
floor.s({                             
    'shape3d': 'rect',
    'shape3d.top.color': '#F0F0F0'                    
});

Next, add the servers in the middle of the scene, servers on both sides, fire extinguishers, air conditioning on the wall, air conditioning on the back of the wall, and so on

for(i=0; i<3; i++){
    for(j=0; j<3; j++){
        createServer1(250+i*280, -1200-500*j, j === 2);
        createServer1(-250-i*280, -1200-500*j, j === 1);
    }
}
                     
//Create two rows of two servers on both sides of the scene
for(i=0; i<2; i++){
    for(j=0; j<2; j++){
        createServer2(1500+i*200, -700-500*j, 
                            (i === 1 ? (j === 1 ? '#00FFFF' : '#C800FF') : null));
        createServer2(-1500-i*200, -700-500*j, 
                            (j === 1 ? (i === 1 ? 'red' : 'yellow') : null));
    }
}                                          
          
// fire extinguisher
createFireExtinguisher(1300, -1800, [0.45, 0]); 
createFireExtinguisher(-1300, -1800); 
createFireExtinguisher(1100, -2450);   
createFireExtinguisher(-1100, -2450, [0.45, 0]);  
                
// air condition
createNode([1120, 170, -700], [80, 340, 170]).s({
    'all.color': '#EDEDED',
    'left.image': 'stand'
}).setToolTip('Air Conditioner'); 
createNode([-1120, 170, -700], [80, 340, 170]).s({
    'all.color': '#EDEDED',
    'right.image': 'stand'
}).setToolTip('Air Conditioner'); 
createNode([1680, 400, -1850], [370, 120, 60]).s({
    'all.color': '#767676',
    'front.image': 'air1'
}).setToolTip('Air Conditioner');             
createNode([-1680, 400, -1850], [370, 120, 60]).s({
   'all.color': '#767676',
   'front.image': 'air2'
}).setToolTip('Air Conditioner'); 
for(i=0; i<2; i++){
    createNode([300+i*580, 90, -2630], [260, 180, 60]).s({
        'all.color': '#EDEDED',
        'back.image': 'air3'
    }).setToolTip('Air Conditioner');  
    createNode([-300-i*580, 90, -2630], [260, 180, 60]).s({
        'all.color': '#EDEDED',
        'back.image': 'air3'
    }).setToolTip('Air Conditioner');                      
}

The createserver1 method is the method used to create the server ht.Node As the fuselage and ht.Shape It is composed of doors, and a random number of devices are added inside the cabinet

Function createserver1 (x, Z, disabled) {// create server 1 (middle part)
    var h = 360, w = 150, d = 170, k = 10,
         main = createNode([0, 0, 0], [w, h, d]),
         face = new ht.Shape(),
         s = {' all.visible ': false, ' front.visible ': true}; // set the node to be visible only to the front       
                  
    dataModel.add(face);
    face.addPoint ({X: - w / 2, Y: D / 2-1}); // three points on the gate
    face.addPoint({x: w/2, y: d/2-1});
    face.addPoint({x: w+w/2, y: d/2-1});
    face.setSegments([1, 2, 1]);                
    face.setTall(h);
    face.setThickness (1) ; // set thickness      
    face.s(s);                
    face.setHost (main); // adsorbed on the main node
                
    main.s({
        'all.color': '#403F46',
        'front.visible': false
    });                
                
    if(!disabled){                
        face.s({
            'all.color': 'rgba(0, 40, 60, 0.7)',
            ' all.reverse.flip ': true, // does the reverse side show the positive
            ' all.transparent ': true // set to transparent
       });
       face.face  =True; // initializes the face attribute             
       face.open = false;
       face.angle = -Math.PI * 0.6;                       
       face.setToolTip('Double click to open the door');
                    
       var up = createNode([0, h/2-k/2, d/2], [w, k, 1]).s(s),
            down = createNode([0, -h/2+k/2, d/2], [w, k, 1]).s(s),
            right = createNode([w/2-k/2, 0, d/2], [k, h, 1]).s(s),
            left = createNode([-w/2+k/2, 0, d/2], [k, h, 1]).s(s);
                                
       up.setHost(face);
       down.setHost(face);
       left.setHost(face);
       right.setHost(face);

       //Randomly create 2 or 4 devices in the cabinet
       var num = Math.ceil(Math.random() * 2),
       start = 20 + 20 * Math.random();
       for(var i=0; i<num; i++){
           var node = createNode([0, start+45*i, 0], [w-6, 16, d-30]);
           node.setHost(main);
           node.s({
               'front.image': 'server',
               'all.color': '#E6DEEC',
               'all.reverse.cull': true
           });
           node.pop  =False; // initializes the "eject" property of the device
           node.setToolTip('Double click to pop the server');

           var node = createNode([0, -start-45*i, 0], [w-6, 16, d-30]);
           node.setHost(main);
           node.s({
               'front.image': 'server',
               'all.color': '#E6DEEC',
               'all.reverse.cull': true
           }); 
           node.pop = false;
           node.setToolTip('Double click to pop the server');
       }                    
   }
                
   main.p3(x, h/2+1, z);
}

We also made the opening and closing actions of the door, as well as the pop-up and recovery position of the devices inside the server. First, a filter function is added to 3D components to filter the elements of double-click events

3D computer room creation based on HTML5 canvas

G3d.ondatadoubleclicked = function (data, e, datainfo) {// call back when an element is double-click
    If ( data.face ){// face is the property that is opened when defining the door, and is added when the node is defined. The same is true for the following pop
        data.getHost (). Getattachments(). Each (function (attach) {// traverse the ht.List Type array
            If ( attach.pop ){// Pop is an attribute that defines whether the device pops up or not
                toggleData(attach);
            }
       });
    }
    toggleData(data, dataInfo.name);
};

Here is the definition of toggle data:

Function toggledata (data, name) {// the action of opening and closing the door and the device ejecting and retracting
    var angle = data.angle,
    pop = data.pop;
            
    if(angle != null){
        if(anim){
            anim.stop (true); // htthe animation is terminated when the built-in function parameter is true
        }
        var oldAngle = data.window ? data.getRotationX() : data.getRotation();
        if(data.open){
            angle = -angle;
        }
        data.open = !data.open;
        anim = ht.Default.startAnim({
            action: function(v){
                if(data.window){
                    data.setRotationX(oldAngle + v * angle);    
               }else{
                   data.setRotation(oldAngle + v * angle);
               }                                
           }
       });
   }
   else if(pop != null){
        if(anim){
           anim.stop(true);
        }
        var p3 = data.p3(),
            s3 = data.s3(),
            dist = pop ? -s3[2] : s3[2];
        data.pop = !data.pop;                        
        if(data.pop){
            data.s({
                'note': 'Detail...',  
                'note.background': '#3498DB',
                'note.font': '26px Arial',
                'note.position': 6,
                'note.t3': [-30, -3, 30],
                'note.expanded': true,
                'note.toggleable': false,
                'note.autorotate': true                        
            });                                     
        }else{
             data.s('note', null);
        }                                                
        anim = ht.Default.startAnim({
             action: function(v){
                 data.p3(p3[0], p3[1], p3[2] + v * dist);                                                               
             }
        }); 
    }            
}

I will not repeat the server in the middle part. Here I will talk about the more interesting part. The fire extinguisher model is not made by max3d, but generated by code

3D computer room creation based on HTML5 canvas

As can be seen from the figure, the fire extinguisher is composed of a cylinder at the bottom, a semicircle in the middle and a small cylinder at the top, which are mapped on the top of the fire extinguisher

Function create fireextinguisher (x, Z, uvoffset) {// create fire extinguisher
    var w = 80, 
          h = 200,
          Body = createnode ([0,0,0], [w, h, w]). S ({// cylinder of body)
              'shape3d ':'cylinder', // cylinder
              'shape3d.image': 'fire',
              'shape3d. uv.offset ': uvoffset, // determines the UV offset of the overall map of 3D graphics
              'shape3d.reverse.cull': true
          }),                    
          sphere = createNode([0, h/2, 0], [w, w, w]).s({
              'shape3d ':'sphere', // sphere
              'shape3d.color': '#F20000',
              'shape3d.reverse.cull': true
          }),
          Top = createnode ([0, H / 2 + W / 3, 0], [w / 2, w / 2, w / 2]). S ({// cylinder of head)
              'shape3d': 'cylinder',
              'shape3d.color': '#242424',
              'shape3d.reverse.cull': true
          });
                    
    sphere.setHost (body); // set adsorption as long as the body moves, the sphere will also move
    top.setHost(sphere);
    body.p3([x, h/2, z]);
    body.setToolTip('Fire Extinguisher');
    sphere.setToolTip('Fire Extinguisher');
    top.setToolTip('Fire Extinguisher');
}

above! This 3D computer room example is very representative, and the performance is also very comprehensive. I think it is necessary to talk about it. I hope it can help you~