背景
业务需求,园区无人车移动端需要加载地图,个人当时给了4个方案
- 复用我司现有的地图(但是是找第三方开发的,且没有源码,无语)
- 三维地图的方案,俯视视角,babylonJs(这个之前web端做过,移动端比较重,且web端只有车道线,building之类都没有,且页面端需要就是一个二维平面就可以了,没必要三维)
- 二维地图,直接加载图片。(这个方法最方便,但是需要涉及多重坐标的转换)
- 二维地图,根据地图信息,一笔一划都自己绘制。(想想这个应该挺麻烦的,但是自己绘制灵活性大一些)
ps: 因为是园区地图,所以没法用百度、高德等API。
技术选择
除了剔除1,其他三个都可以考虑。
babylonjs的方案之前做过,只要固定俯视视角,性能未测,building因为没有数据,未画
目前在调研canvas加载地图图片的需求。
基本要求
- 地图缩放+移动
- 图标位于地图中间,表示起点(同打车APP,移动的是地图,而不是起点)
- 坐标转换(canvas坐标、Img坐标、空间坐标)
其中坐标Img坐标和空间坐标的对应关系是服务端告知的。前端需要处理canvas坐标和Img坐标。
代码实现
html
画个canvas就行
<div style="width:800px;height:800px;border: red solid 1px">
<canvas id="canvas" width="800" height="800"></canvas>
</div>
js
先看一个canvas的核心函数
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
| 参数 | 描述 |
|---|---|
| img | 规定要使用的图像、画布或视频。 |
| sx | 可选。开始剪切的 x 坐标位置。 |
| sy | 可选。开始剪切的 y 坐标位置。 |
| swidth | 可选。被剪切图像的宽度。 |
| sheight | 可选。被剪切图像的高度。 |
| x | 在画布上放置图像的 x 坐标位置。 |
| y | 在画布上放置图像的 y 坐标位置。 |
| width | 可选。要使用的图像的宽度。(伸展或缩小图像) |
| height | 可选。要使用的图像的高度。(伸展或缩小图像) |
简单的说,参数2-5是展示的地图信息,参数6-9是窗口展示信息。
展示的地图信息肯定要是全的,x,y是移动后的左上角,width/height需要考虑scale
context.drawImage(img, 0, 0, img.width, img.height, imgX, imgY, img.width * imgScale, img.height * imgScale);
那就很好理解了,只要计算移动、缩放后的imgX, imgY, imgScale就行。
移动
canvas.onmousedown = function (event) {
var pos = windowToCanvas(canvas, event.clientX, event.clientY);
let xx = (event.clientX - imgX) / imgScale
let yy = (event.clientY - imgY) / imgScale
console.log('pos in img:', xx, yy) // 针对的是img.width, img.height,
canvas.onmousemove = function (event) {
canvas.style.cursor = "move";
var pos1 = windowToCanvas(canvas, event.clientX, event.clientY);
var x = pos1.x - pos.x;
var y = pos1.y - pos.y;
pos = pos1;
imgX += x;
imgY += y;
drawImage();
}
canvas.onmouseup = function () {
canvas.onmousemove = null;
canvas.onmouseup = null;
canvas.style.cursor = "default";
}
}
缩放
var flag = 1
canvas.onmousewheel = canvas.onwheel = function (event) {
var pos = windowToCanvas(canvas, event.clientX, event.clientY);
event.wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltaY * (-40));
if (flag) {
flag = 0
if (event.wheelDelta > 0) {
imgScale *= 1.2;
// imgX = imgX * 1.2 - pos.x;
// imgY = imgY * 1.2 - pos.y;
} else {
imgScale *= 0.8;
// imgX = imgX * 0.8 + pos.x * 0.8;
// imgY = imgY * 0.8 + pos.y * 0.8;
}
drawImage();
setTimeout(() => {
flag = 1
}, 500)
}
event.preventDefault(); // 禁止缩放
}
细节
在缩放的时候,浏览器会随着缩放。即不仅仅是canvas内Img的缩放。所以时候需要加上event.preventDefault();阻止浏览器默认事件。
坐标转换
canvas坐标转换成img坐标。
假设canvas坐标为(x,y), 不一定是用户点击,比如我们的小绿点(表示当前位置,它是不动的)
这个时候去拿到img左上角在canvas中的坐标是(imgX,imgY),对应的img坐标是(0,0)
let iX = (x - imgX) / imgScale
let iY = (y - imgY) / imgScale
console.log('img axis:', iX, iY)
图
这样子基本满足需求了
然后发现到移动端没法用
把mouse相关事件改成touch事件就可以了。
明天更新一下,源码一起放上来