我的编程空间,编程开发者的网络收藏夹
学习永远不晚

vue利用openlayers实现动态轨迹

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

vue利用openlayers实现动态轨迹

实现效果

今天介绍一个有趣的gis小功能:动态轨迹播放!效果就像这样:

这效果看着还很丝滑!别急,接下来教你怎么实现。代码示例基于parcel打包工具和es6语法,本文假设你已经掌握相关知识和技巧。

gis初学者可能对openlayers(后面简称ol)不熟悉,这里暂时不介绍ol了,直接上代码,先体验下感觉。

创建一个地图容器

引入地图相关对象

import Map from 'ol/Map';
import View from 'ol/View';
import XYZ from 'ol/source/XYZ';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';

创建地图对象

const center = [-5639523.95, -3501274.52];
const map = new Map({
  target: document.getElementById('map'),
  view: new View({
    center: center,
    zoom: 10,
    minZoom: 2,
    maxZoom: 19,
  }),
  layers: [
    new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url: 'https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=' + key,
        tileSize: 512,
      }),
    }),
  ],
});

创建一条线路

画一条线路

可以用这个geojson网站随意画一条线,然后把数据内容复制下来,保存为json文件格式,作为图层数据添加到地图容器中。

你可以用异步加载的方式,也可以用require方式,这里都介绍下吧:

// fetch
fetch('data/route.json').then(function (response) {
  response.json().then(function (result) {
    const polyline = result.routes[0].geometry;
  }),
};
// require
var roadData = require('data/route.json')

后面基本一样了,就以fetch为准,现在把线路加载的剩余部分补充完整:

fetch('data/route.json').then(function (response) {
  response.json().then(function (result) {
    const polyline = result.routes[0].geometry;
	// 线路数据坐标系转换
    const route = new Polyline({
      factor: 1e6,
    }).readGeometry(polyline, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857',
    });
	// 线路图层要素
    const routeFeature = new Feature({
      type: 'route',
      geometry: route,
    });
    // 起点要素
    const startMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getFirstCoordinate()),
    });
    // 终点要素
    const endMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getLastCoordinate()),
    });
    // 取起点值
    const position = startMarker.getGeometry().clone();
    // 游标要素
    const geoMarker = new Feature({
      type: 'geoMarker',
      geometry: position,
    });
	// 样式组合
    const styles = {
        // 路线
      'route': new Style({
        stroke: new Stroke({
          width: 6,
          color: [237, 212, 0, 0.8],
        }),
      }),
      'icon': new Style({
        image: new Icon({
          anchor: [0.5, 1],
          class="lazy" data-src: 'data/icon.png',
        }),
      }),
      'geoMarker': new Style({
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({color: 'black'}),
          stroke: new Stroke({
            color: 'white',
            width: 2,
          }),
        }),
      }),
    };
	// 创建图层并添加以上要素集合
    const vectorLayer = new VectorLayer({
      source: new VectorSource({
        features: [routeFeature, geoMarker, startMarker, endMarker],
      }),
      style: function (feature) {
        return styles[feature.get('type')];
      },
    });
	// 在地图容器中添加图层
    map.addLayer(vectorLayer);

以上代码很完整,我加了注释,整体思路总结如下:

  • 先加载路线数据
  • 构造路线、起始点及游标对应图层要素对象
  • 构造图层并把要素添加进去
  • 在地图容器中添加图层

添加起、终点

这个上面的代码已经包括了,我这里列出来是为了让你更清晰,就是startMarkerendMarker对应的代码。

添加小车

同样的,这里的代码在上面也写过了,就是geoMarker所对应的代码。

准备开车

线路有了,车也有了,现在就到了激动人心的开车时刻了,接下来才是本文最核心的代码!

