原理說明
1、在知道canvas畫布尺寸的情況下,需要將地理經緯度信息轉換爲canvas畫布x,y座標,因爲中國地圖地理經緯度座標取值範圍爲73.33-135.05(經度)37-50(維度),所以第一步需要確認的就是畫布的中心位置,這裏命名爲centerX和centerY,同樣的確認中國地圖經緯度對應的中心位置,這裏命名爲positionX,positionY。
2、人爲定義一個放大值range,這個值主要作用就是等比例的將中國地圖在canvas畫布中放大,range的數值需要根據畫布橫向尺寸跨度值與中國地圖經緯度中經度跨度值相除來求解出來。
3、根據range值將中國地圖等比例的在canvas畫布上繪製出來。
4、獲取地圖上需要展示的軌跡經緯度信息,根據上述2,3在canvas畫布上繪製出來。
5、定義一個rate值,用於表示在軌跡上運行物體的速度,爲了能夠保證運行物體軌跡沿着軌跡運行,需要在軌跡任意兩個點之間求出橫向寬度和縱向跨度,並且以跨度最大的那個爲基準求解出軌跡上需要繪製多少個軌跡點,然後從過跨度較小的那個除以求解出來的軌跡點數量得出相應的速率。
6、在軌跡上點和橫縱向運行速度確定之後,通過調用requestAnimationFrame函數實現標記點的運動。
效果圖如下(圖中軌跡經緯度信息純屬虛構)
中國地圖繪製方法
function drawShapeOptionFun () {
// 繪製中國地圖
chinaGeometry.features.forEach(function (chinaItem, chinaIndex) {
var length = chinaItem.geometry.coordinates.length;
var multipleBool = length > 1 ? true : false;
chinaItem.geometry.coordinates.forEach(function (chinaChildItem, wordItemIndex) {
if (multipleBool) {
// 值界可以使用的經緯度信息
if (chinaChildItem.length && chinaChildItem[0].length == 2) {
drawCanvasFun(chinaChildItem);
}
// 需要轉換纔可以使用的經緯度信息
if (chinaChildItem.length && chinaChildItem[0].length > 2) {
chinaChildItem.forEach(function (countryItem, countryIndex) {
drawCanvasFun(countryItem);
})
}
} else {
var countryPos = null;
if (chinaChildItem.length > 1) {
countryPos = chinaChildItem;
} else {
countryPos = chinaChildItem[0];
}
if (countryPos) {
drawCanvasFun(countryPos);
}
}
})
})
}
// canvas繪製平面
function drawCanvasFun (itemPosition) {
ctx.fillStyle = mapColor;
ctx.strokeStyle = mapLineColor;
ctx.beginPath();
ctx.moveTo(width / 2 + (itemPosition[0][0] - averageX) * range, height / 2 - (itemPosition[0][1] - averageY) * range);
itemPosition.forEach(function (item) {
ctx.lineTo(width / 2 + (item[0] - averageX) * range, height / 2 - (item[1] - averageY) * range);
})
ctx.fill();
ctx.stroke();
ctx.closePath();
}
中國地圖上軌跡和軌跡上運行點座標確認方法
function drawMetapFun (pointObj,index) {
ctx.shadowOffsetX = 0; // 設置水平位移
ctx.shadowOffsetY = 0; // 設置垂直位移
ctx.shadowBlur = 1; // 設置模糊度
ctx.shadowColor = pointObj.color; // 設置陰影顏色
ctx.strokeStyle = pointObj.color;
ctx.lineWidth = pointObj.lineWidth;
ctx.beginPath();
ctx.moveTo(width / 2 + (pointObj.data[0][0] - averageX) * range,height / 2 - (pointObj.data[0][1] - averageY) * range)
pointObj.data.forEach(function (item, index) {
if (index != 0) {
ctx.lineTo(width / 2 + (item[0] - averageX) * range,height / 2 - (item[1] - averageY) * range)
}
})
ctx.stroke();
// 軌跡上運行的點
ctx.shadowOffsetX = 0; // 設置水平位移
ctx.shadowOffsetY = 0; // 設置垂直位移
ctx.shadowBlur = 1; // 設置模糊度
ctx.shadowColor = pointObj.color; // 設置陰影顏色
ctx.fillStyle = pointObj.color;
ctx.beginPath();
ctx.arc(width / 2 + (pointPositionArray[index].data[pointPositionArray[index].index][0] - averageX) * range,
height / 2 - (pointPositionArray[index].data[pointPositionArray[index].index][1] - averageY) * range,
ballRadius,0,2*Math.PI);
// ctx.arc(pointPositionArray[index].data[pointPositionArray[index].index][0] + offsetX,pointPositionArray[index].data[pointPositionArray[index].index][1] + offsetY,ballRadius,0,2*Math.PI);
ctx.closePath();
ctx.fill();
if (pointPositionArray[index].index >= pointPositionArray[index].length - 1) {
pointPositionArray[index].index = 0;
}
pointPositionArray[index].index ++;
}
function getMetap (pointArray) {
pointArray.forEach(function (item) {
getMetapFun(item);
})
}
function getMetapFun (pointObj) {
var dataArray = [];
pointObj.data.forEach(function (item, index) {
metapXMax = item[0] > metapXMax ? item[0] : metapXMax;
metapYMax = item[1] > metapYMax ? item[1] : metapYMax;
metapXMin = item[0] < metapXMin ? item[0] : metapXMin;
metapYMin = item[1] < metapYMin ? item[1] : metapYMin;
if (index != 0) {
ctx.lineTo(item[0],item[1]);
space = Math.abs(space);
var diffX = item[0] - pointObj.data[index - 1][0];
var diffY = item[1] - pointObj.data[index - 1][1];
var num = 0;
var _space = 0;
dataArray.push[pointObj.data[index - 1][0],pointObj.data[index - 1][1]];
if (Math.abs(diffX) > Math.abs(diffY)) {
num = parseInt(Math.abs(diffX) / space);
_space = diffY / num;
space = diffX > 0 ? space : -space;
for (var i = 0; i < num; i ++) {
dataArray.push([pointObj.data[index - 1][0] + i * space,pointObj.data[index - 1][1] + i * _space])
}
} else {
num = parseInt(Math.abs(diffY) / space);
_space = diffX / num;
space = diffY > 0 ? space : -space;
for (var i = 0; i < num; i ++) {
dataArray.push([pointObj.data[index - 1][0] + i * _space,pointObj.data[index - 1][1] + i * space])
}
}
}
})
pointPositionArray.push({
index: 0,
length: dataArray.length,
data: dataArray
})
}
實例預覽地址:canvas模擬中國鐵路運行圖
後話
希望上述講解能夠幫助到讀者!!!