百度地图上设置挖空效果的电子围栏
更新时间: 2024-04-15 09:24:01
公司项目有个需求是要在百度地图上设置电子围栏,电子围栏很简单嘛,就是一个覆盖物就能搞定了,然而UI又在搞事情,设计的效果图中电子围栏外卖填充颜色,电子围栏内不填充颜色。
最后我还是写出了这个效果,浅浅的复盘一下:
狗狗太可爱了给他用电子围栏描个边边
我是怎么做到的呢,我使用的还是百度地图的CanvasLayer:
然后利用canvas绘图的一个特性:
绘制路径的时候,如果两个路径的方向不一致,就会出现挖空的效果,所以就让外面罩住屏幕的大框是顺时针,电子围栏的路径是逆时针。
至于怎么判断是顺时针还是逆时针,写在另一篇文章里 判断路径是顺时针还是逆时针
# 实现
实现大致就这样几个步骤:
- 以顺时针定义外部矩形的路径,我使用了zrender作为绘图库
- 计算电子围栏的路径是顺时针还是逆时针,如果是顺时针就将路径的点翻转一下成为逆时针拼接在矩形路径后
需要注意的是,我们在计算路径是否顺时针的时候,是用经纬度去计算,然后再用百度地图的api将经纬度转换为实际屏幕像素位置拼接在矩形路径后面。
zr = null
var canvasLayer = new BMap.CanvasLayer({
update: function () {
if (!zr) {
zr = zrender.init(this.canvas); //初始化zrender
}
const canvasWidth = zr.getWidth()
const canvasHeight = zr.getHeight()
zr.clear() //先清空之前画的
zr.resize()
// 这是外部大框的路径,这个大框实际尺寸超出canvas
let pathString = `M -10,-10 L ${canvasWidth + 10},-10 L ${canvasWidth + 10} ${canvasHeight + 10} L -10 ${canvasHeight + 10} Z `
let pixiPos = [[117.74870031429617,38.93620960719094],[117.75249116354829,38.934132767812294],[117.74976031479795,38.929557891809644],[117.74505319392566,38.93087705835964]]
let reversepixiPos = []
// 将原始路径改为顺时针
if (!isClockwise(pixiPos)) {
pixiPos = pixiPos.reverse()
}
// 将经纬度转换为像素
pixiPos = pixiPos.map(item => {
const {x, y} = map.pointToPixel(new BMap.Point(...item))
return [x, y]
})
// 翻转路径为逆时针
reversepixiPos = pixiPos.reverse()
// 拼接路径
for (let i = 0; i < reversepixiPos.length; i++) {
if (i === 0) {
pathString += `M ${reversepixiPos[i][0]} ${pixiPos[i][1]} `
} else {
pathString += `L ${reversepixiPos[i][0]} ${pixiPos[i][1]} `
}
if (i === reversepixiPos.length - 1) {
pathString += 'Z'
}
}
}
// 判断路径是顺时针还是逆时针,逆时针返回正,顺时针返回负
function isClockwise(points) {
var maxXIndex = 0;
var maxX = points[maxXIndex][0];
var c1,c2,c3;
var x1,y1,x2,y2,x3,y3;
for(var i=0;i<points.length;i++){
if(points[i][0]>maxX){
maxX = points[i][0]
maxXIndex = i;
}
}
if(maxXIndex==0){
c1 = points[points.length-1];
c2 = points[maxXIndex];
c3 = points[maxXIndex+1];
}else if(maxXIndex==points.length-1){
c1 = points[maxXIndex-1];
c2 = points[maxXIndex];
c3 = points[0];
}else {
c1 = points[maxXIndex-1];
c2 = points[maxXIndex];
c3 = points[maxXIndex+1];
}
x1 = c1[0];
y1 = c1[1];
x2 = c2[0];
y2 = c2[1];
x3 = c3[0];
y3 = c3[1];
var s = ((x1-x3)*(y2-y3)-(x2-x3)*(y1-y3));
return s<0;
}
// 使用zrender绘制路径
var mask = zrender.path.createFromString(pathString,{
style: {
fill: 'rgba(0,0,0,0.5)',
stroke: '#FF5959',
lineWidth:6,
lineDash:12
}
})
zr.add(mask)
},
// 定义图层在上层
paneName: 'floatPane'
});
map.addOverlay(canvasLayer);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97