• OpenLayers使用高德导航接口实现动画animate


    需求:项目需要做一个救援动画效果
    技术栈:react、openlayer、高德导航接口、天地图导航接口

    零、选择导航接口

    老大最开始建议使用天地图导航接口,测试后接口响应时间大约为30秒以上,达不到商用条件。因此选择高德的接口。

    一、调用高德接口

    1、1申请key

    在高德官网注册用户,创建应用,申请key
    地址:https://lbs.amap.com/api/webservice/summary
    点击【获取key】,按提示进入控制台,创建应用,创建key
    在这里插入图片描述
    在这里插入图片描述
    创建应用,在应用下边添加key。我需要调用webapi中的【路径规划API】所以选择的是Web服务
    在这里插入图片描述

    1.2测试接口

    https://restapi.amap.com/v3/direction/driving?origin=[出发经度],[出发纬度]&destination=[目标经度],[目标纬度]&extensions=all&output=json&key=[key]
    在这里插入图片描述

    二、实现导航

    2.1、拾取爆点坐标

    爆点的样式:对点要素的样式设置为pipeBroken图片

    const pipeBrokenStyle = new Style({
      image: new Icon({
        anchor: [0.5, 20],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: pipeBroken,
      }),
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    处理点击地图事件。获取鼠标点击的坐标,构建点要素,绘制到地图上。同时写入state。构建查询资源的参数

     beginGetFeatureInfo = (event) => {
        const {map} = this.props;
        const {featuresVectorSource, clickFeature} = this.state;
        if (clickFeature) {
          if (featuresVectorSource.getFeatures().length > 0) {
            try {
              clearMap(map);
            } catch (e) {
              console.log(e);
            }
          }
        }
        const pipeBrokenFeature = new Feature({
          geometry: new Point(event.coordinate),
        });
        pipeBrokenFeature.setStyle(pipeBrokenStyle);
        const pointInfo = `point(${event.coordinate[0]} ${event.coordinate[1]})`;
        this.setState({clickFeature: pipeBrokenFeature, pointInfo,}, () => {
          featuresVectorSource.addFeature(pipeBrokenFeature);
          this.getResources();
        });
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.2、获取资源坐标

    调用业务系统接口查询资源的坐标,此部分按自己的业务系统处理即可,不做展示。

    2.3、坐标转换

    此时具备了资源坐标和爆点的坐标,构造高德导航参数即可。但是项目中使用的是3857坐标系,需要进行转换。
    3857转4326使用的是proj4组件
    4326转gcj02使用的是coordtransform组件(
    https://www.npmjs.com/package/coordtransform
    https://github.com/wandergis/coordtransform)
    从3857转到4326再转换到gcj02(高德使用的是gcj02)

       trans3857To4326 = (coordinate) => {
        return proj4('EPSG:3857', 'EPSG:4326', coordinate);
      }
      // 进行坐标转换 3857转wgs84
        const coordClick = this.trans3857To4326(clickFeature.getGeometry().getCoordinates());  
        // 84再转gcj02
        const clickCoord = coordtransform.wgs84togcj02(coordClick[0], coordClick[1]);   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4、调用接口

    调用接口。建议使用axios而不是Fetch。最开始使用fetch总是调用失败,卡了一天。同事说试试axios,一下就通了

      /**
       * 导航
       */
      navigationRequest = (origin, destination) => {
        // 高德
        const url = `https://restapi.amap.com/v3/direction/driving?origin=${origin[0]},${origin[1]}&destination=${destination[0]},${destination[1]}&extensions=all&output=json&key=[自己的key]`
        return axios.get(url)
          .then(function (response) {
            return response;
          })
          .catch(function (error) {
            console.log(error)
            return error;
          });
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.5、解析数据

    返回数据的结构参见接口说明。我只需要【行驶距离】、【预计行驶时间】和路径坐标。
    在这里插入图片描述

    返回的数据需要坐标转换。从gcj02转4326,再转3857.转换函数如下

    
      trans4326To3857 = (coordinate) => {
        return proj4('EPSG:4326', 'EPSG:3857', coordinate);
      }
    // 生成轨迹要素
      drawLineFeature = (steps) => {
        // 取出所有polyline拼接为键值对
        let polylines = "";
        for (let i = 0; i < steps.length; i++) {
          polylines += steps[i].polyline;
          polylines += ";";
        }
        const points = polylines.split(";");
        const pointList = [];
        const pointList3857 = [];
        for (let i = 0; i < points.length - 1; i++) {
          pointList.push(points[i].split(","));
          pointList3857.push(this.trans4326To3857(coordtransform.gcj02towgs84(points[i].split(",")[0], points[i].split(",")[1])));
        }
    
        return new Feature({geometry: new LineString(pointList3857)});
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.6、生成动效

    动效需要路径要素:reliefSuppliesDriveLine、移动的点:reliefSuppliesCarFeatureTemp。在图层reliefSuppliesCarVL中对要素reliefSuppliesCarFeatureTemp添加动画路径anim,获得控制器reliefSuppliesPlayController。
    控制器可以用于终止动画

    
      /**
       * 开始物资动画
       */
      startReliefSuppliesAnimation = () => {
        const {
          selectedReliefSupplies, reliefSuppliesDriveLine, reliefSuppliesCarVS, reliefSuppliesCarVL, reliefSuppliesCarFeature,
        } = this.state;
    
        const anim = new Path({
          path: reliefSuppliesDriveLine,
          rotate: true,
          easing: linear,
          duration: 0.25 * 60 * 1000,
          revers: false,
          repeat: 99999999,
        });
        
        reliefSuppliesCarVS.addFeature(reliefSuppliesDriveLine);
        if (!reliefSuppliesCarFeature) {
          const reliefSuppliesCarFeatureTemp = new Feature({
            zIndex: 999999999999,
            geometry: new Point(selectedReliefSupplies.getGeometry().getCoordinates()),
          });
          reliefSuppliesCarVS.addFeature(reliefSuppliesCarFeatureTemp);
          // 动画
          const reliefSuppliesPlayController = reliefSuppliesCarVL.animateFeature(reliefSuppliesCarFeatureTemp, anim);
          this.setState({reliefSuppliesCarFeature: reliefSuppliesCarFeatureTemp, reliefSuppliesPlayController});
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    有效代码:reliefSuppliesPlayController.stop();

      /**
       * 清除救援物资动画
       */
      clearReliefSuppliesAnimation = () => {
        const {
          reliefSuppliesCarVS, reliefSuppliesDriveLine, reliefSuppliesCarFeature, reliefSuppliesPlayController,
        } = this.state;
        if (reliefSuppliesPlayController) {
          reliefSuppliesPlayController.stop();
        }
        if (reliefSuppliesCarFeature) {
          reliefSuppliesCarVS.removeFeature(reliefSuppliesCarFeature);
          this.setState({reliefSuppliesCarFeature: null});
        }
        if (reliefSuppliesDriveLine) {
          reliefSuppliesCarVS.removeFeature(reliefSuppliesDriveLine);
          this.setState({reliefSuppliesDriveLine: null});
        }
        reliefSuppliesCarVS.clear();
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    java-php-python--茶店订购管理系统-计算机毕业设计
    Unity的碰撞检测(六)
    JDK1.8新特性(部分)【Lambda表达式、函数式接口】--学习JavaEE的day41
    Kylin
    记录如何用php将敏感文字内容替换为星号的方法
    mybatis-plus自动生成
    Linux C应用编程-5-线程
    Dynamic CRM插件中记录日志-Nlog记录到文本
    Android NFC开发详解:NFC读卡实例解析及总结
    VVC系列(三)xCompressCTU、xCompressCU和xCheckModeSplit解析
  • 原文地址:https://blog.csdn.net/luckysiesteven/article/details/127614349