1. 程式人生 > 其它 >vue+openlayers 自定義底圖運動軌跡回放

vue+openlayers 自定義底圖運動軌跡回放

技術標籤:openlayersVuejavascriptvue.jscss3es6

vue+openlayers運動軌跡回放

<!--
 * @Description: 軌跡回放
 * @Author: Dragon
 * @Email: 153284575@qq.com
 * @Date: 2020-11-20 22:05:31
 * @LastEditTime: 2020-12-29 10:08:46
 * @LastEditors: Dragon
-->

<template>
  <div class="base-tracks">
<div class="query-wrap"> <el-row v-if="routeCoords.length > 0"> <el-col> <el-button type="primary" @click="toggle">{{ textContent }}</el-button> <el-slider class="slider-bar"
v-model="speed" :step="10" > </el-slider> <div class="progress-bar" v-if="progress != 0"> <div class="bar-box"> <div class="bar" :style=
"{ width: progress }"> <span>{{ progress }}</span> </div> </div> </div> </el-col> </el-row> </div> <!-- 地圖 --> <div id="map" ref="rootmap"></div> </div> </template> <script> import "ol/ol.css"; import { Map, View, Feature } from "ol"; import { getCenter } from "ol/extent"; import { Tile as TileLayer, Vector as VectorLayer, Image as ImageLayer } from "ol/layer"; import { Vector, ImageStatic as Static } from "ol/source"; import { Point, LineString } from "ol/geom"; import { Style, Icon, Text, Fill, Stroke, Circle } from "ol/style"; import { Projection } from "ol/proj"; import { getVectorContext } from "ol/render"; import start from "@/assets/start.png"; import end from "@/assets/end.png"; import img from "@/assets/tx-icon-1.png"; import staticMap from "@/assets/map.png"; export default { data() { return { map: null, // 地圖 imgx: 0, // 當前地圖寬 imgy: 0, // 當前地圖高 textContent: "播放", animating: false, // 動畫是否開始 speed: 2, // 速度 now: null, // 當前時間 vectorLayer: null, // 向量圖層 routeCoords: [], // 陣列點集合(線路座標) routeLength: 0, // 集合點的數量長度 routeFeature: null, // 畫線 geoMarker: null, // 移動標記 startMarker: null, // 開始標記 endMarker: null, // 結束標記 styles: { route: new Style({ // 線的樣式 stroke: new Stroke({ width: 6, color: [237, 212, 0, 0.8], }), }), // icon: new Style({ // // 預設icon樣式 // image: new Circle({ // radius: 7, // fill: new Fill({ color: "red" }), // stroke: new Stroke({ // color: "white", // width: 2, // }), // }), // }), geoMarker: new Style({ // 移動人物的圖示樣式 image: new Icon({ anchor: [0.5, 0.8], // 居中 // anchorOrigin: 'top-right', // anchorXUnits: 'fraction', // anchorYUnits: 'pixels', // offsetOrigin: 'top-right', // offset:[0,10], scale: 0.5, // 圖示縮放比例 opacit: 1, // 透明度 src: img, }), }), start: new Style({ // 設定開始標記樣式 image: new Icon({ anchor: [0.5, 1], src: start, }), }), end: new Style({ // 設定結束標記樣式 image: new Icon({ anchor: [0.5, 1], src: require("@/assets/end.png"), }), }), }, progress: 0, }; }, methods: { // 初始化地圖 initMap() { let that = this; let extent = [0, 0, this.imgx, this.imgy]; let projection = new Projection({ extent: extent, }); // 預設地圖 let defaultMap = new ImageLayer({ source: new Static({ url: staticMap, projection: projection, imageExtent: extent, }), }); // 新增向量層 this.vectorLayer = new VectorLayer({ source: new Vector(), }); this.map = new Map({ target: "map", layers: [defaultMap, that.vectorLayer], view: new View({ projection: projection, center: getCenter(extent), zoom: 2, maxZoom: 18, }), }); }, // 軌跡回放 moveFeature(event) { let vectorContext = getVectorContext(event); let frameState = event.frameState; if (this.animating) { let elapsedTime = frameState.time - this.now; let index = Math.round((this.speed * elapsedTime) / 1000); this.progress = Math.floor(((100 / this.routeLength) * (this.speed * elapsedTime)) / 1000) + "%"; if (index >= this.routeLength) { this.progress = "100%"; this.stop(true); return; } let currentPoint = new Point(this.routeCoords[index]); // 當前點 let feature = new Feature(currentPoint); vectorContext.drawFeature(feature, this.styles.geoMarker); } this.map.render(); }, // 運動軌跡開關 toggle() { if (this.textContent === "重新播放") { this.progress = 0; this.stop(false); } else { this.start(); } }, // 開始動畫 start() { if (this.animating) { this.stop(false); } else { // hide geoMarker this.animating = true; this.textContent = "重新播放"; this.now = new Date().getTime(); // 開始時的時間 this.geoMarker.setStyle(null); // 設定顯示範圍 // this.map.getView().setCenter(center) this.vectorLayer.on("postrender", this.moveFeature); this.map.render(); } }, // 停止 stop(ended) { this.textContent = "開始播放"; this.animating = false; // if animation cancelled set the marker at the beginning let ii = ended ? this.routeLength - 1 : 0; let coord = this.routeCoords[ii]; this.geoMarker.setGeometry(new Point(coord)); // this.geoMarker.setStyle(this.createLabelStyle(img)); // 設定走完最後一個點是否展示 // remove listener // 刪除偵聽器 this.vectorLayer.un("postrender", this.moveFeature); }, // 設定座標樣式 createLabelStyle(img) { return new Style({ image: new Icon({ anchor: [0.5, 0.8], // 居中 // anchorOrigin: 'top-right', // anchorXUnits: 'fraction', // anchorYUnits: 'pixels', // offsetOrigin: 'top-right', // offset:[0,10], scale: 0.5, // 圖示縮放比例 opacit: 1, // 透明度 src: img, // 圖示的url }), }); }, // 獲取基站列表 getTrack() { // 獲取介面返回資料 let res = [ [256.83593750000006, 370.91015624999994], [261.71875000000006, 425.59765624999994], [253.90625000000006, 469.54296875], [338.86718750000006, 488.09765625], [406.25000000000006, 488.09765625], [471.67968750000006, 488.09765625], [544.9218750000001, 471.49609375], [547.8515625000001, 416.80859374999994], [542.9687500000001, 366.02734374999994], ]; this.routeCoords = res.map((d) => { return (d = [d[0], d[1]]); }); this.routeLength = this.routeCoords.length; // 畫線 this.routeFeature = new Feature(new LineString(this.routeCoords)); this.routeFeature.setStyle(this.styles.route); // 標記 this.geoMarker = new Feature(new Point(this.routeCoords[0])); this.geoMarker.setStyle(this.styles.geoMarker); // 開始點 this.startMarker = new Feature(new Point(this.routeCoords[0])); this.startMarker.setStyle(this.styles.start); // 結束點 this.endMarker = new Feature( new Point(this.routeCoords[this.routeLength - 1]) ); this.endMarker.setStyle(this.styles.end); // 運動集合展示在向量圖上 this.vectorLayer .getSource() .addFeatures([ this.routeFeature, this.geoMarker, this.startMarker, this.endMarker, ]); this.map.render(); }, }, mounted() { let img = new Image(); img.src = staticMap; let that = this; img.onload = function (res) { that.imgx = res.target.width; that.imgy = res.target.height; that.initMap(); that.getTrack(); }; }, }; </script> <style lang="scss"> .base-tracks { .slider-bar { width: 100px; display: inline-block; position: relative; top: 14px; margin-right: 20px; } .el-form-item { margin: 0; } .el-select, .el-date-editor--datetime { margin: 0 20px 20px 0; } .progress-bar { width: 50%; height: 30px; position: relative; box-sizing: border-box; display: inline-block; .bar-box { position: absolute; top: 20px; left: 0; right: 0; height: 10px; border-radius: 5px; background: #034c77; margin-right: 20px; } .bar { height: 10px; border-radius: 5px; background: green; position: relative; span { width: 20px; height: 20px; line-height: 18px; font-size: 12px; font-weight: bold; text-align: center; position: absolute; color: #fe0000; top: -30px; right: 0; background-size: 100% 30px; } } } #map { height: calc(100vh - 120px); } } </style> <style scoped> .new-container { padding: 0 20px; } </style>