最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue利用openlayers實(shí)現(xiàn)動(dòng)態(tài)軌跡

 更新時(shí)間:2022年11月04日 09:28:15   作者:字節(jié)逆旅  
這篇文章主要為大家介紹了vue利用openlayers實(shí)現(xiàn)動(dòng)態(tài)軌跡,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

實(shí)現(xiàn)效果

今天介紹一個(gè)有趣的gis小功能:動(dòng)態(tài)軌跡播放!效果就像這樣:

這效果看著還很絲滑!別急,接下來(lái)教你怎么實(shí)現(xiàn)。代碼示例基于parcel打包工具和es6語(yǔ)法,本文假設(shè)你已經(jīng)掌握相關(guān)知識(shí)和技巧。

gis初學(xué)者可能對(duì)openlayers(后面簡(jiǎn)稱(chēng)ol)不熟悉,這里暫時(shí)不介紹ol了,直接上代碼,先體驗(yàn)下感覺(jué)。

創(chuàng)建一個(gè)地圖容器

引入地圖相關(guān)對(duì)象

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';

創(chuàng)建地圖對(duì)象

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,
      }),
    }),
  ],
});

創(chuàng)建一條線路

畫(huà)一條線路

可以用這個(gè)geojson網(wǎng)站隨意畫(huà)一條線,然后把數(shù)據(jù)內(nèi)容復(fù)制下來(lái),保存為json文件格式,作為圖層數(shù)據(jù)添加到地圖容器中。

你可以用異步加載的方式,也可以用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為準(zhǔn),現(xiàn)在把線路加載的剩余部分補(bǔ)充完整:

fetch('data/route.json').then(function (response) {
  response.json().then(function (result) {
    const polyline = result.routes[0].geometry;
	// 線路數(shù)據(jù)坐標(biāo)系轉(zhuǎn)換
    const route = new Polyline({
      factor: 1e6,
    }).readGeometry(polyline, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857',
    });
	// 線路圖層要素
    const routeFeature = new Feature({
      type: 'route',
      geometry: route,
    });
    // 起點(diǎn)要素
    const startMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getFirstCoordinate()),
    });
    // 終點(diǎn)要素
    const endMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getLastCoordinate()),
    });
    // 取起點(diǎn)值
    const position = startMarker.getGeometry().clone();
    // 游標(biāo)要素
    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],
          src: 'data/icon.png',
        }),
      }),
      'geoMarker': new Style({
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({color: 'black'}),
          stroke: new Stroke({
            color: 'white',
            width: 2,
          }),
        }),
      }),
    };
	// 創(chuàng)建圖層并添加以上要素集合
    const vectorLayer = new VectorLayer({
      source: new VectorSource({
        features: [routeFeature, geoMarker, startMarker, endMarker],
      }),
      style: function (feature) {
        return styles[feature.get('type')];
      },
    });
	// 在地圖容器中添加圖層
    map.addLayer(vectorLayer);

以上代碼很完整,我加了注釋?zhuān)w思路總結(jié)如下:

  • 先加載路線數(shù)據(jù)
  • 構(gòu)造路線、起始點(diǎn)及游標(biāo)對(duì)應(yīng)圖層要素對(duì)象
  • 構(gòu)造圖層并把要素添加進(jìn)去
  • 在地圖容器中添加圖層

添加起、終點(diǎn)

這個(gè)上面的代碼已經(jīng)包括了,我這里列出來(lái)是為了讓你更清晰,就是startMarkerendMarker對(duì)應(yīng)的代碼。

添加小車(chē)

同樣的,這里的代碼在上面也寫(xiě)過(guò)了,就是geoMarker所對(duì)應(yīng)的代碼。

準(zhǔn)備開(kāi)車(chē)

線路有了,車(chē)也有了,現(xiàn)在就到了激動(dòng)人心的開(kāi)車(chē)時(shí)刻了,接下來(lái)才是本文最核心的代碼!

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);
      // 獲取當(dāng)前渲染幀狀態(tài)時(shí)刻
      const time = event.frameState.time;
      // 渲染時(shí)刻減去開(kāi)始播放軌跡的時(shí)間
      const elapsedTime = time - lastTime;
      // 求得距離比
      distance = (distance + (speed * elapsedTime) / 1e6) % 2;
      // 刷新上一時(shí)刻
      lastTime = time;
	  // 反減可實(shí)現(xiàn)反向運(yùn)動(dòng),獲取坐標(biāo)點(diǎn)
      const currentCoordinate = route.getCoordinateAt(
        distance > 1 ? 2 - distance : distance
      );
      position.setCoordinates(currentCoordinate);
      // 獲取渲染圖層的畫(huà)布
      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);
      // 隱藏小車(chē)前一刻位置同時(shí)觸發(fā)事件
      geoMarker.setGeometry(null);
    }
    function stopAnimation() {
      animating = false;
      startButton.textContent = '開(kāi)車(chē)了';
      // 將小車(chē)固定在當(dāng)前位置
      geoMarker.setGeometry(position);
      vectorLayer.un('postrender', moveFeature);
    }
    startButton.addEventListener('click', function () {
      if (animating) {
        stopAnimation();
      } else {
        startAnimation();
      }
    });

