需求描述:
使用高德地图,实现类似下图中多个圆角多边形热点区域叠加的效果
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ImageLayer</title>
<meta id="viewport" name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0"/>
<style>
html,
body,
#container {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="//webapi.amap.com/maps?v=2.0&key=您申请的key值"></script>
<script>
var map = new AMap.Map('container', {
viewMode:"2D",
zoom: 14,
mapStyle: "amap://styles/darkblue",
center: [116.335183, 39.941735]
});
// map.setBounds([116.316279,39.92724,116.354087,39.956227]);
/*
* 添加Canvas图层
*/
var canvas = document.createElement('canvas');
canvas.width = 871;
canvas.height = 876;
var ctx = canvas.getContext("2d");
function draw() {
const p = [
[15, 20],
[20, 200],
[200, 300],
[300, 100],
[200, 20],
];
const p1 = [
[300,50],
[400,50],
[350,150]
]
const test = [
[353,236],
[676,332],
[567,641],
[342,758],
[159,553],
[356,437]
]
// drawRect(p, 30, ctx, 'rgb(0, 0, 0)', 0.6);
// drawRect(p1, 10, ctx, 'rgb(20, 230, 240)', 0.8);
drawRect(test, 50, ctx, '#FFB503', 0.3);
}
function drawRect(p, radius, ctx, color, alpha) {
ctx.beginPath();
const startPoint = [
(p[0][0] + p[p.length - 1][0]) / 2,
(p[0][1] + p[p.length - 1][1]) / 2,
];
ctx.moveTo(...startPoint);
for (let i = 0; i < p.length; i++) {
if (i === p.length - 1) {
ctx.arcTo(...p[p.length - 1], ...p[0], radius);
} else {
ctx.arcTo(...p[i], ...p[i + 1], radius);
}
}
ctx.globalAlpha=alpha;
ctx.closePath();
ctx.strokeStyle=color;
ctx.fillStyle=color;
ctx.fill();
ctx.stroke();
}
var CanvasLayer = new AMap.CanvasLayer({
canvas: canvas,
bounds: new AMap.Bounds(
[116.316279,39.92724],
[116.354087,39.956227]
),
zooms: [3, 18],
});
var CanvasLayer1 = new AMap.CanvasLayer({
canvas: canvas,
bounds: new AMap.Bounds(
[116.309255,39.961797],
[116.360878,39.922309]
),
zooms: [3, 18],
});
var CanvasLayer2 = new AMap.CanvasLayer({
canvas: canvas,
bounds: new AMap.Bounds(
[116.299684,39.968522],
[116.370249,39.914605]
),
zooms: [3, 18],
});
map.addLayer(CanvasLayer);
map.addLayer(CanvasLayer1);
map.addLayer(CanvasLayer2);
draw();
</script>
</body>
</html>
到这里运行看效果:
稍微先补充两点:
- 经实测,在高德地图中添加CanvasLayer后,控制台会不停出现“[Violation] ‘requestAnimationFrame’ handler took XXms”的警告,直到地图崩溃,页面黑屏。。。(因此还在优化ing)
- 将任意一组经纬度坐标在地图上显示为层叠圆角多边形热点区域(最好是凸多边形)的大致思路:
①确定CanvasLayer的边界(bounds):求出能完全容纳这组经纬度坐标的矩形区域的左上角(lng_min, lat_max)、右下角(lng_max, lat_min)两点对应的经纬度;
②确定坐标原点和画布的尺寸:将左上角、右下角的经纬度坐标转换为容器像素坐标,其中左上角相当于坐标原点,右下角与左上角的像素差值即为画布的宽和高;
③计算给定经纬度坐标对应的像素坐标:将这组经纬度坐标中每一个点都转换为容器像素坐标,其与左上角(坐标原点)的差值即为这个点(在坐标系中)的像素坐标;
④创建canvas节点,使用第③步获得的像素坐标绘制圆角多边形;
(到此已经实现了一层圆角多边形热点区域)
⑤计算放大一定比例后的CanvasLayer的边界:将第②步获得的左上角容器像素坐标减少画布宽高的一定比例、右上角容器像素坐标增加画布宽高的一定比例(缩小CanvasLayer时,左上角增加、右下角减少);将新的左上角、右下角容器像素坐标转换为经纬度;
⑥创建多个CanvasLayer,共用第④步的canvas节点,分别设置初始bounds和第⑤步获得的放大/缩小后的边界,添加到地图中即可实现层叠圆角多边形热点区域效果
优化探索-1:使用覆盖物(Marker),将content设为canvas
效果:可以将Marker的content设为canvas绘制多边形,但Marker添加的图像不会随地图的缩放产生变化(由此可以理解为什么CanvasLayer一直报动画相关的警告,因为CanvasLayer绘制的区域会随缩放地图的操作而缩放,即:产生动画);否决
注:禁用地图缩放、拖拽无法消除CanvasLayer的动画相关警告
另: CanvasLayer不支持事件,若需要实现热点区域的交互,可在上方覆盖一个透明多边形(高德地图Polygon文档)
实现效果下位替代:
因目前未能找到CanvasLayer导致地图崩溃问题的解决方法,为了尽可能地实现地图上层叠多边形热点区域的效果,可以使用Polygon展示多边形区域,通过给多边形设置较宽的描边、适当调整半透明区域和半透明描边的颜色,能在合适的缩放下呈现理想的层叠多边形热点区域效果……(不足之处:①多边形外廓不圆润…②地图缩放过小或过大时显示效果可能不理想…)
** 先码一哈,有空再扩展~需要实现效果的小伙伴可以参考代码自行领悟一波哈;欢迎补充优化!**
参考文档
[1] canvas绘制圆角多边形
[2] canvas绘制多边形并填充
[3] 高德地图Canvas图层示例
[4] 高德地图经纬度与容器像素坐标互转示例
[5] 高德地图CanvasLayer文档
[6] 高德地图Polygon文档