htxzs

前言:

储油罐是采油、炼油企业储存油品的重要设备,储油罐液位、温度的精确计量对企业的库存和安全管理有着重大意义。这种可视化的模型储油罐液位、温度在线监测系统改变了传统采用可视化模型界面,实现了油液的实时动态监测,为生产操作和管理决策提供了准确的数据依据,大大避免了安全事故的发生。

 HT for Web 官方网站:http://www.hightopo.com/   感兴趣的朋友可以去官网看看,里面有很多很有趣的项目。

代码部分:

先来看左边的油罐模型,它是由阀门,罐体,和管道若干构成的。这里我使用了 HT 编辑器绘制了这些组件,并将需要的数据进行了绑定。比如油罐罐体上的百分比,就是在编辑器内部绑定了一个方法,再由编辑器自动生成罐体的 JSON 文件,之后再将油罐图标和其他组件的图标共同构成一个图纸,用户只需要将图纸 JSON 文件反序列化,就可以在页面中显示图纸的内容了。如下是编辑器自动生成的图纸 JSON 文件:

{
  "v": "6.2.5",
  "p": {
    "layers": [
      {
        "name": "0",
        "visible": true,
        "selectable": true,
        "movable": true,
        "editable": true
      },
      {
        "name": "b",
        "visible": true,
        "selectable": true,
        "movable": true,
        "editable": true
      }
    ],
    "autoAdjustIndex": true,
    "hierarchicalRendering": true
  },
  "a": {
    "connectActionType": null
  },
  "d": [
    {
      "c": "ht.Node",
      "i": 43243,
      "p": {
        "displayName": "阀门",
        "layer": "b",
        "tag": "1003",
        "image": "json/tap.json",
        "position": {
          "x": 107.04556,
          "y": 116.30496
        },
        "width": 22.2555,
        "height": 15.89827
      }
    },
    {
      "c": "ht.Shape",
      "i": 43244,
      "p": {
        "position": {
          "x": 71.2996,
          "y": 118.12154
        },
        "width": 53.6712,
        "height": 1,
        "segments": {
          "__a": [
            1,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 44.464,
              "y": 118.12154
            },
            {
              "x": 98.1352,
              "y": 118.12154
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Shape",
      "i": 43245,
      "p": {
        "position": {
          "x": 142.37464,
          "y": 117.89698
        },
        "width": 53.44663,
        "height": 1,
        "segments": {
          "__a": [
            1,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 115.65132,
              "y": 118.12154
            },
            {
              "x": 169.09795,
              "y": 117.67241
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Shape",
      "i": 43246,
      "p": {
        "position": {
          "x": 211.09173,
          "y": 115.87589
        },
        "width": 45.8114,
        "height": 35.03224,
        "segments": {
          "__a": [
            1,
            2,
            2,
            2,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 188.18603,
              "y": 117.44785
            },
            {
              "x": 198.51605,
              "y": 117.22328
            },
            {
              "x": 198.51605,
              "y": 133.39201
            },
            {
              "x": 198.74062,
              "y": 98.8089
            },
            {
              "x": 233.99743,
              "y": 98.35976
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Shape",
      "i": 43247,
      "p": {
        "position": {
          "x": 123.6234,
          "y": 125.75678
        },
        "width": 1,
        "height": 15.7196,
        "segments": {
          "__a": [
            1,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 123.51112,
              "y": 117.89698
            },
            {
              "x": 123.73568,
              "y": 133.61657
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Node",
      "i": 43248,
      "p": {
        "displayName": "油罐",
        "layer": "b",
        "tag": "1001",
        "dataBindings": {
          "p": {}
        },
        "image": "json/oil.json",
        "position": {
          "x": 123.02107,
          "y": 185.15576
        }
      }
    },
    {
      "c": "ht.Text",
      "i": 43249,
      "p": {
        "position": {
          "x": 107.04556,
          "y": 106.11657
        },
        "width": 17.82073,
        "height": 7.48388
      },
      "s": {
        "text": "OPEN",
        "text.font": "5px arial, sans-serif"
      }
    },
    {
      "c": "ht.Text",
      "i": 43250,
      "p": {
        "position": {
          "x": 177.7828,
          "y": 106.11657
        },
        "width": 24.84864,
        "height": 9.50497
      },
      "s": {
        "text": "CLOSED",
        "text.font": "5px arial, sans-serif",
        "text.color": "rgb(217,217,217)"
      }
    },
    {
      "c": "ht.Shape",
      "i": 43251,
      "p": {
        "position": {
          "x": 123.02107,
          "y": 224.35038
        },
        "width": 1,
        "height": 53.08572,
        "segments": {
          "__a": [
            1,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 122.91873,
              "y": 197.80752
            },
            {
              "x": 123.1234,
              "y": 250.89324
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Text",
      "i": 43252,
      "p": {
        "position": {
          "x": 283.74301,
          "y": 250.89324
        },
        "width": 32.25391,
        "height": 9.83265
      },
      "s": {
        "text": "Dye Tank 2",
        "text.font": "5px arial, sans-serif",
        "text.align": "center",
        "text.color": "rgb(247,247,247)"
      }
    },
    {
      "c": "ht.Shape",
      "i": 43253,
      "p": {
        "position": {
          "x": 198.11968,
          "y": 224.48984
        },
        "width": 1,
        "height": 53.08572,
        "segments": {
          "__a": [
            1,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 198.01734,
              "y": 197.94698
            },
            {
              "x": 198.22201,
              "y": 251.0327
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Shape",
      "i": 43254,
      "p": {
        "position": {
          "x": 106.17145,
          "y": 258.47692
        },
        "width": 183.90411,
        "height": 16.4313,
        "segments": {
          "__a": [
            1,
            2,
            2,
            2
          ]
        },
        "points": {
          "__a": [
            {
              "x": 14.21939,
              "y": 250.26127
            },
            {
              "x": 123.23472,
              "y": 250.26127
            },
            {
              "x": 198.1235,
              "y": 250.26127
            },
            {
              "x": 198.1235,
              "y": 266.69256
            }
          ]
        }
      },
      "s": {
        "shape.background": null,
        "shape.border.color": "rgb(217,217,217)",
        "shape.border.width": 2
      }
    },
    {
      "c": "ht.Node",
      "i": 43255,
      "p": {
        "displayName": "油罐",
        "tag": "1002",
        "layer": "b",
        "image": "json/oil.json",
        "position": {
          "x": 198.1235,
          "y": 186.11658
        }
      }
    },
    {
      "c": "ht.Node",
      "i": 43256,
      "p": {
        "displayName": "阀门",
        "tag": "1004",
        "layer": "b",
        "image": "json/tap.json",
        "position": {
          "x": 177.7828,
          "y": 115.65773
        },
        "width": 24.84864,
        "height": 15.04013
      }
    }
  ],
  "contentRect": {
    "x": 0,
    "y": 0
    
  }
}

 如下是油罐图标的自动生成的 JSON 文件,油罐里包含了罐体和其下方的数据标识,里面的 function 为了在解析时区别出来,编辑器自动转成 __ht__function 的格式:

{
  "width": 47,
  "height": 105,
  "comps": [
    {
      "type": "rect",
      "background": "#D8D8D8",
      "borderWidth": 1,
      "borderColor": "rgb(204,202,202)",
      "rect": [
        6.54899,
        0.6234,
        35,
        64
      ]
    },
    {
      "type": "rect",
      "background": {
        "func": "attr@oilColor",
        "value": "rgb(124,235,128)"
      },
      "borderColor": "#979797",
      "rect": [
        10.54899,
        4.59114,
        27,
        56
      ]
    },
    {
      "type": "rect",
      "background": "rgb(247,247,247)",
      "borderColor": "#979797",
      "anchorX": 0.47277,
      "rect": {
        "func": "__ht__function(data, view) {\nreturn [10.54899,4.59114,27,56 - data.a(\'percent\') * 0.56];\n}",
        "value": [
          10.54899,
          4.59114,
          27,
          35
        ]
      }
    },
    {
      "type": "text",
      "text": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'percent\') + \" %\";\n}",
        "value": "100%"
      },
      "align": "center",
      "font": "8px arial, sans-serif",
      "rect": [
        10.54899,
        39.59114,
        27,
        15.3783
      ]
    },
    {
      "type": "rect",
      "background": "rgb(57,137,173)",
      "borderColor": "#979797",
      "rect": [
        1.09799,
        69.25901,
        45.90201,
        10.69561
      ]
    },
    {
      "type": "text",
      "rect": [
        -7.40554,
        49.60682,
        50,
        50
      ]
    },
    {
      "type": "text",
      "text": {
        "func": "attr@tankNum",
        "value": "Dye Tank 1"
      },
      "align": "center",
      "color": "rgb(247,247,247)",
      "font": "5px arial, sans-serif",
      "rect": [
        1.09799,
        69.25901,
        45.90201,
        10.69561
      ]
    },
    {
      "type": "rect",
      "background": "rgb(57,137,173)",
      "borderColor": "#979797",
      "rect": [
        1.09799,
        82.0579,
        45.90201,
        10.69561
      ]
    },
    {
      "type": "text",
      "text": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'percent\') + \" %\";\n}",
        "value": "48 %"
      },
      "align": "center",
      "color": "rgb(48,242,120)",
      "font": "5px arial, sans-serif",
      "rect": [
        1.09799,
        82.0579,
        45.90201,
        10.69561
      ]
    },
    {
      "type": "rect",
      "background": "rgb(57,137,173)",
      "borderColor": "#979797",
      "rect": [
        1.09799,
        94.25901,
        45.90201,
        10.69561
      ]
    },
    {
      "type": "text",
      "text": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'temp\') + \' ℉\';\n}",
        "value": "100"
      },
      "align": "center",
      "color": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'temp\') > 75 ? \"rgb(242, 83, 75)\" : \"rgb(48, 242, 120)\";\n}",
        "value": "rgb(48,242,120)"
      },
      "font": "5px arial, sans-serif",
      "rect": [
        15.44196,
        94.30439,
        16.66947,
        10.69561
      ]
    },
    {
      "type": "text",
      "color": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'temp\') > 75 ? \"rgb(242, 83, 75)\" : \"rgb(48, 242, 120)\";\n}",
        "value": "rgb(48,242,120)"
      },
      "font": "5px arial, sans-serif",
      "rect": [
        22.59446,
        94.30439,
        11.5503,
        10.69561
      ]
    },
    {
      "type": "oval",
      "background": "rgb(212,0,0)",
      "borderColor": "#979797",
      "visible": {
        "func": "__ht__function(data, view) {\nreturn data.a(\'temp\') > 75 ? true : false;\n}",
        "value": true
      },
      "editable": false,
      "rect": [
        34.3647,
        95.70692,
        8.51093,
        7.89055
      ]
    }
  ]
}

需要导入一些 js 的类库,如下:

<script src="../ht/lib/ht.js"></script>
<script src="../ht/lib/ht-ui.js"></script>

 

之后我用了 ht.Default 的工具函数 xhrLoad 异步向服务器发送请求,获得了这段 JSON ,将 JSON 反序列化得到数据存进数据模型中,并且给油罐对象的绑定属性赋初始值。这里注意 xhrLoad 请求是异步的,所以给对象赋初始值的时候要在 xhrLoad 的返回函数内部执行,否则可能在执行时还没反序列化完成,就开始获取对象的属性并赋值,就会出现获取不到对象的错误。

dataModel = new ht.DataModel();
ht.Default.xhrLoad(\'oilTank.json\', function(text) {
	var json = ht.Default.parse(text);
	dataModel.deserialize(json);
	dataModel.getDataByTag(\'1004\').a(\'tapColor\', \'rgb(217, 217, 217)\');
	dataModel.getDataByTag(\'1002\').a(\'oilColor\', \'rgb(247, 213, 161)\');
	for(var i = 1; i < 3; ++i){	
		let data = dataModel.getDataByTag(\'100\' + i);
		data.a(\'percent\', 10);					
		data.a(\'temp\', 37);
		data.a(\'tankNum\', \'Dye Tank \' + i);
		data.a(\'presure\', 132);
		data.a(\'alarms\', \'- -\');
		data.a(\'status\', status[0]);					
	}
});

 

再来看右边的表格,我采用的是在外部用一个 Panel 将表格放到里面,再设计表格的列,因为表格内容实际上是对油罐状态的数据显示,他们可以共享同一个 DataModel ,但由于图纸上每一个组件都会对应一个数据,这在获取油罐数据时会造成麻烦,于是我在表格获取数据之前增加了一个过滤器,用来过滤掉一些不需要的数据:

tableView.setVisibleFunc(function(data) {
	if(data.getTag() === \'1001\' || data.getTag() === \'1002\') {
		return true;
	}
	return false;	
});

 

 然后再设计表格的列,从 DataModel 获取数据并添加到列中:

tablePane = new ht.ui.TablePane(dataModel);
tableView = tablePane.getTableView();	
columnModel = tableView.getColumnModel();	

var status = [
	\'ATUO\',
	\'OFF\'
];									
var column = new ht.ui.Column();
column.setName(\'tankNum\');
column.setDisplayName(\'Name\');
column.setAccessType(\'attr\');
columnModel.add(column);

column = new ht.ui.Column();
column.setName(\'temp\');
column.setAccessType(\'attr\');
column.setDisplayName(\'TEMP\');
column.setAlign(\'center\');
column.formatValue = function(value, data) {
	return data.a(\'temp\') + \' ℉\';
};
column.setEditable(true);
column.setEditorClass(\'ht.ui.editor.NumberEditor\');
columnModel.add(column);

column = new ht.ui.Column();
column.setName(\'presure\');
column.setAccessType(\'attr\');
column.setDisplayName(\'Presure\');
column.formatValue = function(value, data) {
	return data.a(\'presure\') + \' PSI\';
}
column.setEditable(true);
column.setEditorClass(\'ht.ui.editor.IntEditor\');
columnModel.add(column);

column = new ht.ui.Column();
column.setName(\'alarms\');
column.setDisplayName(\'Alarms\');
column.setAccessType(\'attr\');
column.setValue = function(value, data) {
	return data.a(\'alarms\');
}
columnModel.add(column);

column = new ht.ui.EnumColumn();
column.setDatas(status);
column.setName(\'status\');
column.setDisplayName(\'Status\');
column.setAccessType(\'attr\');
column.setEditable(true);
columnModel.add(column);

 在表格中,为了增加表格的效果,我在温度过高时将该行的颜色进行了调整,对工作人员进行提醒,再把表格加入到到 Panel 组件中,并给 Panel 加上了标题

tableView.drawRowBackground = function(drawable, x, y, width, height, data) {
	var g = tableView.getRootContext();
	if(tableView.isSelected(data)) {
		g.fillStyle = \'#87A6CB\';
	}
	else if(data.a(\'temp\') < 65) {
		g.fillStyle = \'rgb(247, 247, 247)\';
	}
	else if(data.a(\'temp\') >= 65 && data.a(\'temp\') < 90) {
		g.fillStyle = \'rgb(247, 204, 139)\';
	}
	else {
		g.fillStyle = \'rgb(242, 83, 75)\';
	}
	g.beginPath();
	g.rect(x, y, width, height);
	g.fill();
};
panel.setTitle(\'TANK STATUS OVERVIEW\');	
panel.setContentView(tablePane);

 

最后来说说模型的总体布局,这个模型的主体是左边的油罐模型和右边的表格,表格的数据全都来源于油罐,于是他们共同属于同一个数据容器。那么首先先来看这个模型的整体布局,我采用的是 ht-ui.js 库里面的相对布局器,并且设置了左边油罐模型的位置让整个结构看起来更合理,于是整个的布局代码如下:

relativeLayout = new ht.ui.RelativeLayout();
graphView = new ht.graph.GraphView(dataModel);
graphView.setZoom(2.292);
graphView.setTranslate(297, -178);
panel = new ht.ui.Panel();
panel.setBorder(0);

relativeLayout.addView(new ht.ui.HTView(graphView), {
	align:\'left\',
	vAlign: \'middle\',
	width: \'match_parent\',
	height: \'match_parent\'
});
relativeLayout.addView(panel, {
	align: \'right\',
	vAlign: \'top\',
	marginTop: 30,
	marginRight: 30,
	width: 500,
	height: 150
});

总结:在写这个小例子的时候遇到了问题,编辑器使用的不够熟练,一些属性不了解,每一种都得测试完才知道它是干嘛用的,花费了不少时间;还有属性面板上的简化属性按钮,在写的时候没取消,导致了很多本来可以直接设置的属性,自己手动进行添加。还有很多操作都是异步的,例如 xhrLoad 加载 JSON 等等...以后必须得更加留意异步问题。数据模型的问题:思考不同图形是否能加在同一个 Node 下,例如罐体和罐体下方的数据条;思考组件是否能加载同一个 DataModel ,例如左侧油罐模型和右侧的数据表格。通过这个小例子也确实学习到了很多东西,希望在未来的日子里努力变得越来越优秀,与大家共勉。

 

分类:

技术点:

相关文章:

  • 2021-08-07
  • 2021-06-28
  • 2020-11-06
  • 2022-02-13
  • 2021-12-23
  • 2021-08-14
  • 2021-11-30
猜你喜欢
  • 2021-11-18
  • 2021-10-05
  • 2021-11-23
  • 2021-11-05
  • 2021-11-02
  • 2021-10-16
相关资源
相似解决方案