原理说明

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. JavaScript之数学对象Math

    Javascript 中Math和其他对象不同,它具有数学常数和函数的属性和方法.因为它的属性是数学常数,所以不能被改变(可以进行赋值操作,但最后值不变). Math的方法就是普通函数,调用他们直接用 ...

  2. java枚举的应用

    最近的项目中,看前辈们用到的枚举比较多,由于自己之前对枚举这种类型不是很了解,遂花费心机看了下,整理记录下. 1.枚举常量 系统中定义的状态字段,用的比较多: public enum orderTyp ...

  3. pathlib模块

    一.pathlib库官方定义 pathlib 是Python内置库,Python 文档给它的定义是 Object-oriented filesystem paths(面向对象的文件系统路径).path ...

  4. 用docker部署RabbitMQ环境

    前置条件: 已经安装好docker 1.查找镜像(有2种方式) ①登录rabbitmq官网找到docker镜像,选择想要的镜像的tag https://www.rabbitmq.com/downloa ...

  5. npm install 时间很长解决方案

    国外镜像站很慢,所以我们可以更换为国内的镜像站 首先可以get命令查看registry npm congfig get registry 如果你没有变更果regustry你的结果应该会是这样的 也就是 ...

  6. java+maven+jenkins+svn构建

    操作参照:https://blog.csdn.net/qq_34977342/article/details/82346915 1.创建一个自由风格的项目,起名字 2.设置构建项目最大保存数量,与天数 ...

  7. ng执行css3动画

    在组件html中 <div> <aside id="aside">侧边栏</aside> <div class="content ...

  8. 响应系统设置的事件(Configuration类)

    1.Configuration给我们提供的方法列表 densityDpi:屏幕密度 fontScale:当前用户设置的字体的缩放因子 hardKeyboardHidden:判断硬键盘是否可见,有两个可 ...

  9. Android实现apk插件方式换肤

    换肤思路: 1.什么时候换肤? xml加载前换肤,如果xml加载后换肤,用户将会看见换肤之前的色彩,用户体验不好. 2.皮肤是什么? 皮肤就是apk,是一个资源包,包含了颜色.图片等. 3.什么样的控 ...

  10. Tomcat线程参数maxThreads、acceptCount

    一.配置Tomcat/conf/server.xml修改配置 <Connector port="8080" protocol="org.apache.coyote. ...