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

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動(dòng)軟件開(kāi)發(fā)培訓(xùn),網(wǎng)站設(shè)計(jì)培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

查找騰訊地圖JS API提供的API,沒(méi)有找到對(duì)應(yīng)的支持,詢問(wèn)負(fù)責(zé)騰訊地圖的人也得到了同樣的答案,即地圖JS API不支持線路畫(huà)方向。于是否就利用地圖的Marker類配合旋轉(zhuǎn)來(lái)實(shí)現(xiàn)這個(gè)功能。

實(shí)現(xiàn)原理

因?yàn)槭抢?code style="margin: 1px 5px; padding: 0px 5px !important; line-height: 1.8; vertical-align: middle; display: inline-block; font-family: "Courier New", sans-serif !important; font-size: 12px !important; background-color: rgb(245, 245, 245) !important; border: 1px solid rgb(204, 204, 204) !important; border-radius: 3px !important;">Marker來(lái)實(shí)現(xiàn)Polyline帶方向箭頭功能,所以要根據(jù)線路不同局部的具體走向來(lái)旋轉(zhuǎn)Marker的Icon,從而實(shí)現(xiàn)該功能。

另外,我們需要知道:

Marker的旋轉(zhuǎn)方向是跟時(shí)針?lè)较虮3忠恢碌?,角度為正表示順時(shí)針旋轉(zhuǎn),負(fù)表示逆時(shí)針旋轉(zhuǎn)。

騰訊地圖的JS API雖然沒(méi)有提供畫(huà)箭頭的支持,但是可喜的是,騰訊地圖提供了一個(gè)類qq.maps.geometry.spherical,它提供了一些方法用于計(jì)算面積、角度和距離,具體可以參考這里。

其中,對(duì)于我們實(shí)現(xiàn)方向箭頭有用的是以下兩個(gè)api:

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

  • computeDistanceBetween(from:LatLng, to:LatLng, radius?:Number): 返回兩坐標(biāo)點(diǎn)間的距離。

結(jié)合上面所描述的,具體的實(shí)現(xiàn)原理圖如下圖展示:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動(dòng)軟件開(kāi)發(fā)培訓(xùn),網(wǎng)站設(shè)計(jì)培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

具體實(shí)現(xiàn)步驟:

  • 利用computeHeading方法計(jì)算航向,然后由其計(jì)算Marker旋轉(zhuǎn)的角度。

注意:

由航向計(jì)算Marker旋轉(zhuǎn)角度,需要根據(jù)具體的Marker的Icon圖形來(lái)具體分析,不能一概而論。比如本人項(xiàng)目使用的Marker icon圖為水平方向的箭頭,如下圖:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動(dòng)軟件開(kāi)發(fā)培訓(xùn),網(wǎng)站設(shè)計(jì)培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

那么,根據(jù)該icon圖可以計(jì)算對(duì)應(yīng)的marker旋轉(zhuǎn)角度,具體計(jì)算規(guī)則如下圖所示。其它方向的Icon可以推算出對(duì)應(yīng)的計(jì)算規(guī)則。

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動(dòng)軟件開(kāi)發(fā)培訓(xùn),網(wǎng)站設(shè)計(jì)培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

  • 利用computeDistanceBetween方法計(jì)算兩坐標(biāo)點(diǎn)中間位置的經(jīng)緯度

  • 創(chuàng)建Marker實(shí)例,并設(shè)置其Icon和旋轉(zhuǎn)角度

實(shí)現(xiàn)代碼

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

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

      var linePoint = polyline.getPath();//線的經(jīng)緯度坐標(biāo)
      var arrowCount= linePoint.length;
      for(let i = 1; i < arrowCount; i+=2){//不是每?jī)蓚€(gè)點(diǎn)之間都畫(huà)箭頭,而是每隔一個(gè)間隔畫(huà)一個(gè)箭頭
        let pixelStart = linePoint.getAt(i-1); 
        let pixelEnd = linePoint.getAt(i);
        let rotation, arrowLatLng, marker;
        let spherical = qq.maps.geometry.spherical;
        let distance = spherical.computeDistanceBetween(pixelStart, pixelEnd); //計(jì)算兩經(jīng)緯度坐標(biāo)件的距離

        if(distance <= 15) {//距離太近小于15m的兩經(jīng)緯度坐標(biāo)點(diǎn)間不畫(huà)方向
          continue;
        }

        rotation = spherical.computeHeading(pixelStart, pixelEnd);//兩經(jīng)緯度坐標(biāo)點(diǎn)之間的航向
        //計(jì)算兩經(jīng)緯度坐標(biāo)點(diǎn)中間位置的經(jīng)緯度
        arrowLatLng = spherical.computeOffsetOrigin(pixelEnd, distance/2, rotation);

        marker = addMarker(arrowLatLng.lat, arrowLatLng.lng, defaultOps);
        let heading = computeRotaion(rotation); //由兩坐標(biāo)點(diǎn)之間的航向計(jì)算marker要旋轉(zhuǎn)的角度
        marker.setRotation(heading);
      }
    }

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

分類: 其他

http://www.cnblogs.com/wonyun/p/7152017.html