地图投影
难题
地球的问题在于它并不平坦,而我们人类用来绘制和渲染的大部分内容往往是平坦的。为了解决这个问题,我们通过将圆形地球的投影应用到平面地图来接受地图所代表的一些变形。有许多不同类型的投影,常见的一种是墨卡托投影(参见谷歌地图),它会扭曲赤道更南和更北的区域。但这样做是为了保持方向。您可以将指南针放在墨卡托投影地图上并获得准确的方位,但您不能拿尺子来测量距离。
但大小很重要,简单的解决方案
但这一切都有一个可取之处。与地球相比,我们人类非常渺小,对于局部地图而言,地球曲率造成的失真是如此之小以至于无关紧要。
如果您在一个小区域(例如城市和郊区)有一组坐标,您可以只使用方形投影。其中 lat 和 long 是渲染表面网格上的 x 和 y。
一步一步
如何获取一些映射数据并将其调整到维护方面的画布。
所以你有一组点和一个画布上下文
<canvas id="canvas" width =300 height = 200></canvas>
ctx = canvas.getContext("2d");
var myPoints = [[2.809510437833253,49.408625488749216],[2.8095461924850422,49.40864172401838],[2.8095226856172806,49.40866595550704],[2.809565304449213,49.40868849340382],[2.8097185865450465,49.40858536874469],[2.809677338568488,49.40856463072128],[2.8096442193374154,49.408580757620854],[2.809609885351463,49.40855283978645],[2.809510437833253,49.408625488749216]]
然后找到这些点的范围(最小和最大坐标)
var minX,minY,maxX,maxY;
myPoints.forEach((p,i) => {
if(i === 0){ // if first point
minX = maxX = p[0];
minY = maxY = p[1];
}else{
minX = Math.min(p[0],minX);
minY = Math.min(p[1],minY);
maxX = Math.max(p[0],maxX);
maxY = Math.max(p[1],maxY);
}
});
// now get the map width and heigth in its local coords
const mapWidth = maxX-minX;
const mapHeight = maxY-minY;
const mapCenterX = (maxX + minX) /2;
const mapCenterY = (maxY + minY) /2;
现在您有了地图范围,您可以通过找到适合宽度和高度的最小比例将其缩放到画布。
const scale = Math.min(canvas.width / mapWidth,canvas.height / mapHeight);
现在您可以先减去地图中心来绘制地图,然后将其放大,然后移至画布中心。
ctx.beginPath();
myPoints.forEach(p => {
ctx.lineTo(
(p[0] - mapCenterX) * scale + canvas.width /2 ,
(p[1] - mapCenterY) * scale + canvas.height / 2
);
});
ctx.stroke();
还有一个工作示例。
ctx = canvas.getContext("2d");
var myPoints = [[2.809510437833253,49.408625488749216],[2.8095461924850422,49.40864172401838],[2.8095226856172806,49.40866595550704],[2.809565304449213,49.40868849340382],[2.8097185865450465,49.40858536874469],[2.809677338568488,49.40856463072128],[2.8096442193374154,49.408580757620854],[2.809609885351463,49.40855283978645],[2.809510437833253,49.408625488749216]]
var minX,minY,maxX,maxY;
myPoints.forEach((p,i) => {
if(i === 0){ // if first point
minX = maxX = p[0];
minY = maxY = p[1];
}else{
minX = Math.min(p[0],minX);
minY = Math.min(p[1],minY);
maxX = Math.max(p[0],maxX);
maxY = Math.max(p[1],maxY);
}
});
// now get the map width and heigth in its local coords
const mapWidth = maxX-minX;
const mapHeight = maxY-minY;
const mapCenterX = (maxX + minX) /2;
const mapCenterY = (maxY + minY) /2;
// to find the scale that will fit the canvas get the min scale to fit height or width
const scale = Math.min(canvas.width / mapWidth,canvas.height / mapHeight);
// Now you can draw the map centered on the cavas
ctx.beginPath();
myPoints.forEach(p => {
ctx.lineTo(
(p[0] - mapCenterX) * scale + canvas.width /2 ,
(p[1] - mapCenterY) * scale + canvas.height / 2
);
});
ctx.stroke();
canvas { border : 2px solid black; }
<canvas id="canvas" width =300 height = 200></canvas>