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

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

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

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

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

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

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

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

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

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)建地圖對象

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)建一條線路

畫一條線路

可以用這個geojson網(wǎng)站隨意畫一條線,然后把數(shù)據(jù)內(nèi)容復(fù)制下來,保存為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);

以上代碼很完整,我加了注釋,整體思路總結(jié)如下:

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

添加起、終點(diǎn)

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

添加小車

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

準(zhǔn)備開車

線路有了,車也有了,現(xiàn)在就到了激動人心的開車時刻了,接下來才是本文最核心的代碼!

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

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

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

完整代碼

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 = '開車了';
      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)動態(tài)軌跡的詳細(xì)內(nèi)容,更多關(guān)于vue openlayers動態(tài)軌跡的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

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

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

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

    vue h5移動端禁止縮放代碼

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

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

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

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

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

    Vue中的baseurl如何配置

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

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

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

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

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

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

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

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

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

最新評論

罗田县| 德保县| 东辽县| 革吉县| 修水县| 茂名市| 濉溪县| 荣昌县| 贵德县| 乐东| 都匀市| 大荔县| 民和| 镇原县| 清流县| 诸城市| 沙洋县| 万全县| 天峻县| 湖南省| 玉屏| 迁安市| 观塘区| 古浪县| 连平县| 仙居县| 庄河市| 邛崃市| 惠安县| 中牟县| 武乡县| 芦溪县| 西平县| 静乐县| 铜陵市| 郓城县| 咸宁市| 冷水江市| 德安县| 天长市| 东山县|