最近產品提出一個需求,在咱們使用的騰訊地圖上爲線路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線路就帶有方向箭頭了,能夠很清晰的看出線路的走向了。