原理说明

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. [C++] 重载运算符与类型转换(2)——函数调用运算符和类型转换运算符

    1.这两个应该是C++中比较高级的用法了. 一.函数调用运算符   1.重载函数调用运算符(),必须是成员函数,一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或者类型上有所区别.   ...

  2. 一起看期待已久的.NET Core 3.0新的单文件部署特性,记在昨日VS2019更新后

    VS2019又又又迎来一次新的更新,这次的重点在.NET Core, 妥妥的更新好,默默地反选2.2,一切都在意料之中. 这次我们来看VS2019的新特性单文件部署: https://www.talk ...

  3. 深入理解Three.js中线条Line,LinLoop,LineSegments

    前言 在可视化开发中,无论是2d(canvas)开发还是3d开发,线条的绘制应用都是比较普遍的.比如绘制城市之间的迁徙图,运行轨迹图等.本文主要讲解的是Three.js中三种线条Line,LineLo ...

  4. 公开的免费WebService接口分享,用于做接口练习

    本文转载于 https://cloud.tencent.com/developer/article/1349603 天气预报Web服务,数据来源于中国气象局 Endpoint http://www.w ...

  5. Pytorch-数学运算

    引言 本篇介绍tensor的数学运算. 基本运算 add/minus/multiply/divide matmul pow sqrt/rsqrt round 基础运算 可以使用 + - * / 推荐 ...

  6. linux系统下开发环境安装与配置

    安装系统环境 CentOS 6.8 64位 jdk版本 7u80 64位 Tomcat版本 Tomcat7 maven版本 Apache Maven 3.6.0 vsftpd版本 vsftpd-2.2 ...

  7. CentOS 8 正式发布

    转载请注明:文章转载自 OSCHINA 社区 [http://www.oschina.net] 本文地址:https://www.oschina.net/news/110111/centos-8-re ...

  8. freemarker常见语法

    FreeMarker的插值有如下两种类型:1,通用插值${expr};2,数字格式化插值:#{expr}或#{expr;format}  ${basketball.name?if_exists } / ...

  9. 初级Python

    [toc] 一.数据类型 1.1基本数据类型 1.1.1数字类型 1.整数类型 十进制:1010,-219 二进制:以0b或0B开头:0b010,-0B101 八进制,以0o或0O开头:0o123,- ...

  10. JAVA的List接口的remove重载方法调用原理

    前言 说真的,平常看源码都是自己看完自己懂,很少有写出来的冲动. 但是在写算法的时候,经常用到java中各种集合,其中也比较常用到remove方法. remove有重载函数,分别传入参数是索引inde ...