標籤:動效 ret 擷取 rip move 方案 effect turn 定位
相信只要是使用百度地圖做即時定位服務的朋友都會遇到這個問題,在對座標位置進行覆蓋物展示的時候,會出現由於擷取座標資料時間或者兩個座標點相距過遠,導致在視覺上看Marker移動就像“殭屍跳”一樣,一蹦一蹦的給客戶看分分鐘鄙視你到不能自已。另外如果用的是有指向性表徵圖ICON的時候,更會引來吐槽~誒誒誒,你這小車車怎麼在這個立交橋轉彎的時候車頭向著後面呢?怎麼搞得嘛你!會不會弄啊你!
所以今天參照百度大大提供的路書開源檔案實現下自己的需求,記錄一下以便提供參考。
一、覆蓋物在擷取座標資料的同時,在座標點之間平滑的移動
首先,之所以會出現殭屍跳的效果,是因為項目是根據即時座標資料進行定位,所以存在一個等待新資料的過程,而對於覆蓋物的座標改變就是一個setPosition(BMap.Point)方法而已也就造成了停頓。所以目前暫且解決方案就是:讓他這個覆蓋物在這個等待的期間找點事情做,不要一下就直接從起點蹦到終點了,慢慢的移動過去。小碎步,平滑的的移動過去~~
怎麼移動呢?此時這個事情就可以轉化為已知起始點座標,進行移動覆蓋物的這麼過程了,說白了就是讓他覆蓋物在兩個點連成的這條線上多執行幾次setPosition(BMap.Point),一次步子別邁那麼大,只要保證在下次新座標來之前到達就行了。
那麼問題又來了,這兩條線上的點我怎麼知道呢? 因為擷取到的經緯度座標是球面座標,所以要先轉換為平面座標 {BMap.Pixel}= map.getMapType().getProjection().lngLatToPoint(BMap.Point);
然後小運算下(參照路書開源檔案)
1 /* 2 *緩動效果 3 *初始座標,目標座標,當前的步長,總的步長 4 *@param{BMap.Pixel} initPos 初始平面座標 5 *@parm{BMap.Pixel} targetPos 目標平面座標 6 *@param{number} 當前幀數 7 *@param {number} count 總幀數 8 */ 9 this.linear = function (initPos, targetPos, currentCount, count) {10 var b = initPos, c = targetPos - initPos, t = currentCount,11 d = count;12 return c * t / d + b;13 }14 15 var x = effect(_prvePoint.x, _newPoint.x, currentCount, count),16 y = effect(_prvePoint.y, _newPoint.y, currentCount, count);
經過計算得到的是一個平面座標pixel(x,y)。然後再將平面座標轉換為球面座標給Marker進行定位即可。(這些方法在百度類庫參考文檔中都可以找得到的。魔法門: http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E5%9C%B0%E5%9B%BE%E7%B1%BB%E5%9E%8B%E7%B1%BB)
var pos = map.getMapType().getProjection().pointToLngLat(new BMap.Pixel(x, y));
修改覆蓋物定位座標值。當然這個地方要進行多次執行也就需要個setInterval咯 這裡面的
me._em._newPointMark.setPosition(pos);
完整方法:
1 /** 2 *小車移動 3 *@param {Point} prvePoint 開始座標(PrvePoint) 4 *@param {Point} newPoint 目標點座標 5 *@param {Function} 動畫效果 6 *@return 無傳回值 7 */ 8 9 this.Move = function (prvePoint, newPoint, effect, setRotation) {10 var me = this,11 //當前幀數12 currentCount = 0,13 //初始座標14 _prvePoint = me._projection.lngLatToPoint(prvePoint),//將球面座標轉換為平面座標15 //擷取結束點的(x,y)座標16 _newPoint = me._projection.lngLatToPoint(newPoint),17 //兩點之間要迴圈定位的次數18 count = me._runTime / me._intervalTimer;19 //兩點之間勻速移動20 me._intervalFlag = setInterval(function () {21 //兩點之間當前幀數大於總幀數的時候,則說明已經完成移動22 if (currentCount >= count) {23 clearInterval(me._intervalFlag);24 } else {25 //動畫移動26 currentCount++;//計數27 var x = effect(_prvePoint.x, _newPoint.x, currentCount, count),28 y = effect(_prvePoint.y, _newPoint.y, currentCount, count);29 //根據平面座標轉化為球面座標30 var pos = map.getMapType().getProjection().pointToLngLat(new BMap.Pixel(x, y));31 //設定marker角度(兩點之間的距離車的角度保持一致)32 if (currentCount == 1) {33 //轉換角度 34 setRotation(prvePoint,newPoint, me._em);35 }36 //正在移動37 38 me._em._newPointMark.setPosition(pos);39 }40 }, me._intervalTimer);41 me._em._prvePoint = newPoint;42 }
值得注意的是,這裡關鍵的就是這個count = me._runTime / me._intervalTimer; 決定了在這兩個點之間要走多少個小碎步~~
這個count的由來也得根據自身項目需求計算。
1,通過控制覆蓋物移動資料控制動畫效果。這種方法就需要通過 速度與每次執行的時間計算得到每次執行前進的距離,然後在與兩點之間的距離做商得到要執行的次數。(這種方法呢適合做曆史軌跡回放這種,所有座標資訊都已經知道,一個點執行完就跳到下一個座標,只是通過控制速度來控制動畫的展示快慢)
2,通過控制平緩移動過程的總時間與每次執行間隔時間來控制動畫效果。此方法就是文中的樣本,直接二者做商即可得到要執行的次數。(這種方法適合做即時定位使用,因為下一次定位元據是間隔多少時間後接收,這個使我們可以控制的,所以這個平緩移動的動畫過程的總時間也是可以由我們自己控制的)
二、車頭指向行徑方向
這個功能其實就是改變覆蓋物的旋轉角度em._newPointMark.setRotation(number);
只是還是那個原因,因為得到的座標點資料是球面座標,所以還是要先進行轉為平面座標才好計算,然後通過三角函數tan#$%^&*( 計算後得到兩個點之間的角度值。此部分沒有太多個人化的邏輯操作,直接參照百度大大的就行了。
1 /** 2 *在每個點的真實步驟中設定小車轉動的角度 3 *@param{BMap.Point} curPos 起點 4 *@param{BMap.Point} targetPos 終點 5 */ 6 this.setRotation = function (curPos, targetPos, em) 7 { 8 var me = this; 9 var deg = 0;10 curPos = map.pointToPixel(curPos);11 targetPos = map.pointToPixel(targetPos);12 if (targetPos.x != curPos.x) {13 var tan = (targetPos.y - curPos.y) / (targetPos.x - curPos.x),14 atan = Math.atan(tan);15 deg = atan * 360 / (2 * Math.PI);16 if (targetPos.x < curPos.x) {17 deg = -deg + 90 + 90;18 } else {19 deg = -deg;20 }21 em._newPointMark.setRotation(-deg);22 23 } else {24 var disy = targetPos.y - curPos.y;25 var bias = 0;26 if (disy > 0)27 bias = -128 else29 bias = 130 em._newPointMark.setRotation(-bias * 90);31 }32 return;33 }
百度地圖JavascriptApi Marker平滑移動及車頭指向行徑方向