基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块
前言
随着大数据随着大数据时代的来临,物联网的日益发展,原先的 SCADA 系统本身也在求新求变,从最开始的专业计算机和操作系统,到通用计算机和相关软件,再到现在基于 html5 Canvas 的新型组态开发,其应用的范围也从最初的电力,逐渐发展到应用于电力、冶金、化工、自动化群控等等大部分工控场景中,本文是将传统安防结合 SCADA 系统,制作的智能安防中的巡逻监控模块,主要采用 HT for Web 作为开发环境。
代码实现
绘制背景色
首先结合 addBottomPainter() 在 HT 拓扑图形组件 graphView 底层上使用 Canvas 画笔进行绘制背景色。
// 画背景
graphView.addBottomPainter(function (g) {
g.save();
g.beginPath();
g.rect(0, 0, 2000, 1600);
g.fillStyle = "rgb(39,48,74)";
g.fill();
g.restore();
});
加载基础图元
然后将视图背景、人员视角俯视图和提示通过 setImage() 在拓扑组件 graphView 上以图元的形式加载出来,用 setScale() 控制图元的缩放比例使视图更具有真实感,用 setAnchor() 更改锚点,以便旋转时有视角旋转的感觉,最后通过加入 dataModel 的方式使图元加载到拓扑组件 graphView 上,其设计原理是 Object View Mapping (OVM),通过统一的模型驱动视图组件。
// 加载人物基础图元
var people = new ht.Node();
// 设置 Tag
people.setTag(id + 'People');
people.setImage('people');
// 设置缩放倍数
people.setScale(10, 10);
people.setPosition(100, 100);
// 设置锚点
people.setAnchor(.5, .2);
dataModel.add(people);
广州vi设计http://www.maiqicn.com 办公资源网站大全https://www.wode007.com
设置人员属性
将巡逻路径和相关人员属性以对象形式设置,其中巡逻路径按照点的形式保存在 points ,其中的转折逻辑通过 segments 进行控制,其规则如下:
- 1: moveTo,占用1个点信息,代表一个新路径的起点
- 2: lineTo,占用1个点信息,代表从上次最后点连接到该点
- 3: quadraticCurveTo,占用2个点信息,第一个点作为曲线控制点,第二个点作为曲线结束点
- 4: bezierCurveTo,占用3个点信息,第一和第二个点作为曲线控制点,第三个点作为曲线结束点
- 5: closePath,不占用点信息,代表本次路径绘制结束,并闭合到路径的起始点
var people4 = {
id: '437904',
source: {x: 270,y: 352,},
target: {x: 270,y: 352,},
points: [
{x: 262,y: 220,},{x: 380,y: 228,},{x: 509,y: 234,},{x: 509,y: 316,},{x: 513,y: 452,},{x: 382,y: 454,},{x: 278,y: 454,}
],
segments: [1, 3, 3, 3, 3]
};
获得路径上点和角度
通过 getPercentPosition() 和 getPercentAngle() 获得路径 edge 上的点和角度,从而可以通过 setPosition() 控制基础图元位置,再加上动画函数 startAnim() , 从而达到在路径上进行运动旋转的效果。
var position = graphView.getPercentPosition(data, i);
var angle = graphView.getPercentAngle(data, i) - Math.PI * .5;
根据路线转角大小控制图元在转角停留时间
// 转角大小
var rotationAngle = Math.abs((people.getRotation() - angle) % (Math.PI * 2));
// 通过转角大小判断是否需要动画
if (rotationAngle > .2) {
// 判断转角是否大于180度
if (rotationAngle > Math.PI) {
if (people.getRotation() - angle < 0) {
people.setRotation(angle + (Math.PI * 2 - rotationAngle));
} else {
people.setRotation(angle - (Math.PI * 2 - rotationAngle));
}
}
计算路径总距离,控制行进速度
通过路径上各个点的距离计算出总路径然后按距离控制控制路径百分比获得相应的点和旋转角度。
// 计算路径长短
var distance = 0;
for (let i = 0; i + 1 < path.points.length; i++) {
var x = path.points[i + 1].x - path.points[i].x;
var y = path.points[i + 1].y - path.points[i].y;
var pathDistance = Math.sqrt(x * x + y * y);
distance += pathDistance;
}
增加监听显示标记ID
var preMoveData, preClickData;
// 增加鼠标移动标记显示
graphView.getView().addEventListener('mousemove', (e) => {
const data = graphView.getDataAt(e);
if (preMoveData === preClickData && (!data || !data.mark)) return;
if (!data || !data.mark) {
preMoveData && preMoveData.mark && preMoveData.mark.s('2d.visible', false);
return;
}
data.mark.s('2d.visible', true);
preMoveData = data;
});
// 增加鼠标点击标记显示
graphView.mi(e => {
if (e.kind === 'clickData' && e.data.mark) {
preClickData && preClickData.mark.s('2d.visible', false);
e.data.mark.s('2d.visible', true);
if (preClickData === e.data) {
e.data.mark.s('2d.visible', false);
preClickData = undefined;
}else {
preClickData = e.data;
}
}
})