上一篇写了基础的2D机柜绘制,今天这篇记录下机柜绘制的进阶篇。本篇主要是就数据封装及机柜界面的优化。
首先是数据封装,正常来说数据的封装不会如上篇那么简单,这里加入更详细的数据用于展示信息,所需封装的数据如下:
//configuration 机柜配置信息
//cabinet_id 机柜id
//u_number 设备所占u信息 格式为 (所占单元起始u-总共占单元数)
//positive_or_negative 表示正反机柜
//left_or_right 设备在单元左右 0为左1为右 不可为null或空 若单元仅一台设备则为0
//device_number 设备编号
//device_category 设备品类
//device_brand 设备品牌
//device_type 设备类型
//device_id 设备id
function sample() {
var array = new Array();
array.push({configuration: '机柜配置信息1', cabinet_id: '1', u_number: '1-21', positive_or_negative: 1, left_or_right: 0, device_number: '设备编号1', device_category: '设备品类1', device_brand:'设备品牌1', device_type: '设备型号1', device_typeId:6, device_id:1});
array.push({configuration: '机柜配置信息2', cabinet_id: '2', u_number: '1-21', positive_or_negative: 1, left_or_right: 1, device_number: '设备编号2', device_category: '设备品类2', device_brand:'设备品牌2', device_type: '设备型号2', device_typeId:6, device_id:2});
array.push({configuration: '机柜配置信息3', cabinet_id: '3', u_number: '24-3', positive_or_negative: 1, left_or_right: 0, device_number: '设备编号3', device_category: '设备品类3', device_brand:'设备品牌3', device_type: '设备型号3', device_typeId:2, device_id:3});
array.push({configuration: '机柜配置信息4', cabinet_id: '4', u_number: '33-3', positive_or_negative: 1, left_or_right: 0, device_number: '设备编号4', device_category: '设备品类4', device_brand:'设备品牌4', device_type: '设备型号4', device_typeId:3, device_id:4});
initCabinet(30, array, 'positiveCabinet');
initCabinet(30, array, 'negativeCabinet');
}
因为我们这个项目当前后台尚未完成,因此这里所展示的字段都是直接从数据库中简单查出来的,这样能够大大简化后台的封装操作同时减少其他开发人员使用本功能时候的使用难度。
调用的方法和第一篇的差不多,只是这里引入了同一单元左右设备的概念。方法改造如下:
for (var i = 0; i < unitArray.length; i++) {
var arrayElement = unitArray[i];//array中的元素
var indexAndLength = arrayElement.u_number.split('-');//设备所占机柜的起始单元及单元总数
var mapKey = indexAndLength[0];//封装设备至map中key为设备起始单元index
var mapElement = map[mapKey];//获取map中的元素
if (typeof(mapElement) == 'undefined') {//起始单元没有数据
mapElement = {};
map[mapKey] = mapElement;
initMap(mapElement);
}
var deviceIndex = arrayElement.left_or_right == '1' ? 1 : 0; //指定数据添加的index
mapElement.content[deviceIndex] = arrayElement.configuration + "," + arrayElement.device_number + "," + arrayElement.device_category + "," + arrayElement.device_brand + "," + arrayElement.device_type;
mapElement.length[deviceIndex] = indexAndLength[1];
mapElement.type[deviceIndex] = arrayElement.device_typeId;
mapElement.cabinetId[deviceIndex] = arrayElement.cabinet_id;
mapElement.deviceId[deviceIndex] = arrayElement.device_id;
mapElement.elementCount += 1;
}
这里数据的封装较上篇来说,最大的不同就是存入map的value由原来的单一数值变成了数组,用以处理同单元存在两个设备的情况。下面贴上初始化map元素的方法:
//初始化map
function initMap(map) {
var contentList = new Array(); contentList.push('-1', '-1');//设备内容
var lengthList = new Array(); lengthList.push('-1', '-1');//设备所占单元数
var typeList = new Array(); typeList.push('-1', '-1');//设备类型,用于决定图片
var cabinetIdList = new Array(); typeList.push('-1', '-1');
var deviceIdList = new Array(); typeList.push('-1', '-1');
map.content = contentList;
map.length = lengthList;
map.type = typeList;
map.cabinetId = cabinetIdList;
map.deviceId = deviceIdList;
map.elementCount = 0;//初始化单元设备数量
}
注意这里封装好的map的key不是最终的key因为存在同单元多个设备的情况,因此我们需要在数据初步封装完成后再次循环map确认每组设备实际所占的单元个数。
var mapFinal = {};
for (var key in map) {
var mapEl = map[key];//获取map元素
var elCount = mapEl.elementCount;
var mapIndex = -1;//最终map的index
if (elCount == 1) {
mapIndex = parseInt(key) + parseInt(mapEl.length[0]) - 1;
}else{
mapIndex = parseInt(key) + (parseInt(mapEl.length[0]) < parseInt(mapEl.length[1]) ? parseInt(mapEl.length[1]) : parseInt(mapEl.length[0])) - 1;
}
mapFinal[mapIndex] = mapEl;
}
封装好数据之后循环unit总数如上篇一样处理即可:
for (var i = unitCount; i >= 1; i--) {
if (typeof(mapFinal[i]) == 'undefined') {
content += '<div class="areaBlock" align="center" data-geo=""><div class="blockFont">' + i + '</div></div>'
} else {
var deviceCount = mapFinal[i].elementCount;
if (deviceCount == '1'){
var length = parseInt(mapFinal[i].length[0]);
var type = mapFinal[i].type[0];
var height = blockHeight * (length) + blockInterval * (length - 1) + 'px';
var deviceContent = mapFinal[i].content[0];
var cabinetId = mapFinal[i].cabinetId[0];
var deviceId = mapFinal[i].deviceId[0];
i -= (length - 1);
content += '<div class="areaBlockWithImg" align="center" style="height: ' + height + ';background-image: url('+ initImg(type) +')" data-geo="" onclick="deviceOnclick(' + cabinetId + ',' + deviceId + ')">' + '<input id="content" type="hidden" value="' + deviceContent+'">' + '</div>'
}else{
var lengthLeft = parseInt(mapFinal[i].length[0]);//左边设备所占单元数
var typeLeft = mapFinal[i].type[0];//左边设备类型
var deviceContentLeft = mapFinal[i].content[0];//左边设备信息
var cabinetIdLeft = mapFinal[i].cabinetId[0];
var deviceIdLeft = mapFinal[i].deviceId[0];
var lengthRight = parseInt(mapFinal[i].length[1]);//右边设备所占单元数
var typeRight = mapFinal[i].type[1];//右边设备类型
var deviceContentRight = mapFinal[i].content[1];//右边设备信息
var cabinetIdRight = mapFinal[i].cabinetId[1];
var deviceIdRight = mapFinal[i].deviceId[1];
var length = lengthLeft > lengthRight ? lengthLeft : lengthRight;//取两个设备所占单元最大数
var height = blockHeight * (length) + blockInterval * (length - 1) + 'px';//指定高度
i -= (length - 1);
content += '<div class="areaBlock" style="height: '+ height +'">';
content += '<div class="areaBlockWithDoubleDeviceLeft" style="background-image: url('+ initImg(typeLeft) +')" data-geo="" onclick="deviceOnclick(' + cabinetIdLeft + ',' + deviceIdLeft + ')">' + '<input id="content" type="hidden" value="' + deviceContentLeft +'">' + '</div>';
content += '<div class="areaMiddleBlock"></div>'
content += '<div class="areaBlockWithDoubleDeviceRight" style="background-image: url('+ initImg(typeRight) +')" data-geo="" onclick="deviceOnclick(' + cabinetIdRight + ',' + deviceIdRight + ')">' + '<input id="content" type="hidden" value="' + deviceContentRight +'">' + '</div>';
content += '</div>';
}
}
}
这里再做一个显示方面的优化,正常一个设备tooltip是显示在右侧,如果有两个设备并且都显示在右侧那么就显得不友好,因此这里也设置两种不同的tooltip用于不同位置的设备:
//初始化tooltip
function initTooltip(unitCount) {
var leftPositionOffset = 'right-'+ (32+Math.abs(parseInt(unitCount)-40)/2*3)+' center';
$('.areaBlockWithDoubleDeviceLeft').tooltip({
position: {my: leftPositionOffset, at: "left center"},
items: "[data-geo]",
content: function () {
var element = $(this);
var deviceContent = '';
if (typeof(this.getElementsByTagName('input')[0]) != 'undefined') {
deviceContent = this.getElementsByTagName('input')[0].value;
}
if (element.is("[data-geo]")) {
var text = deviceContent == ''? element.text().split(',') : deviceContent.split(',');
return showInfo(text);
}
}
});
$('.areaBlockWithDoubleDeviceRight, .areaBlock, .areaBlockWithImg').tooltip({
position: {my: "left+50 center", at: "right center"},
items: "[data-geo]",
content: function () {
var element = $(this);
var deviceContent = '';
if (typeof(this.getElementsByTagName('input')[0]) != 'undefined') {
deviceContent = this.getElementsByTagName('input')[0].value;
}
if (element.is("[data-geo]")) {
var text = deviceContent == ''? element.text().split(',') : deviceContent.split(',');
return showInfo(text);
}
}
});
}
这样一来最终的效果图如下:
这里贴下完整的js代码:
//map元素字段说明
//content 单元设备信息 list
//length 单元设备所占单元数 list
//type 单元设备类别 list
//elementCount 单元设备数量 int 若数量为1则处理所有数组第一个元素
function initCabinet(unitCount, unitArray, cabinetBlockId) {
var blockInterval = 3;//单元的间隔
var blockHeight = 12;//单元高度
var map = {};
for (var i = 0; i < unitArray.length; i++) {
var arrayElement = unitArray[i];//array中的元素
var indexAndLength = arrayElement.u_number.split('-');//设备所占机柜的起始单元及单元总数
var mapKey = indexAndLength[0];//封装设备至map中key为设备起始单元index
var mapElement = map[mapKey];//获取map中的元素
if (typeof(mapElement) == 'undefined') {//起始单元没有数据
mapElement = {};
map[mapKey] = mapElement;
initMap(mapElement);
}
var deviceIndex = arrayElement.left_or_right == '1' ? 1 : 0; //指定数据添加的index
mapElement.content[deviceIndex] = arrayElement.configuration + "," + arrayElement.device_number + "," + arrayElement.device_category + "," + arrayElement.device_brand + "," + arrayElement.device_type;
mapElement.length[deviceIndex] = indexAndLength[1];
mapElement.type[deviceIndex] = arrayElement.device_typeId;
mapElement.cabinetId[deviceIndex] = arrayElement.cabinet_id;
mapElement.deviceId[deviceIndex] = arrayElement.device_id;
mapElement.elementCount += 1;
}
var mapFinal = {};
for (var key in map) {
var mapEl = map[key];//获取map元素
var elCount = mapEl.elementCount;
var mapIndex = -1;//最终map的index
if (elCount == 1) {
mapIndex = parseInt(key) + parseInt(mapEl.length[0]) - 1;
}else{
mapIndex = parseInt(key) + (parseInt(mapEl.length[0]) < parseInt(mapEl.length[1]) ? parseInt(mapEl.length[1]) : parseInt(mapEl.length[0])) - 1;
}
mapFinal[mapIndex] = mapEl;
}
var parentBlockHeight = (blockHeight + blockInterval) * unitCount + 'px';
$('.parentBlock').css('height', parentBlockHeight);
var content = "";
for (var i = unitCount; i >= 1; i--) {
if (typeof(mapFinal[i]) == 'undefined') {
content += '<div class="areaBlock" align="center" data-geo=""><div class="blockFont">' + i + '</div></div>'
} else {
var deviceCount = mapFinal[i].elementCount;
if (deviceCount == '1'){
var length = parseInt(mapFinal[i].length[0]);
var type = mapFinal[i].type[0];
var height = blockHeight * (length) + blockInterval * (length - 1) + 'px';
var deviceContent = mapFinal[i].content[0];
var cabinetId = mapFinal[i].cabinetId[0];
var deviceId = mapFinal[i].deviceId[0];
i -= (length - 1);
content += '<div class="areaBlockWithImg" align="center" style="height: ' + height + ';background-image: url('+ initImg(type) +')" data-geo="" onclick="deviceOnclick(' + cabinetId + ',' + deviceId + ')">' + '<input id="content" type="hidden" value="' + deviceContent+'">' + '</div>'
}else{
var lengthLeft = parseInt(mapFinal[i].length[0]);//左边设备所占单元数
var typeLeft = mapFinal[i].type[0];//左边设备类型
var deviceContentLeft = mapFinal[i].content[0];//左边设备信息
var cabinetIdLeft = mapFinal[i].cabinetId[0];
var deviceIdLeft = mapFinal[i].deviceId[0];
var lengthRight = parseInt(mapFinal[i].length[1]);//右边设备所占单元数
var typeRight = mapFinal[i].type[1];//右边设备类型
var deviceContentRight = mapFinal[i].content[1];//右边设备信息
var cabinetIdRight = mapFinal[i].cabinetId[1];
var deviceIdRight = mapFinal[i].deviceId[1];
var length = lengthLeft > lengthRight ? lengthLeft : lengthRight;//取两个设备所占单元最大数
var height = blockHeight * (length) + blockInterval * (length - 1) + 'px';//指定高度
i -= (length - 1);
content += '<div class="areaBlock" style="height: '+ height +'">';
content += '<div class="areaBlockWithDoubleDeviceLeft" style="background-image: url('+ initImg(typeLeft) +')" data-geo="" onclick="deviceOnclick(' + cabinetIdLeft + ',' + deviceIdLeft + ')">' + '<input id="content" type="hidden" value="' + deviceContentLeft +'">' + '</div>';
content += '<div class="areaMiddleBlock"></div>'
content += '<div class="areaBlockWithDoubleDeviceRight" style="background-image: url('+ initImg(typeRight) +')" data-geo="" onclick="deviceOnclick(' + cabinetIdRight + ',' + deviceIdRight + ')">' + '<input id="content" type="hidden" value="' + deviceContentRight +'">' + '</div>';
content += '</div>';
}
}
}
$('#'+cabinetBlockId).append(content);
initTooltip(unitCount);
}
//初始化tooltip
function initTooltip(unitCount) {
var leftPositionOffset = 'right-'+ (32+Math.abs(parseInt(unitCount)-40)/2*3)+' center';
leftPositionOffset = 'right-50 center';
$('.areaBlockWithDoubleDeviceLeft').tooltip({
position: {my: leftPositionOffset, at: "left center"},
items: "[data-geo]",
content: function () {
var element = $(this);
var deviceContent = '';
if (typeof(this.getElementsByTagName('input')[0]) != 'undefined') {
deviceContent = this.getElementsByTagName('input')[0].value;
}
if (element.is("[data-geo]")) {
var text = deviceContent == ''? element.text().split(',') : deviceContent.split(',');
return showInfo(text);
}
}
});
$('.areaBlockWithDoubleDeviceRight, .areaBlock, .areaBlockWithImg').tooltip({
position: {my: "left+50 center", at: "right center"},
items: "[data-geo]",
content: function () {
var element = $(this);
var deviceContent = '';
if (typeof(this.getElementsByTagName('input')[0]) != 'undefined') {
deviceContent = this.getElementsByTagName('input')[0].value;
}
if (element.is("[data-geo]")) {
var text = deviceContent == ''? element.text().split(',') : deviceContent.split(',');
return showInfo(text);
}
}
});
}
//设备点击事件
function deviceOnclick(cabinetId, deviceId) {
alert('机柜id:' + parseInt(cabinetId) + ', 设备id:' + parseInt(deviceId))
}
//显示设备信息
function showInfo(text) {
var content = '';
if (text.length == 5) {
content += "<div>" + text[1] + "</div><div>" + text[2] + "</div><div>" + text[3] + "</div>";
} else {
content += "<div>单元 " + text[0] + " 可使用</div>";
}
return content;
}
//初始化设备图片
function initImg(deviceType) {
var img = 'img/deviceImg/';
switch (deviceType){
case 1://路由器
img += 'root/cisioRoot1.png';
break;
case 2://安全设备
img += 'securityDevice/fireWall1.jpg';
break;
case 3://服务器
img += 'server/dellServer1.jpg';
break;
case 4://存储设备
img += 'storeDevice/storeDevice1.jpg';
break;
case 5://交换机
img += 'swap/dellSwap1.png';
break;
case 6://塔式服务器
img += 'towerServer/dellTowerServer1.jpg';
break;
default://默认
img += 'defaultDevice.jpg';
break;
}
return img;
}
//初始化map
function initMap(map) {
var contentList = new Array(); contentList.push('-1', '-1');//设备内容
var lengthList = new Array(); lengthList.push('-1', '-1');//设备所占单元数
var typeList = new Array(); typeList.push('-1', '-1');//设备类型,用于决定图片
var cabinetIdList = new Array(); typeList.push('-1', '-1');
var deviceIdList = new Array(); typeList.push('-1', '-1');
map.content = contentList;
map.length = lengthList;
map.type = typeList;
map.cabinetId = cabinetIdList;
map.deviceId = deviceIdList;
map.elementCount = 0;//初始化单元设备数量
}
这样基本上可以直接将数据库中获取的数据直接进行处理而不用后端再做更多复杂的处理。
如果后面有更复杂的需求后续还会更新。