前言
一直没有深入学习过canvas,近期接手一个地图网格的优化需求,优化前是用百度地图的鼠标绘制管理类BMapLib.DrawingManager实现鼠标绘制管理的入口,并通过实例化该类,调用open方法开启绘制状态进行绘制。但是画线交互方式是通过鼠标点击,不太流畅。因此希望通过canvas在地图上进行鼠标点击划动画线。
百度地图鼠标绘制管理类--BMapLib.DrawingManager
- 资源
<!-- 百度地图 -->
<script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=osOdXZRHUHOC2yMC4YB3InaCxzGVECy4"></script>
<!-- 热力图 -->
<script type="text/javascript" src="//api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js"></script>
<!-- 鼠标绘制 -->
<script type="text/javascript" src="//api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.js"></script>
<!-- 工具类文档: http://api.map.baidu.com/library/GeoUtils/1.2/docs/symbols/BMapLib.GeoUtils.html -->
<script type="text/javascript" src="//api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js"></script>
<link rel="stylesheet" href="//api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" />
<script>
window.BMap = BMap;
window.BMapLib = BMapLib;
</script>
封装canvas画线基类
通过canvas方法画线并将线路经的坐标传给后端
挂载dom: <canvas className="map-draw-canvas" id="mapDrawCanvas"></canvas>
class MapCanvas {
protected mapDrawCanvas = null;
protected ctx = null;
protected width = null;
protected height = null;
protected draw = false;
protected points = [];
protected map = null;
constructor(props: any) {
this.width = props.width;
this.height = props.height;
this.map = props.map;
this.mapDrawCanvas = document.getElementById('mapDrawCanvas');
this.mapDrawCanvas.width = this.width;
this.mapDrawCanvas.height = this.height;
this.mapDrawCanvas.style.display = 'block';
this.ctx = this.mapDrawCanvas.getContext('2d');
}
private randomWithSet(length, data: Array<any>) {
const set = new Set();
const MAXIMUM = Math.min(length, data.length);
const UID_COUNT = data.length;
// eslint-disable-next-line no-constant-condition
while (true) {
if (set.size > MAXIMUM - 1) break;
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
const tmp = parseInt(Math.random() * UID_COUNT, 10);
if (set.has(tmp)) continue;
set.add(tmp);
}
return Array.from(set)
.sort(function(a: any, b: any) {
return a - b;
})
.map((i: number) => data[i]);
}
public startDraw() {
// 画布添加滚轮事件,放缩地图
this.mapDrawCanvas.onmousewheel = this.scrollFunc.bind(this);
const gridMap = document.getElementById('grid-map');
const y = gridMap.getBoundingClientRect().top;
this.mapDrawCanvas.onmousedown = e => {
this.ctx.beginPath();
this.ctx.strokeStyle = '#ff0000';
this.ctx.beginPath();
this.ctx.lineWidth = 1;
this.ctx.moveTo(e.clientX + 8, e.clientY - y + 28);
this.mapDrawCanvas.onmousemove = e => {
// console.log(e.clientX, e.clientY);
this.ctx.lineTo(e.clientX + 8, e.clientY - y + 28);
this.ctx.stroke();
this.points.push({ x: e.clientX + 8, y: e.clientY - y + 28 });
};
this.mapDrawCanvas.onmouseup = e => {
this.mapDrawCanvas.onmouseup = null;
this.mapDrawCanvas.onmousemove = null;
this.mapDrawCanvas.onmousedown = null;
this.draw = false;
this.mapDrawCanvas.style.display = 'none';
this.endDraw();
};
};
}
public endDraw() {
if (this.points.length > 5) {
this.drawLinePoints();
}
this.mapDrawCanvas.style.display = 'none';
// 移除去鼠标滚动事件
this.mapDrawCanvas.onmousewheel = null;
}
public clearCanvas() {
this.ctx.clearRect(0, 0, this.width, this.height);
this.points = [];
}
public drawLinePoints() {
const { BMap, BMapLib } = window as any;
if (this.map) {
const a = this.randomWithSet(10, this.points).map(point => {
// eslint-disable-next-line no-undef
return this.map.pixelToPoint(point);
});
console.log(a);
const bc = new BMap.Polyline(a, {
strokeColor: '#ff0000',
strokeWeight: 2,
strokeOpacity: 1
});
bc.enableEditing();
this.map.addOverlay(bc);
}
}
public getPoints() {
return this.points;
}
public showCanvas(width, height) {
this.mapDrawCanvas.style.display = 'block';
this.mapDrawCanvas.width = width;
this.mapDrawCanvas.height = height;
}
// 鼠标滚轮事件
private scrollFunc(e) {
const { wheelDelta } = e;
if (wheelDelta > 0) {
this.map.zoomIn();
} else {
this.map.zoomOut();
}
}
public hideCanvas() {
this.mapDrawCanvas.style.display = 'none';
this.mapDrawCanvas.onmousewheel = null;
}
}
export default MapCanvas;
如何使用
// 打开画笔,开始绘制
const { width, height } = this._map;
if (!this.mapCanvas) {
this.mapCanvas = new MapCanvas({ map: this._map, width, height });
const ployline = getDrawingPolyline(this._map);
if (ployline) {
ployline.remove();
}
} else {
this.mapCanvas.showCanvas(width, height);
}
this.mapCanvas.startDraw();
思考
地图遮罩层并高亮选中区域,如何做?
问题
- canvas开启画线模式,不能缩放 解决
- 样式穿透
参考文献
[1] api.map.baidu.com/library/Dra… [2]