原理说明

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

后话

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

canvas模拟中国铁路运行图的更多相关文章

  1. 结合 CSS3 & Canvas 模拟人行走的效果

    HTML5 和 CSS3 技术给 Web 带来了新的利器,点燃了 Web 开发人员的激情.所谓只有想不到,没有做不到,的确如此.下面给大家分享一个结合 CSS3 & Canvas 模拟人行走的 ...

  2. 经典!HTML5 Canvas 模拟可撕裂布料效果

    这是一个模拟可撕裂布料效果的 HTML5 Canvas 应用演示,效果逼真.你会看到,借助 Canvas 的强大绘图和动画功能,只需很少的代码就能实现让您屏息凝神的效果. 温馨提示:为保证最佳的效果, ...

  3. 中国铁路基于Intel架构超大规模OpenStack行业云的性能优化研究

    1. 项目简介 铁路作为一种大众化的交通工具和非常重要的货物运输方式,其业务规模庞大.覆盖全国.服务全国各族人民.铁路面向公众提供的服务业务,主要是客运和货运两大类,且每年365天.每天7*24小时连 ...

  4. html5打开摄像头并用canvas模拟拍照 - 转

    <video id="video" width="640" height="480" autoplay></video&g ...

  5. html5打开摄像头并用canvas模拟拍照

    网上很多关于用HTML5打开本地摄像头的文章,但各有瑕疵.根据我自己的亲身体验,我分享一下我用HTML5打开摄像头的经验. 废话不多说,直接看代码. HTML代码: <video id=&quo ...

  6. Scratch与物理·天文:模拟中国嫦娥探月工程,探索月球的背面!

    北京时间2019年5月16日凌晨,国际顶级学术期刊<自然>(Nature)在线发表了一篇来自中国科学家的成果:中国的嫦娥四号月球探测器2019年1月3日在月球背面的冯卡门陨石坑(Von K ...

  7. canvas模拟重力效果

    总结 速度和加速度是动画的基础元素,其中两者都是向量,包括了一个重要因素:方向. 要学会应用 分解 和 合成 ,将速度或加速度分解到x.y轴上,然后将每条轴上的加速度或速度相加,然后再分别与物体的位置 ...

  8. canvas 模拟小球上抛运动的物理效果

    最近一直想用学的canvas做一个漂亮的小应用,但是,发现事情并不是想的那么简单.比如,游戏的逼真效果,需要自己来coding…… 所以,自己又先做了一个小demo,算是体验一下亲手打造物理引擎的感觉 ...

  9. 用Canvas,画中国国旗(Canvas基本知识点)

    .getContext("2d")=======>获取绘图接口 //2d .beginPath()========>创建绘图路径开始点 .moveTo(x,y)==== ...

随机推荐

  1. moment实现计算两个时间的差值

    var m1 = moment('2018-08-14 11:00:00'), m2 = moment('2018-08-14 12:10:00'); console.log(m1)console.l ...

  2. 代码审计之XSS及修复

    xss在平时的测试中,还是比较重要的,如果存在储存型xss,就可以做很多事情了,打cookie,添加管理员等等很多操作. 以下所有代码都是我自己写的,可能有不美观,代码错误等等问题,希望大家可以指正. ...

  3. ES 32 - Elasticsearch 数据建模的探索与实践

    目录 1 什么是数据建模? 2 如何对 ES 中的数据进行建模 2.1 字段类型的建模方案 2.2 检索.聚合及排序的建模方案 2.3 额外存储的建模方案 3 ES 数据建模实例演示 3.1 动态创建 ...

  4. mkdir,rmdir

    mkdir (选项)(参数)  创建文件夹-m:创建文件夹的同时,赋予其权限-p:若创建目录的上层不存在时,一并创建出来-v:显示创建的过程创建多个目录的时候,用空格隔开 rmdir (选项)(参数) ...

  5. 前沿科技-混合现实(MR)远程协作辅助工具:微缩虚拟形象Mini-Me

    今天分享一篇在刚刚结束的CHI’2018上发表的full paper.该文章由来自澳洲University of South Australia的Piumsomboon等人和来自新西兰Universi ...

  6. Docker实战笔记命令篇

    拉取一个镜像 docker pull ubuntu:14.04 查看系统中的镜像 docker images 运行镜像并进入 docker run -it ubuntu:14.04 查看运行的容器 d ...

  7. SpringBoot导入jsp依赖始终报错

    先粘出我自己的pom代码: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...

  8. 【Elasticsearch 搜索之路】(一)什么是 Elasticsearch?

    本篇文章对 Elasticsearch 做了基本介绍,在后续将通过专栏的方式持续更新,本系列以 Elasticsearch7 作为主要的讲解版本,欢迎各位大佬指正,共同学习进步! 一般涉及大型数据库的 ...

  9. 294 div2 C. A and B and Team Training

    C. A and B and Team Training 题目:A and B are preparing themselves for programming contests. An import ...

  10. [ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker

    对于一个 .NET Core开发人员,你可能没有使用过Docker,但是你不可能没有听说过Docker.Docker是Github上最受欢迎的开源项目之一,它号称要成为所有云应用的基石,并把互联网升级 ...