web技術分享| 【地圖】實現自定義的軌跡回放

語言: CN / TW / HK

在這裡插入圖片描述

實現(軌跡回放)方式有兩種:

  • 第一種是使用 JS APIAMap.PolyLine(折線)等圖形配合實現。
  • 第二種是使用 JS APIAMapUI 元件庫 配合使用,利用 PathSimplifier軌跡展示元件)繪製出行動軌跡。

方案選擇

以上兩種實現方式我們可以根據兩個因素 來決定哪一種更加適合自己:節點數量 的多少、排布的密集度

前者適合節點數量較少,排布比較稀鬆,例如,計程車軌跡回放,計程車行駛速度快,週期上報的時間也會相對較長。後者更加針對節點數量巨大、排布密集的路徑,按秒記錄位置的飛機行進軌跡,精細的地理邊界等等。

實現流程

無論選擇兩種方式,我們都需要先收集到客戶端上報的資訊,這些資訊可以自定義,通常我們會包含:經緯度、速度、逆編碼之後的地理位置、方向、海拔 等基本地理資訊,同時我們也可以加入一些自定義 的資訊,例如:人員資訊(頭像暱稱等)、出行資訊(訂單等)。

實現的流程:

  • 客戶端按(時間)週期上報地理資訊以及自定義資訊。
  • 服務端按時間軸儲存客戶上報的資訊。
  • 按(時間等)條件查詢出使用者的軌跡,並通過簡化演算法去除一部分節點(例如,節點距離十分微小、或者多個點都在同一條直線、3點之間,其中一點略有偏差無法繪製成直線等等),最終獲得適合繪製的路徑(陣列)。
  • 根據路徑去繪製使用者的行動軌跡。

路徑簡化演算法(可選)

客戶端上報的資料是按時間週期上報的,也就是說每個時間都對應了一個經緯度,經緯度在地圖上就是一個又一個點,將這些點連線時,我們會得到 N 多條折線,為了繪製的軌跡更加美觀,行動路線更加明確平滑,通常我們需要一個演算法來簡化折線。

例如:

  • A 點和 B 點,兩者距離不到 1 畫素,則可以去掉 B 點,只留 A 點。
  • ABC 三點在一條直線上,或者,B 點僅僅稍微偏離 A 點和 C 點構成的線段,那麼 B 點就可以去掉。

這裡官方也推薦了一種演算法庫 simplify.js供大家參考,這裡不做過多的闡述。

實現示例

車輛軌跡回放

這裡我們使用第一種方式來實現 - 利用 JS APIAMap.PolyLine

在這裡插入圖片描述

實現原理:

  • 在地圖上繪製車輛標記AMap.Marker)。
  • 利用 AMap.PolyLine 繪製出兩條軌跡:歷史軌跡駕駛途徑過的軌跡,以顏色區分。
  • 按照一定的速度使車輛前進,並監聽 Maker 移動的事件,在事件回撥中,將車輛(Marker)位置設定為地圖中心點,給使用者視覺主觀上一種車輛在前進的感覺,同時延長駕駛途徑過的軌跡
  • 對於實現場景比較複雜的,需要進行自定義處理的比如:
  • 檢視每個節點的資料,我們可以把每個節點給繪製出來,節點被點選時顯示該節點的資料。
  • 移動倍速播放,首先按上報的時間間隔來播放,選擇倍速之後,改變 MarKer 移動的 duration
  • 其他自定義。

自定義 API

我們可以讓車輛:

  • 開始移動
  • 暫停移動
  • 恢復移動
  • 停止移動

程式碼示例

