最近几个月跑了不少步,试用了很多不同的APP,导致轨迹、跑量什么的各自为政,因此萌生了写个程序把所有跑步的轨迹都画在一张地图上的想法。
第一步,先把各个地方能导出轨迹的都导出来。看了一下.FIT .TPX .GPX中,以GPX文件结构最简单,下面就是一段.gpx文件的记录点格式,于是把轨迹都导成.gpx文件。
第二步,读取GPX文件数据
人生苦短,我用Python——用Python读入这些GPX轨迹信息,处理后再画在地图上,应该是最容易的做法了。Python本身接近自然语言,丰富的第三方库让写程序就像用英文和计算机对话一样。
直接使用Python自带的xml库完成读取,注意要剔除lat和lon为0的数据点,因为GPX是用这种方法来标记暂停的。
import xml.dom.minidom as xdom
gpxPath = 'test.gpx'
dom_tree = xdom.parse(gpxPath)
collection = dom_tree.documentElement
trkpts = collection.getElementsByTagName("trkpt")
lats, lons = [], []
for trkpt in trkpts:
lat = trkpt.getAttribute("lat")
lon = trkpt.getAttribute("lon")
if lat=='0' or lon=='0':
continue
lats.append(float(lat))
lons.append(float(lon))
datas = {'lat': lats, 'lon': lons}
第三步,将数据画在地图上
前面进行的一切顺利,没想到在画地图的时候卡住了。
建筑师出身,对图面的要求不能太低。而Python的地图库里面几乎没有好看的地图,而且使用起来都颇为麻烦。在尝试了Basemap、Plotly、Folium之后,最终选择使用高德地图,方便好用。
高德地图JavaScrip API快速入门
在正式开始开发地图应用之前,您需要做如下几步:
- 申请JSAPI的开发者key
申请地址:http://lbs.amap.com/dev/key - 引入高德地图JavaScript API文件:
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=您申请的key值"></script>
- 创建地图容器
在页面body里你想展示地图的地方创建一个div 容器,并指定id标识:
<div id="container"></div>
- 指定容器大小
按照需要设定地图容器的大小,确保大小合适,比如用CSS这样设置它:
#container {width:300px; height: 180px; }
接下来要写个网页用来读取本地的数据文件。因为之前已经使用Python完成了GPX数据读取,所以先改写一下,输出JS可以方便读取的JSON文件。
import os
fileDir, fileName = os.path.split(gpxPath)
jsonDir = os.path.join(fileDir, 'jsons')
if not os.path.exists(jsonDir):
os.mkdir(jsonDir)
jsonPath = os.path.join(jsonDir, fileName) + '.json'
with open(jsonPath, 'w') as f:
f.write(json.dumps(datas))
同时为了方便的处理多条数据,把上面Python的部分写成一个procXml函数,然后在命令行中将要转换的文件作为参数传入。
import sys
def main():
if len(sys.argv) < 2:
print 'Specify the gpx file path'
return
fileList = sys.argv[1:]
for p in fileList:
if os.path.isfile(p):
gpxPath = os.path.abspath(p)
print 'Processing'+str(gpxPath)
try:
procXml(p)
print 'Coresponding JSON file was generated.'
except:
print '=====Somthing was wrong!====='
if __name__ == '__main__':
main()
保存为gpx2json.py,将从跑步软件中导出的GPX文件都放在同目录下的gpxs文件夹中,然后在命令行中输入以下命令进行批量转换:
python gpx2json.py gpxs/*
轨迹处理完毕后的json文件会放到gpxs/json/下,马上就要读取本地的json文件并调用高德地图的API画轨迹了,已经接近完成了呢。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=cgbvip@gmail.com"></script>
<title>-*- iRunMap -*-</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input id="file-upload" type="file" multiple>
<input id ="clear" type="button" value='clear'>
</form>
<div id="container" style="width:1200px;height:800px;">
</div>
<script src="drawPath.js"></script>
</body>
</html>
保存为index.html。框架已经搭好,就差最后的drawPath.js了。
看了一下高德的API,mapStyle选择dark,黑色的背景地图非常酷炫。为了更清楚的显示轨迹信息,直接隐掉路网、建筑等图层,features设置为bg(纯背景)。用HTML5提供的ObjectURL获得本地文件的地址。
'use strict';
var map = new AMap.Map('container', {
zoom: 12,
center: [121, 31],
mapStyle: 'dark',
features: ['bg']
});
$(document).ready(function(){
$('#clear').on('click', (function(){
map.clearMap();
}));
$('#file-upload').on('change', function(){
for(var i=0,f;f=this.files[i];i++){
var fPath = window.URL.createObjectURL(f);
$.getJSON(fPath, function(data){
var lineArr = new Array();
for(var i=0;i<data.lat.length;i++){
lineArr.push(new AMap.LngLat(data.lon[i],data.lat[i]));
}
var polyline =new AMap.Polyline({
path: lineArr,
strokeColor: "#00ff00",
strokeOpacity: 0.5,
strokeWeight: 3,
strokeStyle: "solid",
});
polyline.setMap(map);
});
}
});
});
Duang的一下就完成了!打开文件上传所有GPX文件,一直在复旦大学和上海西南某高校附近徘徊呢,真是冤家。
查看源码