基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块
前言
最近学习了 HT for Web flow 插件,除了正常的 flow 效果,其中还有两个十分好用的两个接口 getPercentPosition() 和 getPercentAngle(), 通过这两个接口可以达到很多的效果,这个 demo 我就是利用这两个接口进行对的巡逻人员的角度位置和速度进行控制。
代码实现
绘制背景色
首先结合 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);
设置人员属性
将巡逻路径和相关人员属性以对象形式设置,其中巡逻路径按照点的形式保存在 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;
}
}
})
总结
flow 是十分适合这种 2d 路线规划,或者是 SCADA 的可视化数据展示,尤其是 getPercentPosition() 和 getPercentAngle() 两个接口, 十分适合用于高自定义的路线可视化图形展示。