102.在Vue3中使用OpenLayers实现定位动画(平移-弹性平移-飞行)
前言
在 WebGIS 开发中,OpenLayers 是一个功能强大的开源地图库,能够帮助开发者快速构建地图应用。在 Vue 3 组合式 API (Composition API) 的加持下,我们可以更优雅地封装 OpenLayers,并实现炫酷的地图交互功能。
本文将介绍如何在 Vue 3 项目中使用 OpenLayers 实现 地图定位动画,包括 平移、弹性平移、飞行 三种效果,并通过 Vue 3 的 setup
语法优化代码结构,使代码更加清晰、易维护。
效果演示
最终效果如下:
- 平移:地图视图平滑地移动到指定位置。
- 弹性平移:使用缓动函数 (
easing
) 使地图带有缓冲的移动效果。 - 飞行:通过缩放动画模拟飞行效果,让视角从远处逐渐拉近目标点。
项目初始化
我们使用 Vue 3 + Vite 创建一个新的 Vue 项目,并安装 Element Plus 组件库来支持按钮交互。
1. 创建 Vue 3 项目
npm create vite@latest vue3-openlayers-demo --template
vue cd vue3-openlayers-demo
npm install
2. 安装 Element Plus
npm install element-plus
3. 安装 OpenLayers
npm install ol
核心代码实现
接下来,我们将在 src/components
目录下创建一个 OpenLayersMap.vue
组件,实现地图初始化和定位动画。
完整代码
<!--
* @Author: 彭麒
* @Date: 2025/3/19
* @Email: 1062470959@qq.com
* @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
-->
<template>
<div class="container">
<div class="w-full flex justify-center flex-wrap">
<div class="font-bold text-[24px]">在Vue3中使用OpenLayers实现定位动画(平移-弹性平移-飞行)</div>
</div>
<h4>
<el-button type="primary" size="small" @click="pan">平移</el-button>
<el-button type="primary" size="small" @click="elastic">弹性平移</el-button>
<el-button type="primary" size="small" @click="fly">飞行</el-button>
</h4>
<div id="vue-openlayers"></div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import "ol/ol.css";
import { Map, View } from "ol";
import Tile from "ol/layer/Tile";
import BingMaps from "ol/source/BingMaps";
import * as olEasing from "ol/easing";
const map = ref(null);
const pan = () => {
map.value?.getView().animate({
center: [119, 39],
duration: 2000,
});
};
const elastic = () => {
map.value?.getView().animate({
center: [-36, -22],
easing: olEasing.easeOut,
});
};
const fly = () => {
flyTo([-55, 36]);
};
const flyTo = (location, done = () => {}) => {
let view = map.value?.getView();
if (!view) return;
let duration = 2000;
let zoom = view.getZoom();
let parts = 2;
let called = false;
function callback(complete) {
--parts;
if (called) return;
if (parts === 0 || !complete) {
called = true;
done(complete);
}
}
view.animate({ center: location, duration }, callback);
view.animate(
{ zoom: zoom - 1, duration: duration / 2 },
{ zoom: zoom, duration: duration / 2 },
callback
);
};
const bing = () => {
map.value?.getLayers().getArray().forEach((layer) => {
if (layer) map.value.removeLayer(layer);
});
let nsource = new BingMaps({
key: "AqQf9nX6PZKkFZOkdOqBOh3vg8xwGV1AYWGqC6EsOoJ0OHSUwm8CN8AhaFpT7mfR",
imagerySet: "RoadOnDemand",
});
let bingMapLayer = new Tile({ source: nsource });
map.value?.addLayer(bingMapLayer);
};
const initMap = () => {
map.value = new Map({
target: "vue-openlayers",
layers: [],
view: new View({
center: [122, 47],
zoom: 4,
projection: "EPSG:4326",
}),
loadTilesWhileAnimating: true,
});
bing();
};
onMounted(() => {
initMap();
});
</script>
<style scoped>
.container {
width: 840px;
height: 590px;
margin: 50px auto;
border: 1px solid #42b983;
}
#vue-openlayers {
width: 800px;
height: 400px;
margin: 0 auto;
border: 1px solid #42b983;
position: relative;
}
</style>
代码解析
1. 初始化地图
我们使用 onMounted
生命周期,在组件加载后执行 initMap()
初始化 OpenLayers 地图:
const initMap = () => {
map.value = new Map({
target: "vue-openlayers",
layers: [],
view: new View({
center: [122, 47],
zoom: 4,
projection: "EPSG:4326",
}),
loadTilesWhileAnimating: true,
});
bing();
};
2. Bing 地图加载
const bing = () => {
map.value?.getLayers().getArray().forEach((layer) => {
if (layer) map.value.removeLayer(layer);
});
let nsource = new BingMaps({
key: "AqQf9nX6PZKkFZOkdOqBOh3vg8xwGV1AYWGqC6EsOoJ0OHSUwm8CN8AhaFpT7mfR",
imagerySet: "RoadOnDemand",
});
let bingMapLayer = new Tile({ source: nsource });
map.value?.addLayer(bingMapLayer);
};
这里使用 Bing 地图服务 作为底图,你可以替换成其他地图源,如 OpenStreetMap (OSM)。
3. 定位动画
const pan = () => {
map.value?.getView().animate({
center: [119, 39],
duration: 2000,
});
};
animate()
方法可以平滑移动地图视图。
4. 飞行动画
const flyTo = (location, done = () => {}) => {
let view = map.value?.getView();
if (!view) return;
let duration = 2000;
let zoom = view.getZoom();
let parts = 2;
let called = false;
function callback(complete) {
--parts;
if (called) return;
if (parts === 0 || !complete) {
called = true;
done(complete);
}
}
view.animate({ center: location, duration }, callback);
view.animate(
{ zoom: zoom - 1, duration: duration / 2 },
{ zoom: zoom, duration: duration / 2 },
callback
);
};
这里通过 缩放动画 模拟飞行效果。
总结
本文介绍了如何在 Vue 3 + OpenLayers 中实现 定位动画,并使用 Composition API 优化代码。希望对大家有所帮助!如果喜欢的话,记得点赞、收藏、关注哦!🚀🚀🚀