当前位置: 首页 > news >正文

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 优化代码。希望对大家有所帮助!如果喜欢的话,记得点赞、收藏、关注哦!🚀🚀🚀

相关文章:

  • 梦回杭州...
  • 【一起学Rust | Tauri2.0框架】基于 Rust 与 Tauri 2.0 框架实现全局状态管理
  • 打造更高效的移动远控方案,贝锐向日葵Android主控SDK更新
  • Mac - Cursor 配置 + GPT 4.0/4.5/o1/o3/Deepseek Api 使用
  • 数据结构——第六章:图
  • 力扣算法Hot100——128. 最长连续序列
  • C# WPF编程-TabControl
  • 【Linux网络】手动部署并测试内网穿透
  • AWS AI中几个重要的工具介绍
  • CA 机构如何防止中间人攻击
  • leecode463.岛屿的周长
  • Java利用POI+JFreeChart 实现excel导出数据和图标(折线统计图)
  • Kafka Snappy 压缩异常分析与解决方案
  • C++编译汇编八股总结
  • redis的典型应用 --缓存
  • Spring Boot 与 MyBatis Plus 整合 KWDB 实现 JDBC 数据访问
  • Bitcoin Thunderbolt 内测通道开启,加速比特币交易新时代
  • C++ 语法之数组指针
  • MyBatis 面试专题
  • ruoyi-vue部署linux(war包方式)
  • 嫩黑线货物列车脱轨致1名路外人员死亡,3人被采取刑事强制措施
  • 马上评|家长抱婴儿值护学岗,如何避免“被自愿”?
  • 巴菲特最新调仓:一季度大幅抛售银行股,再现保密仓位
  • 马上评|清理“滥竽充数者”,为医者正名
  • 京东CEO许冉:外卖日单量接近2000万单,看到外卖对平台拉动和转化效应
  • 中国巴西民间推动建立经第三方验证的“森林友好型”牛肉供应链