cesium製作自己的騎行軌跡

壯壯壯壯壯發表於2021-11-03

製作自己的騎行軌跡

馬上國慶節了,計劃騎車回家,突然想到把所有的騎行線路彙總一下,無奈碼錶和APP不支援這樣的操作,出於職業病,在此操作一下。

我用的是黑鳥碼錶,可以匯出fit運動軌跡,但是fit還需要轉gpx格式才能讀取,否在二進位制無法讀取。想到在官網也可以看騎行記錄,做為一名開發,我嗅到了可以從官網的個人中心去爬取騎行資料,比直接讀取檔案更為方便和快捷。

效果

連結地址 壯壯壯壯壯的騎行記錄

獲取軌跡資料

登陸

登陸黑鳥官網,右上角進入個人中心

查單條資料

F12開啟開發人員選項後,隨便點選一條騎行記錄進入詳情,檢視網路選項卡,找到請求騎行資料的請求,做為GISer,對經緯度格外敏感,看到38,114就知道這是需要的資料了。

提取騎行資料

提取騎行資料,postman裡測試,設定請求頭的Cookie,成功請求到資料。各個網站驗證可能是不一樣的,有的用Cookie,有的用Token,有的用Authorization,酌情而定。
記住請求地址中的關鍵資訊 56135240 ,推測此為記錄ID,後面肯定會在列表中存在。

http://www.blackbirdsport.com/api/records/56135240/data

提取騎行列表

提取騎行列表,返回上一頁,檢視網路選項卡,找到請求騎行列表的資料,在記錄裡找到recordID,和前面查詢具體資料的關鍵字一致,那麼就可以準備爬下所有資料了。

postman測試地址,正常返回所有資料。http://www.blackbirdsport.com/api/records?lastRecordId=0&pageSize=25 末尾的 pageSize=25 改為 pageSize=100 一次爬取100條資料,小菜腿還沒騎夠100次

爬取

java爬取,資料輸出到控制檯,複製儲存好,接下來前臺會用到,至此,資料爬取已經完成。

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
* 獲取黑鳥的行車行車資料
* @author lizhuang
* @date 2021/9/9 14:00
*/
public class GetBickRecord {
public static void main(String[] args) {
String detailUrl = "http://www.blackbirdsport.com/api/records/{}/data";
String listUrl = "http://www.blackbirdsport.com/api/records?lastRecordId=0&pageSize=100";
String cookie = "xxxxxx";//自己在網站上獲取的cookie

String strRes = HttpRequest.get(listUrl).header("Cookie",cookie).execute().body();
JSONObject o = JSONUtil.parseObj(strRes);
JSONArray list = o.getJSONArray("content");

JSONArray jSONArray = new JSONArray();

for (int i = 0; i < list.size(); i++) {
JSONObject obj = list.getJSONObject(i);
String temp = StrUtil.format(detailUrl, obj.getStr("recordId"));
String strData = HttpRequest.get(temp).header("Cookie",cookie).execute().body();
String[] track = JSONUtil.parseObj(strData).getJSONObject("content").getStr("track").split(";");
JSONArray j = new JSONArray();
StringBuilder sb = new StringBuilder();
try {

Thread.sleep(1000);
}catch (Exception e){
}
for (int i1 = 0; i1 < track.length; i1++) {
String[] s1 = track[i1].split(",");
JSONArray json = new JSONArray();
json.add(s1[0]);
json.add(s1[1]);
json.add(s1[2]);
j.add(json);
}
jSONArray.add(j);
}

System.out.println(jSONArray.toString());

}
}

頁面製作

2102年了,當然要三維了。

關於展示想法

  • 想做成騎行次數越多的線路顏色越亮,最好在加上動態效果,也就OD線可以實現了。

  • 向量地圖和影像地圖切換,採用百度暗色系向量地圖和天地圖影像,天地圖載入速度時快時慢,其他網際網路影像精度不夠,國外大廠又被牆了,只能用天地圖了。

  • 關於地形,載入了地形後,發現OD線不能貼地,像要貼地只能改為普通線,暫時把地形去掉了,後面想到好方法再往上加吧。

  • 地形+普通線貼地的效果圖

程式碼

直接上程式碼吧,前臺使用cesium,採用百度暗色系底圖,線條採用OD線。

<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- <title>騎行記錄</title> -->
<!-- 0 引入js檔案:XbsjEarth.js和vue.min.js -->
<script src="../lib/XbsjEarth/XbsjEarth.js"></script>
<!-- <script src="http://earthsdk.com/v/last/XbsjEarth/XbsjEarth.js"></script> -->
<script src="./scripts/vue.min.js"></script>
<!-- <script src="http://earthsdk.com/v/last/Apps/Examples/scripts/vue.min.js"></script> -->
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
}
</style>
</head>


<body>
<div id="vueApp" style="width: 100%; height: 100%; background: grey; position: relative;">
<earth-comp></earth-comp>
</div>