簡(jiǎn)單說(shuō)下它的原理就是利用postrender事件觸發(fā)一個(gè)函數(shù),這個(gè)事件本來(lái)是地圖渲染結(jié)束事件,但是它的回調(diào)函數(shù)中,小車(chē)的坐標(biāo)位置一直在變,那就會(huì)不停地觸發(fā)地圖渲染,當(dāng)然最終也會(huì)觸發(fā)postrender。這樣就實(shí)現(xiàn)的小車(chē)沿著軌跡的動(dòng)畫(huà)效果了。這段代碼有點(diǎn)難理解,最好自己嘗試體驗(yàn)下,比較難理解部分我都加上了注釋。

好了,ol動(dòng)態(tài)巡查已經(jīng)介紹完了,動(dòng)手試下吧!看你的車(chē)能否開(kāi)起來(lái)?

完整代碼

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 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 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  rel="external nofollow"  target="_blank">&copy; MapTiler</a> ' +
  '<a  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],
          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 = '開(kāi)車(chē)了';
      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實(shí)現(xiàn)動(dòng)態(tài)軌跡的詳細(xì)內(nèi)容,更多關(guān)于vue openlayers動(dòng)態(tài)軌跡的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue-cli使用stimulsoft.reports.js的詳細(xì)教程

    vue-cli使用stimulsoft.reports.js的詳細(xì)教程

    Stimulsoft?Reports.JS是一個(gè)使用JavaScript和HTML5生成報(bào)表的平臺(tái)。它擁有所有擁來(lái)設(shè)計(jì),編輯和查看報(bào)表的必需組件。該報(bào)表工具根據(jù)開(kāi)發(fā)人員數(shù)量授權(quán)而不是根據(jù)應(yīng)用程序的用戶(hù)數(shù)量。接下來(lái)通過(guò)本文給大家介紹vue-cli使用stimulsoft.reports.js的方法,一起看看吧
    2021-12-12
  • vue h5移動(dòng)端禁止縮放代碼

    vue h5移動(dòng)端禁止縮放代碼

    今天小編就為大家分享一篇vue h5移動(dòng)端禁止縮放代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-10-10
  • Vue組件通信的幾種實(shí)現(xiàn)方法

    Vue組件通信的幾種實(shí)現(xiàn)方法

    這篇文章主要介紹了Vue組件通信的幾種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 實(shí)例詳解vue中的$root和$parent

    實(shí)例詳解vue中的$root和$parent

    這篇文章主要介紹了vue中的$root和$parent ,本文通過(guò)文字實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-04-04
  • Vue中的baseurl如何配置

    Vue中的baseurl如何配置

    這篇文章主要介紹了Vue中的baseurl如何配置問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • vue中動(dòng)態(tài)獲取變量名并賦值方式

    vue中動(dòng)態(tài)獲取變量名并賦值方式

    這篇文章主要介紹了vue中動(dòng)態(tài)獲取變量名并賦值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • vue.js中使用echarts實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)刷新功能

    vue.js中使用echarts實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)刷新功能

    這篇文章主要介紹了vue.js中使用echarts實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)刷新功能,需要的朋友可以參考下
    2019-04-04
  • vue3使用particles插件實(shí)現(xiàn)粒子背景的方法詳解

    vue3使用particles插件實(shí)現(xiàn)粒子背景的方法詳解

    這篇文章主要為大家詳細(xì)介紹了vue3使用particles插件實(shí)現(xiàn)粒子背景的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn)

    vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn)

    el-tab本身的功能是點(diǎn)擊之后切換不同頁(yè),本文主要介紹了vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • vue中使用jwt-decode解析token的方法

    vue中使用jwt-decode解析token的方法

    這篇文章主要介紹了vue中使用jwt-decode解析token,文末給大家補(bǔ)充介紹了vue通過(guò)jwt-decode解析token獲取需要的數(shù)據(jù),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06

最新評(píng)論

马边| 家居| 得荣县| 隆回县| 乌审旗| 怀集县| 兴业县| 乌拉特后旗| 灌云县| 谷城县| 焦作市| 中超| 赤城县| 云林县| 徐州市| 沅陵县| 大厂| 论坛| 乌海市| 婺源县| 封开县| 分宜县| 山阳县| 临汾市| 武邑县| 井陉县| 桓仁| 石狮市| 昆山市| 连山| 吉隆县| 永新县| 兴安盟| 宜君县| 聊城市| 华池县| 中阳县| 宝丰县| 青河县| 临西县| 望谟县|