``` AMap.plugin('AMap.MoveAnimation', function(){ var marker, lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];

var map = new AMap.Map("container", { resizeEnable: true, center: [116.397428, 39.90923], zoom: 17 });

marker = new AMap.Marker({ map: map, position: [116.478935,39.997761], icon: "http://a.amap.com/jsapi_demos/static/demo-center-v2/car.png", offset: new AMap.Pixel(-13, -26), });

// 繪製歷史軌跡 var polyline = new AMap.Polyline({ map: map, path: lineArr, showDir:true, strokeColor: "#28F", //線顏色 // strokeOpacity: 1, //線透明度 strokeWeight: 6, //線寬 // strokeStyle: "solid" //線樣式 });
// 駕駛途徑過的軌跡 var passedPolyline = new AMap.Polyline({ map: map, strokeColor: "#AF5", //線顏色 strokeWeight: 6, //線寬 });

// 監聽車輛移動事件

marker.on('moving', function (e) { // 延長駕駛途徑過的軌跡 passedPolyline.setPath(e.passedPath); // 將車輛位置設定為地圖中心點 map.setCenter(e.target.getPosition(),true) });

map.setFitView();

// 開始移動

window.startAnimation = function startAnimation () { marker.moveAlong(lineArr, { // 每一段的時長 duration: 500,//可根據實際採集時間間隔設定 // JSAPI2.0 是否延道路自動設定角度在 moveAlong 裡設定 autoRotation: true, }); }; // 暫停移動 window.pauseAnimation = function () { marker.pauseMove(); }; // 恢復移動 window.resumeAnimation = function () { marker.resumeMove(); }; // 停止移動 window.stopAnimation = function () { marker.stopMove(); }; }); ```

參考:http://lbs.amap.com/demo/jsapi-v2/example/marker/replaying-historical-running-data

飛機航班的軌跡回放

使用 JS APIAMapUI 元件庫 配合使用,利用 PathSimplifier軌跡展示元件)繪製出行動軌跡,這種方案比較簡單,只需要進行一些配置即可,例如說方案一中的倍速播放就需要計算,同時還存在不能動態改變倍速的弊端,但是方案二卻不會存在。

實現原理:

  • 在地圖上繪製飛機標記AMap.Marker)。
  • 利用 AMap.PolyLine 繪製出兩條軌跡:歷史軌跡駕駛途徑過的軌跡,以顏色區分。
  • 配置軌跡的顏色,動畫的速度等等。
  • 對於實現場景比較複雜的,需要進行自定義處理的,可以在PathSimplifier 提供的回撥中進行配置及處理。

示例程式碼

``` //載入PathSimplifier,loadUI的路徑引數為模組名中 'ui/' 之後的部分 AMapUI.load(['ui/misc/PathSimplifier'], function(PathSimplifier) {

if (!PathSimplifier.supportCanvas) {
    alert('當前環境不支援 Canvas!');
    return;
}

//啟動頁面
initPage(PathSimplifier);

});

function initPage(PathSimplifier) { //建立元件例項 var pathSimplifierIns = new PathSimplifier({ zIndex: 100, map: map, //所屬的地圖例項 getPath: function(pathData, pathIndex) { //返回軌跡資料中的節點座標資訊,[AMap.LngLat, AMap.LngLat...] 或者 [[lng|number,lat|number],...] return pathData.path; }, getHoverTitle: function(pathData, pathIndex, pointIndex) { //返回滑鼠懸停時顯示的資訊 if (pointIndex >= 0) { //滑鼠懸停在某個軌跡節點上 return pathData.name + ',點:' + pointIndex + '/' + pathData.path.length; } //滑鼠懸停在節點之間的連線上 return pathData.name + ',點數量' + pathData.path.length; }, renderOptions: { //軌跡線的樣式 pathLineStyle: { strokeStyle: 'red', lineWidth: 6, dirArrowStyle: true } } });

//這裡構建兩條簡單的軌跡,僅作示例
pathSimplifierIns.setData([{
    name: '軌跡0',
    path: [
        [100.340417, 27.376994],
        [108.426354, 37.827452],
        [113.392174, 31.208439],
        [124.905846, 42.232876]
    ]
}, {
    name: '大地線',
    //建立一條包括500個插值點的大地線
    path: PathSimplifier.getGeodesicPath([116.405289, 39.904987], [87.61792, 43.793308], 500)
}]);

//建立一個巡航器
var navg0 = pathSimplifierIns.createPathNavigator(0, //關聯第1條軌跡
    {
        loop: true, //迴圈播放
        speed: 1000000
    });

navg0.start();

} ```

參考:http://lbs.amap.com/demo/amap-ui/demos/amap-ui-pathsimplifier/index

在這裡插入圖片描述