<script>
function switchMap(){
earth.sceneTree.root.children[1].enabled = !earth.sceneTree.root.children[1].enabled
}

function loadData(dataFunc) {

var data = [[["38.07765", "114.53156"], ["38.07769", "114.53156"]]] //'此處為上面java程式碼System.out.println()輸出的資料,三位陣列'

var timeDuration = 10.0;
var moveBaseDuration = 4.0;

var hStep = 300 / (data.length - 1);

var busLines = [];
data.map(function (busLine, idx) {
var points = [];
busLine.map(function (item, idx) {
if (Cesium.Math.toRadians(item[1]) != 0) {
// points.push([Cesium.Math.toRadians(item[1]), Cesium.Math.toRadians(item[0]),item[2]]) 此為新增z值的資料(x,y,z)
points.push([Cesium.Math.toRadians(item[1]), Cesium.Math.toRadians(item[0])]) // 僅有x,y
}
})

busLines.push({
positions: points,
color: [Math.random() * 0.5 + 0.5, Math.random() * 0.8 + 0.2, 0.0, 1.0],
width: 2.0,
startTime: timeDuration * Math.random(),
duration: moveBaseDuration + 1.0 * Math.random()
});
});

console.log('busLines', busLines)
dataFunc(busLines, timeDuration);
}

// 1 建立Earth的vue元件
var EarthComp = {
template: `
<div style="width: 100%; height: 100%">
<div ref="earthContainer" style="width: 100%; height: 100%">
</div>
<div style=" position: absolute; z-index: 99; display: inline-block; left: 2%; top: 2%;">
<button style=" width: 130px; height: 40px; color: #fff; border-radius: 5px; padding: 10px 25px; font-family: 'Lato', sans-serif; font-weight: 500; background: transparent; cursor: pointer; transition: all 0.3s ease; position: relative; display: inline-block; box-shadow: inset 2px 2px 2px 0px rgb(255 255 255 / 50%), 7px 7px 20px 0px rgb(0 0 0 / 10%), 4px 4px 5px 0px rgb(0 0 0 / 10%); outline: none;" onclick="switchMap()">切換地圖</button>
</div>
</div>
`,
data() {
return {
_earth: undefined, // 注意:Earth和Cesium的相關變數放在vue中,必須使用下劃線作為字首!
_bgImagery: undefined,
fps: 0,
elapsedTime: 0
};
},
// 1.1 資源建立
mounted() {
// 1.1.1 建立地球
var earth = new XE.Earth(this.$refs.earthContainer);

// 1.1.2 新增預設地球影像
earth.sceneTree.root = {
"children": [
{
"czmObject": {
"xbsjType": "Imagery",
"xbsjImageryProvider": {
"XbsjImageryProvider": {
"url": "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
}
}
}
},
{
"czmObject": {
"xbsjType": "Imagery",
"xbsjImageryProvider": {
"XbsjImageryProvider": {
"url": "http://t6.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=2cda5caa13d033e23a39407fc62accdb",
"dstCoordType": "GCJ02"
}
}
}
},
/** 中國14級地形
{
"czmObject": {
"xbsjType": "Terrain",
"xbsjTerrainProvider": {
"type": "XbsjCesiumTerrainProvider",
"XbsjCesiumTerrainProvider": {
"url": "http://lab.earthsdk.com/terrain/577fd5b0ac1f11e99dbd8fd044883638",
"requestVertexNormals": true,
"requestWaterMask": true
}
}
}
}
*/
]
}
earth.sceneTree.root.children[1].enabled = false
earth._viewer.camera.flyTo({
destination: new Cesium.Cartesian3(-2102351.020236049, 4605886.135770324, 3909950.0555654215),
orientation: {
heading: 6.270938378736673,
pitch: -0.8989671219533877,
roll: 6.282706587562512
},
duration: 3
});


this._odlines = new XE.Obj.ODLines(earth);
this._odlines.translucentPass = false;
this._odlines.color = [1, 1, 1, 1];

window.earth = earth
window.odlines = this._odlines

loadData((data, timeDuration) => {
this._odlines.data = data;
this._odlines.timeDuration = timeDuration;
this._odlines.playing = true;
});
},
// 1.2 資源銷燬
beforeDestroy() {
// vue程式銷燬時,需要清理相關資源
this._fpsUnbind = this._fpsUnbind && this._fpsUnbind();
this._elapsedTimeUnbind = this._elapsedTimeUnbind && this._elapsedTimeUnbind();
this._earth = this._earth && this._earth.destroy();
},
}

// 2 建立vue程式
// XE.ready()用來載入Cesium.js等相關資源
XE.ready().then(() => {
var app = new Vue({
el: '#vueApp',
components: {
EarthComp,
},
});
});
</script>
</body>

</html>

不足

OD線效果在手機瀏覽器裡無法顯示,後面想辦法解決一下 地形 + 貼地、移動端適配的問題。

原文地址

灑家廢物的部落格

相關文章