飞行动画官方例子:https://openlayers.org/en/latest/examples/flight-animation.html
<template>
<div class="con-box">
<div id="map" class="map" />
</div>
</template>
<script>
import "ol/ol.css";
import olMap from "ol/Map";
import olView from "ol/View";
import ollayerTile from "ol/layer/Tile";
// import olsourceOSM from "ol/source/OSM";
import { get as getProjection, Projection, fromLonLat } from "ol/proj";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Point, LineString, MultiLineString, Polygon } from "ol/geom";
import XYZ from "ol/source/XYZ";
import { Map, View, Feature, ol } from "ol";
import {
Circle,
Fill,
Stroke,
Style,
Text,
Icon,
Circle as CircleStyle,
} from "ol/style.js";
import Overlay from "ol/Overlay.js";
import { Image } from "ol/layer.js";
import { OSM, Vector, ImageStatic } from "ol/source";
import { defaults as defaultControls } from "ol/control";
import GeoJSON from "ol/format/GeoJSON.js";
import { Tile as TileLayer } from "ol/layer.js";
import Draw, { createBox, createRegularPolygon } from "ol/interaction/Draw";
import { unByKey } from "ol/Observable";
import { getVectorContext } from "ol/render";
import { easeIn, easeOut } from "ol/easing";
import Stamen from "ol/source/Stamen.js";
import {getWidth} from 'ol/extent.js';
const pointsPerMs = 0.02;
export default {
data() {
return {
value: "",
dataURL1: "https://scpic.chinaz.net/files/pic/pic9/202012/bpic22030.jpg",
map: null,
view: null,
positionLayer: null,
featuresArr: [],
opt: {
img: "",
imgsize: "",
},
geo: null,
vlayer: null,
draw: null,
source: null,
multiSource: null,
feature: null,
duration: 3000,
tileLayer: null,
testArr: [],
simplyArr: [
[0, 0],
[-600, 600],
[600, 0],
[0, -600],
],
multiArr: [
[
[0, 0],
[600, 600],
[-600, 0],
[0, -600],
],
[
[300, 0],
[800, 200],
[0, 0],
[0, -100],
],
],
trackPoint: null,
simpLine: null,
multiLine: null,
traceCroods: null,
sliderPos: 0,
styleOl: new Style({
stroke: new Stroke({
color: "#EAE911",
width: 2,
}),
}),
flightsSource: null,
flightsLayer: null,
};
},
mounted() {
this.initmap();
},
methods: {
initmap() {
this.tileLayer = new TileLayer({
source: new Stamen({
layer: "toner",
}),
});
this.map = new Map({
layers: [this.tileLayer],
target: "map",
view: new View({
center: [-11000000, 4600000],
zoom: 2,
}),
});
this.initFlightMap()
},
initFlightMap() {
let self = this;
this.flightsSource = new VectorSource({
attributions:
"Flight data by " +
'OpenFlights,',
loader: function () {
const url = "data/geojson/flight.json";
fetch(url)
.then((response) => {
return response.json();
})
.then((json) => {
const flightsData = json.flights;
for (let i = 0; i < flightsData.length; i++) {
const flight = flightsData[i];
const from = flight[0];
const to = flight[1];
// create an arc circle between the two locations
const arcGenerator = new arc.GreatCircle(
{ x: from[1], y: from[0] },
{ x: to[1], y: to[0] }
);
const arcLine = arcGenerator.Arc(100, { offset: 10 });
// paths which cross the -180°/+180° meridian are split
// into two sections which will be animated sequentially
const features = [];
arcLine.geometries.forEach(function (geometry) {
const line = new LineString(geometry.coords);
line.transform("EPSG:4326", "EPSG:3857");
features.push(
new Feature({
geometry: line,
finished: false,
})
);
});
self.addLater(features, i * 50);
}
self.tileLayer.on("postrender", self.animateFlights);
});
},
});
this.flightsLayer = new VectorLayer({
source: this.flightsSource,
style: function (feature) {
// if the animation is still active for a feature, do not
// render the feature with the layer style
if (feature.get('finished')) {
return self.styleOl;
}
return null;
},
});
this.map.addLayer(this.flightsLayer)
},
addLater(features, timeout) {
let self=this;
window.setTimeout(function () {
let start = Date.now();
features.forEach(function (feature) {
feature.set("start", start);
self.flightsSource.addFeature(feature);
const duration =
(feature.getGeometry().getCoordinates().length - 1) / pointsPerMs;
start += duration;
});
}, timeout);
},
animateFlights(event) {
console.log('渲染事件',event)
const vectorContext = getVectorContext(event);
const frameState = event.frameState;
vectorContext.setStyle(this.styleOl);
const features = this.flightsSource.getFeatures();
for (let i = 0; i < features.length; i++) {
const feature = features[i];
if (!feature.get("finished")) {
// only draw the lines for which the animation has not finished yet
const coords = feature.getGeometry().getCoordinates();
const elapsedTime = frameState.time - feature.get("start");
if (elapsedTime >= 0) {
const elapsedPoints = elapsedTime * pointsPerMs;
if (elapsedPoints >= coords.length) {
feature.set("finished", true);
}
const maxIndex = Math.min(elapsedPoints, coords.length);
const currentLine = new LineString(coords.slice(0, maxIndex));
// animation is needed in the current and nearest adjacent wrapped world
const worldWidth = getWidth(
this.map.getView().getProjection().getExtent()
);
const offset = Math.floor(
this.map.getView().getCenter()[0] / worldWidth
);
// directly draw the lines with the vector context
currentLine.translate(offset * worldWidth, 0);
vectorContext.drawGeometry(currentLine);
currentLine.translate(worldWidth, 0);
vectorContext.drawGeometry(currentLine);
}
}
}
// tell OpenLayers to continue the animation
this.map.render();
},
},
};
</script>
<style scoped>
#map {
width: 97%;
margin: 0 auto;
/* background: rgb(238, 238, 238); */
}
.con-box {
width: 100%;
height: 100%;
border: 1px solid #999999;
}
.map {
height: 700px;
border: 1px solid;
}
.icon_but {
margin: 0 10px;
padding: 10px;
border: 1px solid red;
}
.toolbar {
margin: 10px;
}
.toolbar span {
display: inline-block;
}
.ol-popup {
border: 1px solid red;
font-size: 20px;
font-weight: bolder;
}
.con-box {
width: 100%;
height: calc(100% - 84px);
border: 1px solid #999999;
}
</style>