Building on the previous article covering standard data center construction, this guide walks through implementing 3D micro-modules for data center visualization using Three.js.
1. Component Creation
Assemble the data center from small components, working from the inside out.
1.1 Server Model
Define server geometry and textures via JSON parameters for full attribute control.
var serverConfig = {
"show": true,
"uuid": "",
"name": "equipment_card_2_4",
"objType": "cube",
"length": 60,
"width": 65,
"height": 20,
"x": 0,
"y": 300,
"z": 0,
"style": {
"skinColor": 9593611,
"skin": {
"skin_up": { "skinColor": 9593611, "imgurl": "../../img/3dImg/rack_inside.jpg" },
"skin_down": { "skinColor": 9593611, "imgurl": "../../img/3dImg/rack_inside.jpg" },
"skin_fore": { "skinColor": 9593611, "imgurl": "../../img/3dImg/rack_inside.jpg" },
"skin_behind": { "skinColor": 9593611, "imgurl": "../../img/3dImg/server2.jpg" },
"skin_left": { "skinColor": 9593611, "imgurl": "../../img/3dImg/rack_inside.jpg" },
"skin_right": { "skinColor": 9593611, "imgurl": "../../img/3dImg/rack_inside.jpg" }
}
},
"showSortNub": 4
};
var serverModel = WT.commonFunc.createServer(serverConfig);
1.2 Server Ports
Retrieve port data via API and generate corresponding geometry.
var portParams = webApi.getPortsFromServerByServerid(serverId);
WT.commonFunc.createPorts(portParams);
2.1 Cabinet Model
The cabinet consists of multiple movable parts, each controllable individually.
{
show: true,
name: 'cabinet3',
actionSign: "cabinet1",
shellname: 'cabinet3_emptyCabinetshell',
uuid: '',
objType: 'emptyCabinet2',
transparent: true,
size: { length: 66, width: 70, height: 200, thick: 2 },
position: { x: 0, y: 305, z: 0 },
doors: {
doorType: 'lr',
doorSize: [1],
doorname: ['cabinet3_emptyCabinetdoor_01'],
skins: [{
skinColor: 0x333333,
skin_fore: { imgurl: "../../img/3dImg/rack_door_back.jpg" },
skin_behind: { imgurl: "../../img/3dImg/rack_front_door.jpg" }
}]
},
style: {
skinColor: 0xff0000,
skin: {
skinColor: 0xff0000,
skin_up: { imgurl: "../../img/3dImg/rack_door_back.jpg" },
skin_down: { imgurl: "../../img/3dImg/rack_door_back.jpg" },
skin_fore: { skinColor: 0xff0000, imgurl: "../../img/3dImg/rack1.png" },
skin_behind: { skinColor: 0xff0000, imgurl: "../../img/3dImg/rack2.png" },
skin_left: { imgurl: "../../img/3dImg/rack_door_back.jpg" },
skin_right: { imgurl: "../../img/3dImg/rack_door_back.jpg" }
}
}
}
2.2 Virtual Frame with Lighting
Add glowing borders using emissive materials and tube rendering.
var borderModel = THREE.commonFunc.borderLight(serverId);
3.1 Micro-Module Assembly
Arrange cabinets in two rows with spacing equal to 2.5 times cabinet thickness. Pass only cabinet position parameters.
/*
* Retrieve cabinet positions within module
* position: [{1,1,uuid-xxx}, {1,2,uuid-xxx}, ...]
*/
var microModule = THREE.commonFunc.createMicroModule(serverId);
2. Data Center Environment
Define the room using JSON configuration.
[
{
"name": "doorCaseTop",
"objType": "cube",
"length": 220, "width": 24, "height": 5,
"x": -300, "y": 220, "z": -350,
"style": { "skinColor": 9095650, "skin": { "skin_behind": { "skinColor": 13819101 } } }
},
{
"name": "Leftwall",
"objType": "cube",
"length": 20, "width": 810, "height": 240,
"x": 490, "y": 120, "z": 50,
"style": { "skinColor": 9095650 }
},
{
"name": "Rightwall",
"objType": "cube",
"length": 20, "width": 810, "height": 240,
"x": -490, "y": 120, "z": 50,
"style": { "skinColor": 9095650 }
},
{
"name": "forewall",
"objType": "holeCube",
"length": 1000, "width": 20, "height": 240,
"x": 0, "y": 120, "z": -350,
"childrens": [
{ "name": "doorhole", "objType": "cube", "width": 20, "height": 220, "length": 220, "x": -300, "y": -10, "z": 0 },
{ "name": "windowHole", "objType": "cube", "width": 20, "height": 160, "length": 500, "x": 200, "y": 10, "z": 0 }
]
},
{
"name": "floor_2",
"objType": "cube",
"length": 1800, "width": 1600, "height": 10,
"x": 32.156, "y": -8.708, "z": 11.662,
"style": {
"skin": {
"skin_up": { "imgurl": "../../img/3dImg/grasslight-big.jpg" }
}
}
}
]
Other environment elements include:
- Fire extinguishers (loaded from external OBJ JSON)
- Air conditioners (cube with texture)
- Power distribution cabinets
- Desks and chairs (built from tubes and cylinders)
3. Functional Logic
3.1 Single Cabinet Inspection
Open cabinet doors and display server layout.
if (modelBussiness.showSingleServerNeedVitures.length > 0) {
WT3DObj.commonFunc.changeObjsOpacity(modelBussiness.showSingleServerNeedVitures, 0.2, 1, 200, function () {
$.each(modelBussiness.showCabServers, function (_index, _obj) {
_obj.visible = true;
});
});
}
_this.openCabDoor(_obj);
if (modelBussiness.lastMouseInCurrentObj.name.indexOf("OBJCREN7") > 0 ||
modelBussiness.lastMouseInCurrentObj.name.indexOf("OBJCREN8") > 0) {
this.commonFunc.opcabinetBackLeftdoor(_obj.doors.leftDoor);
this.commonFunc.opcabinetBackRightdoor(_obj.doors.rightDoor);
} else if (modelBussiness.lastMouseInCurrentObj.name.indexOf("OBJCREN9") > 0) {
this.commonFunc.opcabinetMaindoor(_obj.doors.mainDoor);
}
setTimeout(function () {
if (_obj.doors.leftDoor.doorState === undefined || _obj.doors.leftDoor.doorState === "close") {
if (_obj.doors.rightDoor.doorState === undefined || _obj.doors.rightDoor.doorState === "close") {
if (_obj.doors.mainDoor.doorState === undefined || _obj.doors.mainDoor.doorState === "close") {
modelBussiness.commonFunc.showCabnetDetail(_obj, function () {});
}
}
}
}, 200);
3.2 Micro-Module Analytics
Display heat maps, space utilization, power, cooling, and load metrics.
{
btnid: "btn_space",
btnTitle: "Cabinet Utilization",
btnimg: "../../img/3dImg/space.png",
sortnub: 0,
btnType: "system",
enable: true,
show_event: function () {
if (modelBussiness.lock == true) {
layer.tips("Currently running: " + modelBussiness.currentLockDetail, "#btn_space");
return;
}
modelBussiness.currentLockDetail = "Cabinet Utilization";
modelBussiness.lock = true;
setTimeout(function () { modelBussiness.lock = false; }, 2000);
modelBussiness.showSpaceRate();
}
},
{
btnid: "btn_temperature",
btnTitle: "Temperature Heatmap",
btnimg: "../../img/3dImg/temperature.png",
sortnub: 0,
btnType: "system",
enable: true,
show_event: function () {
if (modelBussiness.lock == true) {
layer.tips("Currently running: " + modelBussiness.currentLockDetail, "#btn_temperature");
return;
}
modelBussiness.currentLockDetail = "Temperature Heatmap";
modelBussiness.lock = true;
setTimeout(function () { modelBussiness.lock = false; }, 2000);
modelBussiness.showTemptureMap();
}
}
3.3 Server Decommissioning
var _this = modelBussiness;
_this.currentShowServerNames = [];
var cabinetName = cabinetobj.name;
if (_this.Devs[cabinetName] && _this.Devs[cabinetName].devs && _this.Devs[cabinetName].devs.length > 0) {
$.each(_this.Devs[cabinetName].devs, function (_index, _obj) {
_obj.visible = true;
_this.currentShowServerNames.push(_obj.name);
});
} else {
var devJsonModels = [];
if (devs && devs.length > 0) {
$.each(devs, function (_index, _obj) {
var height = (_obj.devURange.max - _obj.devURange.min + 1) * 8.2;
var positiony = height / 2 + 42 + (_obj.devURange.min - 1) * 8.5;
var postioinx = cabinetobj.position.x;
var postioinz = cabinetobj.position.z;
var rotationy = cabinetobj.rotation.y + Math.PI;
var name = cabinetobj.name + "_Server_" + _index;
if (!_obj.devCustomSkin) {
var skins = ["../img/3dImg/server2.jpg", "../img/3dImg/server3.jpg", "../img/3dImg/server1.jpg"];
_obj.devCustomSkin = {
up: "../img/3dImg/rack_inside.jpg",
down: "../img/3dImg/rack_inside.jpg",
fore: skins[parseInt(Math.random() * 3)],
behind: skins[parseInt(Math.random() * 3)],
left: "../img/3dImg/server_side.jpg",
right: "../img/3dImg/server_side.jpg"
};
}
var server = getSingleServerModel(cabinetobj.name + "_Server_" + _index, { "x": postioinx, "y": positiony, "z": postioinz }, height, rotationy, _obj.devId, _obj.devCustomSkin);
server.BindDevId = _obj.devId;
devJsonModels.push(server);
_this.currentShowServerNames.push(name);
});
WT3DObj.commonFunc.loadModelsByJsons(devJsonModels, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, true);
_this.Devs[cabinetName] = {
devs: WT3DObj.commonFunc.findObjectsByNames(_this.currentShowServerNames)
};
}
}
3.4 Server Commissioning
if (_this.needHideCabinets.length > 0) {
WT3DObj.commonFunc.changeCameraPosition({ x: 2531, y: 3967, z: -1150 }, { x: -615, y: 0, z: -35 }, 1000, function () {
$.each(_this.needHideCabinets, function (_index, _obj) {
if (_obj.name.indexOf("_rate_") < 0 && _obj.name.indexOf("_yearCube_") < 0) {
_obj.visible = true;
}
});
});
}
if (_this.needHideobjs.length > 0) {
_this.hideDevs();
WT3DObj.commonFunc.changeCameraPosition({ x: 2531, y: 3967, z: -1150 }, { x: -615, y: 0, z: -35 }, 1000, function () {
$.each(_this.needHideobjs, function (_index, _obj) {
if (_obj.name.indexOf("TCL_line_") < 0 && _obj.name.indexOf("_wind") < 0) {
_obj.visible = true;
if (_obj.children && _obj.children.length > 0) {
$.each(_obj.children, function (_cindex, _cobj) {
_cobj.visible = true;
});
}
}
});
if (_this.currentShowCabinet) {
_this.currentShowCabinet.visible = false;
}
WT3DObj.commonFunc.changeObjsOpacity(_this.needHideobjs, 0.01, 1, 1000, function () {
_this.hideLines();
_this.hideWinds();
_this.hideUsageSpaceRate();
_this.hideSpaceRate();
});
});
}
3.5 Scheduled Server Operations
layer.closeAll();
console.log(result);
var cabNoUse = {};
if (result && result.length && result.length > 0) {
$.each(result, function (_index, _obj) {
var _cab = wtserverAPI.getCabinetByUUID(modelBussiness.roomName, _obj.cabid);
if (_cab && _cab.cabName) {
var ageValue = [];
if (_obj.uPositionUsed && _obj.uPositionUsed.length && _obj.uPositionUsed.length > 0) {
for (var j = 0; j < _obj.uPositionUsed.length - 1; j++) {
if (j == 0) {
ageValue.push({ value: 1, max: _obj.uPositionUsed[0], min: _obj.uPositionUsed[0] });
}
if (_obj.uPositionUsed[j + 1] - _obj.uPositionUsed[j] > 1) {
ageValue.push({ value: 1, max: _obj.uPositionUsed[j + 1], min: _obj.uPositionUsed[j + 1] });
} else {
ageValue[ageValue.length - 1].max = _obj.uPositionUsed[j + 1];
}
}
}
cabNoUse[_cab.cabName] = ageValue;
}
});
}
console.log(cabNoUse);
for (var i = 0; i < allCabs.length; i++) {
var itcobj = WT3DObj.commonFunc.findObject(allCabs[i]);
var ageValue = [];
if (cabNoUse[allCabs[i]]) {
ageValue = cabNoUse[allCabs[i]];
}
var style = { borderColor: 0x4444, outColor: 0xFFFFFF, outOprity: 0.1 };
if (itcobj) {
_this.commonFunc.createUseageCube(allCabs[i],
{ x: 160, y: 380, z: 140 },
{ x: itcobj.position.x, y: itcobj.position.y, z: itcobj.position.z },
{ x: 0, y: 0, z: 0 },
ageValue,
style, { timelogn: 1000 }, i);
}
}