zoukankan      html  css  js  c++  java
  • 腾讯地图JS API实现带方向箭头的线路Polyline

    最近产品提出一个需求,在我们使用的腾讯地图上为线路polyline添加线路方向。例如下图所示:

    查找腾讯地图JS API提供的API,没有找到对应的支持,询问负责腾讯地图的人也得到了同样的答案,即地图JS API不支持线路画方向。于是否就利用地图的Marker类配合旋转来实现这个功能。

    实现原理

    因为是利用Marker来实现Polyline带方向箭头功能,所以要根据线路不同局部的具体走向来旋转Marker的Icon,从而实现该功能。

    另外,我们需要知道:

    Marker的旋转方向是跟时针方向保持一致的,角度为正表示顺时针旋转,负表示逆时针旋转。

    腾讯地图的JS API虽然没有提供画箭头的支持,但是可喜的是,腾讯地图提供了一个类qq.maps.geometry.spherical,它提供了一些方法用于计算面积、角度和距离,具体可以参考这里

    其中,对于我们实现方向箭头有用的是以下两个api:

    • computeHeading(from:LatLng, to:LatLng): 返回从一个坐标到另一个坐标的航向。航向是指从一个坐标指向另一个坐标的向量与正北方向的夹角,范围为[-180,180)。

    • computeDistanceBetween(from:LatLng, to:LatLng, radius?:Number): 返回两坐标点间的距离。

    结合上面所描述的,具体的实现原理图如下图展示:

    具体实现步骤:

    • 利用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线路就带有方向箭头了,可以很清晰的看出线路的走向了。

  • 相关阅读:
    学业优秀者汇总
    计算机类教学质量国家标准(含信息安全专业)
    从《构建之法》到《终身幼儿园》
    2019-2020-1 《信息安全专业导论》教学进程
    程序设计快速入门
    铜齿铁牙UP计划
    ios app 提交评审注意事项
    IOS开发之不同版本适配问题2(#ifdef __IPHONE_7_0)
    iOS:个性化UITextView(缩进,行距,铺满)
    iOS 同一设备内的应用之间资源共享的实现
  • 原文地址:https://www.cnblogs.com/wonyun/p/7152017.html
Copyright © 2011-2022 走看看