const speedInput = document.getElementById('speed');
    const startButton = document.getElementById('start-animation');
    let animating = false;
    let distance = 0;
    let lastTime;
    function moveFeature(event) {
      const speed = Number(speedInput.value);
      // 获取当前渲染帧状态时刻
      const time = event.frameState.time;
      // 渲染时刻减去开始播放轨迹的时间
      const elapsedTime = time - lastTime;
      // 求得距离比
      distance = (distance + (speed * elapsedTime) / 1e6) % 2;
      // 刷新上一时刻
      lastTime = time;
	  // 反减可实现反向运动,获取坐标点
      const currentCoordinate = route.getCoordinateAt(
        distance > 1 ? 2 - distance : distance
      );
      position.setCoordinates(currentCoordinate);
      // 获取渲染图层的画布
      const vectorContext = getVectorContext(event);
      vectorContext.setStyle(styles.geoMarker);
      vectorContext.drawGeometry(position);
      map.render();
    }
    function startAnimation() {
      animating = true;
      lastTime = Date.now();
      startButton.textContent = 'Stop Animation';
      vectorLayer.on('postrender', moveFeature);
      // 隐藏小车前一刻位置同时触发事件
      geoMarker.setGeometry(null);
    }
    function stopAnimation() {
      animating = false;
      startButton.textContent = '开车了';
      // 将小车固定在当前位置
      geoMarker.setGeometry(position);
      vectorLayer.un('postrender', moveFeature);
    }
    startButton.addEventListener('click', function () {
      if (animating) {
        stopAnimation();
      } else {
        startAnimation();
      }
    });

简单说下它的原理就是利用postrender事件触发一个函数,这个事件本来是地图渲染结束事件,但是它的回调函数中,小车的坐标位置一直在变,那就会不停地触发地图渲染,当然最终也会触发postrender。这样就实现的小车沿着轨迹的动画效果了。这段代码有点难理解,最好自己尝试体验下,比较难理解部分我都加上了注释。

好了,ol动态巡查已经介绍完了,动手试下吧!看你的车能否开起来?

完整代码

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Marker Animation</title>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script class="lazy" data-src="https://unpkg.com/elm-pep"></script>
    <style>
      .map {
        width: 100%;
        height:400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <label for="speed">
      speed: 
      <input id="speed" type="range" min="10" max="999" step="10" value="60">
    </label>
    <button id="start-animation">Start Animation</button>
    <script class="lazy" data-src="main.js"></script>
  </body>
</html>

main.js

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import Polyline from 'ol/format/Polyline';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import XYZ from 'ol/source/XYZ';
import {
  Circle as CircleStyle,
  Fill,
  Icon,
  Stroke,
  Style,
} from 'ol/style';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {getVectorContext} from 'ol/render';
const key = 'Get your own API key at https://www.maptiler.com/cloud/';
const attributions =
  '<a href="https://www.maptiler.com/copyright/" rel="external nofollow"  target="_blank">&copy; MapTiler</a> ' +
  '<a href="https://www.openstreetmap.org/copyright" rel="external nofollow"  target="_blank">&copy; OpenStreetMap contributors</a>';
const center = [-5639523.95, -3501274.52];
const map = new Map({
  target: document.getElementById('map'),
  view: new View({
    center: center,
    zoom: 10,
    minZoom: 2,
    maxZoom: 19,
  }),
  layers: [
    new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url: 'https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=' + key,
        tileSize: 512,
      }),
    }),
  ],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
