vue+openlayers 自定義底圖運動軌跡回放
阿新 • • 發佈:2020-12-30
技術標籤: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>