博客 / 詳情

返回

騰訊地圖api,根據路線畫自定義箭頭

我遇到的情況:

1、使用騰訊地圖畫出路徑,並在地圖上表示方向(也就是箭頭指向)

我查了很多的資料,並沒有詳細的結論,我按照api給的方法,我自定義做出的效果
vue+element+騰訊地圖API,(僅供參考)
效果圖如下:
效果圖

思路

1、首先看是否跟我使用的方法聲明Map一致的方法,騰訊地圖的JavaScript API GL的api(如有不同,可以看邏輯,邏輯是一樣的,但是需要自己去專研下代碼)
https://lbs.qq.com/webApi/jav...
2、如果看到這裏,那我先講下邏輯,我之前考慮過方案:
(1)地圖自帶的線段帶的箭頭指向(跟實際需求不符) ,而且,箭頭不能大於具體寬度,這樣我們沒辦法擴展,果然放棄了(希望騰訊地圖api,這裏可以改善下)

這時示例地址:
https://lbs.qq.com/webDemoCen...
這是api地址:
https://lbs.qq.com/webApi/jav...

image.png

(2)自定義DOM覆蓋物(DOMOverlay)這是百度搜索最多的方案,但是我看過,可以做到,聲明img結構(img就是箭頭的圖片),按照img旋轉不同的角度所得到的,但是會出現一種bug,就是不會隨着地圖縮放而進行變化,這就很惱火了,所以我就沒考慮(測試肯定給我提bug)
(3)這種目前我使用的一種,根據兩點的座標,判斷角度、拿到箭頭的三角座標給畫兩條線,結合成箭頭形狀,(説白點:就是跟畫線一樣,畫出來的箭頭)
(4)根據畫多邊形,進行繪製,但是原理都是一樣的,先找到箭頭的三角座標,之後進行處理,需要看具體的需求,(如果是箭頭是覆蓋有顏色的,那就先拿到座標,進行多邊形繪製,效果也能實現)。重點:拿到箭頭的三個角的座標!!!
(5)其他的方案,大同小異,都是根據需求,結合座標,進行繪製。

下面我就具體講下第三種

1、聲明map以及polylineLayer(前面是地圖,後面是畫線),點位的聲明,我就不做粘貼的,會一點都應該會撒點

<div class="echarts_heating" id="map"></div> //html

var map = new TMap.Map(document.getElementById("map"), {
    zoom: 11, //設置地圖縮放級別
    center: center, //設置地圖中心點座標
    mapStyleId: "style1", //個性化樣式默認style
    disableDefaultUI: true,
    showControl: false,
    baseMap: {
      type: "vector",
      features: ["base", "building3d", "point"], // 隱藏矢量文字可根據需求去配置
      
    },
    // mapStyleId: "style1", //設置樣式ID,本例中的key綁定的style1為經典地圖樣式
    //(若使用未綁定的樣式或無效ID,則會提示錯誤,並用地圖默認樣式顯示)
  });

畫線polylineLayer的聲明以及線段的風格

  
var polylineLayer = new TMap.MultiPolyline({
    map, // 繪製到目標地圖
    // 折線樣式定義
    styles: {
      style_blue: new TMap.PolylineStyle({
        color: "#F15E59", // 線填充色
        width: 3, // 折線寬度
        lineCap: "round", // 線端頭方式
      }),
      style_dash: new TMap.PolylineStyle({
        color: "#F15E59", // 線填充色
        width: 3, // 折線寬度
        lineCap: "butt", // 線端頭方式
        dashArray: [6, 5], // 虛線展示方式
      }),
    },
    geometries: [],
  });

在vue的methods中

 //arr是點位座標,[起點,終點] index,indexli,是為了不同的id所循環出來的,方便不同的命名,可取消
computeHeading(arr, index, indexli) {
  // 根據computeDistance去查詢兩點之前的距離
  let computeDistance = TMap.geometry.computeDistance(arr);
  // 查詢兩點之前的距離,如果距離過短,不進行任何處理
  if (computeDistance > 1500) {
    let computeHeading = TMap.geometry.computeHeading(arr[0], arr[1]);
    // 根據computeHeading,獲取當前點位的的角度

    let du; //這個變量只是為了不讓箭頭的頂端和icon重疊而聲明的反向的角度
    if (computeHeading > 0) {
      du = computeHeading - 180;
      // 因為地圖的座標系中只有【180,-180】所以進行逆時針轉換
    } else {
      du = computeHeading + 180;
    }
    // path0 就是根據computeDestination,反向拿到的新的箭頭頂點的座標
    // 其中200,是icon與頂點的距離,可調整
    let path0 = TMap.geometry.computeDestination(arr[1], du, 200);
    // top1,top2,是畫箭頭的角度獲取,
    // 因為地圖的座標系中只有【180,-180】所以進行逆時針轉換
    // 我這邊取得是偏移40度, 140,220,可調整
    let top1 = this.computeRotaion(computeHeading + 140);
    let top2 = this.computeRotaion(computeHeading + 220);
    // path1,path2是根據箭頭的座標,預計畫的線段長度、以及角度,去獲取箭頭兩邊的點位座標
    let path1 = TMap.geometry.computeDestination(path0, top1, 1200);
    let path2 = TMap.geometry.computeDestination(path0, top2, 1200);
    // console.log("path1", path1);
    // 根據獲得到箭頭的三點左邊,進行繪製,這邊也可以繪製覆蓋性多邊形 index,indexli,可修改,可取消,只要是不同的id即可
    this.polylineLayer.add({
      styleId: "style_blue",
      id: "pl1_" + index + "_" + indexli,
      paths: [path0, path1],
    });
    this.polylineLayer.add({
      styleId: "style_blue",
      id: "pl2_" + index + "_" + indexli,
      paths: [path0, path2],
    });
    // 根據不同長度,做不同的方案,根據長度在10000米以上的,我這邊做中間的箭頭,原理同上//
    if (computeDistance > 10000) {
      // 先拿到中間的點位座標
      let pathzhong = TMap.geometry.computeDestination(
        arr[1],
        du,
        computeDistance / 2
      );
      // path3,path4,是中間箭頭兩邊點位座標,
      let path3 = TMap.geometry.computeDestination(pathzhong, top1, 1200);
      let path4 = TMap.geometry.computeDestination(pathzhong, top2, 1200);
      // 在根據三點座標,進行畫線,作出箭頭 index,indexli,可修改,可取消,只要是不同的id即可
      this.polylineLayer.add({
        styleId: "style_blue",
        id: "pl3_" + index + "_" + indexli,
        paths: [pathzhong, path3],
      });
      this.polylineLayer.add({
        styleId: "style_blue",
        id: "pl4_" + index + "_" + indexli,
        paths: [pathzhong, path4],
      });
    }
  }
},
// 由於地圖座標的範圍【180,-180】所以進行轉化
computeRotaion(heading) {
  let rotation;
  if (heading > 180) {
    rotation = heading - 360;
  } else {
    rotation = heading;
  }
  return rotation;
}

註釋中有完整的解釋,需要耐心去看,也可以根據自身的情況去修改。我這裏沒有進行封裝,但是可以正常的使用,如果你需要多組件調用,,需要自己去封裝搞下,我就不在這把我需求封裝的拿出來了,畢竟需求不同

總結:

希望多提意見,有更好的建議,可以留言,虛心學習!

卑微的小劉!

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.