fetch('data/polyline/route.json').then(function (response) {
  response.json().then(function (result) {
    const polyline = result.routes[0].geometry;
    const route = new Polyline({
      factor: 1e6,
    }).readGeometry(polyline, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857',
    });
    const routeFeature = new Feature({
      type: 'route',
      geometry: route,
    });
    const startMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getFirstCoordinate()),
    });
    const endMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getLastCoordinate()),
    });
    const position = startMarker.getGeometry().clone();
    const geoMarker = new Feature({
      type: 'geoMarker',
      geometry: position,
    });
    const styles = {
      'route': new Style({
        stroke: new Stroke({
          width: 6,
          color: [237, 212, 0, 0.8],
        }),
      }),
      'icon': new Style({
        image: new Icon({
          anchor: [0.5, 1],
          class="lazy" data-src: 'data/icon.png',
        }),
      }),
      'geoMarker': new Style({
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({color: 'black'}),
          stroke: new Stroke({
            color: 'white',
            width: 2,
          }),
        }),
      }),
    };
    const vectorLayer = new VectorLayer({
      source: new VectorSource({
        features: [routeFeature, geoMarker, startMarker, endMarker],
      }),
      style: function (feature) {
        return styles[feature.get('type')];
      },
    });
    map.addLayer(vectorLayer);
    const speedInput = document.getElementById('speed');
    const startButton = document.getElementById('start-animation');
    let animating = false;
    let distance = 0;
    let lastTime;
    function moveFeature(event) {
      const speed = Number(speedInput.value);
      const time = event.frameState.time;
      const elapsedTime = time - lastTime;
      distance = (distance + (speed * elapsedTime) / 1e6) % 2;
      lastTime = time;
      const currentCoordinate = route.getCoordinateAt(
        distance > 1 ? 2 - distance : distance
      );
      position.setCoordinates(currentCoordinate);
      const vectorContext = getVectorContext(event);
      vectorContext.setStyle(styles.geoMarker);
      vectorContext.drawGeometry(position);
      // tell OpenLayers to continue the postrender animation
      map.render();
    }
    function startAnimation() {
      animating = true;
      lastTime = Date.now();
      startButton.textContent = 'Stop Animation';
      vectorLayer.on('postrender', moveFeature);
      geoMarker.setGeometry(null);
    }
    function stopAnimation() {
      animating = false;
      startButton.textContent = '开车了';
      geoMarker.setGeometry(position);
      vectorLayer.un('postrender', moveFeature);
    }
    startButton.addEventListener('click', function () {
      if (animating) {
        stopAnimation();
      } else {
        startAnimation();
      }
    });
  });
});

package.json

{
  "name": "feature-move-animation",
  "dependencies": {
    "ol": "6.9.0"
  },
  "devDependencies": {
    "parcel": "^2.0.0-beta.1"
  },
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build --public-url . index.html"
  }
}

参考资源:

https://openlayers.org/en/latest/examples/feature-move-animation.html

以上就是vue利用openlayers实现动态轨迹的详细内容,更多关于vue openlayers动态轨迹的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

vue利用openlayers实现动态轨迹

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue利用openlayers实现动态轨迹

这篇文章主要为大家介绍了vue利用openlayers实现动态轨迹,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

如何利用CSS+JS实现唯美星空轨迹运动效果

小编给大家分享一下如何利用CSS+JS实现唯美星空轨迹运动效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!css是什么意思css是一种用来表现HTML或XML等
2023-06-08

怎么用CSS3和table标签实现一个圆形轨迹的动画

小编给大家分享一下怎么用CSS3和table标签实现一个圆形轨迹的动画,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!html:其实就是根据table标签把几个实心
2023-06-08

怎么在Android应用中利用贝塞尔曲线实现一个购物车添加轨迹

这期内容当中小编将会给大家带来有关怎么在Android应用中利用贝塞尔曲线实现一个购物车添加轨迹,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。效果如下:1、新建自定义View,重写构造方法,初始化Pain
2023-05-31

怎么用vue实现动态路由

这篇文章主要介绍了怎么用vue实现动态路由的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用vue实现动态路由文章都会有所收获,下面我们一起来看看吧。1、什么是动态路由?动态路由,动态即不是写死的,是可变的。
2023-07-02

利用java实现动态代理的方法

这篇文章将为大家详细讲解有关利用java实现动态代理的方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java 动态代理的方法总结AOP的拦截功能是由java中的动态代理来实现的。说白了,
2023-05-31

怎么使用SpringBoot+Vue实现动态菜单

本篇内容介绍了“怎么使用SpringBoot+Vue实现动态菜单”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 整体思路效果图:最终菜单
2023-07-02

怎么在Vue中利用路由监听实现同页面动态加载

怎么在Vue中利用路由监听实现同页面动态加载?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。watch: { $route.path: function (
2023-06-15

Python利用pynimate实现制作动态排序图

这篇文章主要为大家详细介绍了Python如何利用pynimate实现制作动态排序图,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
2023-02-01

编程热搜

目录