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

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

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

實現原理

由於是利用Marker來實現Polyline帶方向箭頭功能,因此要根據線路不一樣局部的具體走向來旋轉Marker的Icon,從而實現該功能。java

另外,咱們須要知道:api

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

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

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

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

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

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

具體實現步驟:

  • 利用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線路就帶有方向箭頭了,能夠很清晰的看出線路的走向了。

相關文章
相關標籤/搜索