最近产品提出一个需求,在咱们使用的腾讯地图上为线路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线路就带有方向箭头了,能够很清晰的看出线路的走向了。