騰訊地圖JS API實現帶方向箭頭的線路Polyline


最近產品提出一個需求,在我們使用的騰訊地圖上為線路polyline添加線路方向。例如下圖所示:

查找騰訊地圖JS API提供的API,沒有找到對應的支持,詢問負責騰訊地圖的人也得到了同樣的答案,即地圖JS API不支持線路畫方向。於是否就利用地圖的Marker類配合旋轉來實現這個功能。

實現原理

因為是利用Marker來實現Polyline帶方向箭頭功能,所以要根據線路不同局部的具體走向來旋轉Marker的Icon,從而實現該功能。

另外,我們需要知道:

Marker的旋轉方向是跟時針方向保持一致的,角度為正表示順時針旋轉,負表示逆時針旋轉。

騰訊地圖的JS API雖然沒有提供畫箭頭的支持,但是可喜的是,騰訊地圖提供了一個類qq.maps.geometry.spherical,它提供了一些方法用於計算面積、角度和距離,具體可以參考這里

其中,對於我們實現方向箭頭有用的是以下兩個api:

  • computeHeading(from:LatLng, to:LatLng): 返回從一個坐標到另一個坐標的航向。航向是指從一個坐標指向另一個坐標的向量與正北方向的夾角,范圍為[-180,180)。

  • computeDistanceBetween(from:LatLng, to:LatLng, radius?:Number): 返回兩坐標點間的距離。

結合上面所描述的,具體的實現原理圖如下圖展示:

具體實現步驟:

  • 利用computeHeading方法計算航向,然后由其計算Marker旋轉的角度。

注意:

由航向計算Marker旋轉角度,需要根據具體的Marker的Icon圖形來具體分析,不能一概而論。比如本人項目使用的Marker icon圖為水平方向的箭頭,如下圖:

那么,根據該icon圖可以計算對應的marker旋轉角度,具體計算規則如下圖所示。其它方向的Icon可以推算出對應的計算規則。

  • 利用computeDistanceBetween方法計算兩坐標點中間位置的經緯度

  • 創建Marker實例,並設置其Icon和用marker實例的setRotation方法來旋轉角度

注意:

有官方聲明marker實例的setRotation方法的旋轉角度范圍為0~360,所以根據計算的旋轉角度必須為這一范圍,否則可能會出現圖形走樣的情況。

實現代碼

正如上面描述的實現原理,下面即是實現為Polyline實例添加方向箭頭Marker的實現代碼:

function setIcon(marker){
 var size = new qq.maps.Size(9, 8); //marker icon圖片大小為18px * 16px, 等比例縮放
 var anchor = new qq.maps.Point(5, 4); //經緯度點在圖標中的位置點
 var image = require('imgs/arrow.png');
 var icon = new qq.maps.MarkerImage(image, size, undefined, anchor, size);
 marker.setIcon(icon); 
}
//畫marker
function addMarkers(lat, lng, opts){
 var position = new qq.maps.LatLng(lat, lng);
 var defaultOps = {
     map: mapInstance, //mapInstance為對應的qq map實例
     position,
     zIndex: 8,
     visible: true,
     draggable: false
  }
  var options = Object.assign({}, defaultOpts, opts || {});
  var marker = new qq.maps.Marker(options);
  setIcon(marker);
  return marker
}
//計算線路方向箭頭旋轉的方向,heading為兩個經緯度點之間的航向(兩點之間與正北方向的夾角),其范圍為[-180, 180)
function computeRotaion(heading){
 let rotation;
  if(heading < 0) {
    rotation = 270 + heading;
  }else {
    rotation = heading - 90;
  }
  return rotation
}
//為polyline添加方向marker
function addArrowMarkers(polyline){
      var defaultOps = {
        cursor: 'normal',
        zIndex: polyline.getZIndex() + 1,
        clickable: false,
        draggable: false
      };

      var linePoint = polyline.getPath();//線的經緯度坐標
      var arrowCount= linePoint.length;
      for(let i = 1; i < arrowCount; i+=2){//不是每兩個點之間都畫箭頭,而是每隔一個間隔畫一個箭頭
        let pixelStart = linePoint.getAt(i-1); 
        let pixelEnd = linePoint.getAt(i);
        let heading, rotation, arrowLatLng, marker;
        let spherical = qq.maps.geometry.spherical;
        let distance = spherical.computeDistanceBetween(pixelStart, pixelEnd); //計算兩經緯度坐標件的距離

        if(distance <= 15) {//距離太近小於15m的兩經緯度坐標點間不畫方向
          continue;
        }

        heading = spherical.computeHeading(pixelStart, pixelEnd);//兩經緯度坐標點之間的航向
        //計算兩經緯度坐標點中間位置的經緯度
        arrowLatLng = spherical.computeOffsetOrigin(pixelEnd, distance/2, heading);

        marker = addMarker(arrowLatLng.lat, arrowLatLng.lng, defaultOps);
        rotation = computeRotaion(heading); //由兩坐標點之間的航向計算marker要旋轉的角度
        marker.setRotation(rotation);
      }
    }

至此,帶方向的polyline線路就帶有方向箭頭了,可以很清晰的看出線路的走向了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM