canvas模拟中国铁路运行图

原理说明

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函数实现标记点的运动。

效果图如下(图中轨迹经纬度信息纯属虚构

canvas模拟中国铁路运行图

中国地图绘制方法

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模拟中国铁路运行图

后话

希望上述讲解能够帮助到读者!!!