147.在 Vue3 中使用 OpenLayers 地圖上 ECharts 模擬飛機循環飛行

🧩 效果預覽

👇 飛機從多個城市起飛并向其他城市飛行,動畫流暢,地圖可縮放拖拽:



📦 一、項目技術棧

技術用途
Vue 3現代前端框架
OpenLayers地圖底圖渲染
ECharts + ol-echarts飛機飛行動畫渲染
ol-echarts將 ECharts 圖層嵌入到 OpenLayers

?? 二、環境準備

1. 創建項目(如果你已有 Vue3 項目可跳過)

npm init vue@latest vue-openlayers-echarts
cd vue-openlayers-echarts
npm install

選用 Vue 3 + TypeScriptVue 3 + JavaScript 皆可。

2. 安裝必要依賴

npm install ol echarts ol-echarts

如果你使用的是 Vite 構建工具,也可以添加 ECharts 按需引入優化:


🌍 三、準備地圖 JSON 數據

我們需要一個 GeoJSON 格式的中國地圖數據 作為 ECharts 的底圖。你有兩種方式下載:

? 方法一:使用阿里官方提供的地圖數據

  1. 打開:https://geo.datav.aliyun.com/areas/bound/100000_full.json

  2. 將其放入你的項目 public/map/china.json

? 方法二:也可以使用世界地圖 world.json(視覺更國際化)

  • 下載鏈接:https://cdn.jsdelivr.net/npm/echarts@5/map/json/world.json

  • 保存路徑同樣為:public/map/world.json


🧱 四、完整代碼實現(Composition API)

創建組件 OpenlayersPlane.vue,核心代碼如下:

<!--* @Author: 彭麒* @Date: 2025/7/8* @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 地圖上Echarts模擬飛機循環飛行</div></div><div id="vue-openlayers"></div></div>
</template><script setup>
import { onMounted } from 'vue'
import 'ol/ol.css'
import { Map, View } from 'ol'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'
import EChartsLayer from 'ol-echarts'
import * as echarts from 'echarts/core'
// 引入世界地圖數據
import { registerMap } from 'echarts/core'let map = nullonMounted(async () => {// 注冊世界地圖數據try {// 方法1:如果你已下載文件到項目中// import worldJson from '@/assets/geo/world.json'// 方法2:從公共目錄獲取const worldJson = await fetch('/map/china.json').then(res => res.json())//// // 注冊世界地圖數據registerMap('world', worldJson)initMap()} catch (error) {console.error('加載世界地圖數據失敗:', error)}
})function initMap() {const osmLayer = new TileLayer({source: new OSM()})map = new Map({target: 'vue-openlayers',layers: [osmLayer],view: new View({projection: 'EPSG:4326',center: [116.53, 39.44],zoom: 7})})// 正確初始化 EChartsLayerconst option = getOption()const echartslayer = new EChartsLayer(option, {hideOnMoving: false,hideOnZooming: false,forcedRerender: true, // 強制重新渲染coordinate: map.getView().getProjection().getCode()})echartslayer.appendTo(map)
}function getOption() {const geoCoordMap = {'北京': [116.4551, 40.2539],'上海': [121.4648, 31.2891],'廣州': [113.5107, 23.2196],'大連': [122.2229, 39.4409],'南寧': [108.479, 23.1152],'南昌': [116.0046, 28.6633],'拉薩': [91.1865, 30.1465],'長春': [125.8154, 44.2584],'包頭': [110.3467, 41.4899],'重慶': [107.7539, 30.1904],'常州': [119.4543, 31.5582],'昆明': [102.9199, 25.4663],'鄭州': [113.4668, 34.6234],'長沙': [113.0823, 28.2568],'丹東': [124.541, 40.4242]}const BJData = [[{ name: '北京' }, { name: '上海', value: 95 }],[{ name: '北京' }, { name: '廣州', value: 90 }],[{ name: '北京' }, { name: '大連', value: 80 }],[{ name: '北京' }, { name: '南寧', value: 70 }],[{ name: '北京' }, { name: '南昌', value: 60 }],[{ name: '北京' }, { name: '拉薩', value: 50 }],[{ name: '北京' }, { name: '長春', value: 40 }],[{ name: '北京' }, { name: '包頭', value: 30 }],[{ name: '北京' }, { name: '重慶', value: 20 }],[{ name: '北京' }, { name: '常州', value: 10 }]]const SHData = [[{ name: '上海' }, { name: '包頭', value: 95 }],[{ name: '上海' }, { name: '昆明', value: 90 }],[{ name: '上海' }, { name: '廣州', value: 80 }],[{ name: '上海' }, { name: '鄭州', value: 70 }],[{ name: '上海' }, { name: '長春', value: 60 }],[{ name: '上海' }, { name: '重慶', value: 50 }],[{ name: '上海' }, { name: '長沙', value: 40 }],[{ name: '上海' }, { name: '北京', value: 30 }],[{ name: '上海' }, { name: '丹東', value: 20 }],[{ name: '上海' }, { name: '大連', value: 10 }]]const planePath ='path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z';function convertData(data) {const res = []for (let i = 0; i < data.length; i++) {const fromCoord = geoCoordMap[data[i][0].name]const toCoord = geoCoordMap[data[i][1].name]if (fromCoord && toCoord) {res.push({fromName: data[i][0].name,toName: data[i][1].name,coords: [fromCoord, toCoord]})}}return res}const color = ['#f00', '#0000ff']const series = []// 修復數組格式和括號對齊問題const dataList = [['北京', BJData],['上海', SHData]]dataList.forEach((item, i) => {series.push({name: item[0] + ' Top10',type: 'lines',coordinateSystem: 'geo', // 添加坐標系統zlevel: 1,effect: {show: true,period: 6,trailLength: 0.7,color: '#fff',symbolSize: 3},lineStyle: {normal: {color: color[i],width: 0,curveness: 0.2}},data: convertData(item[1])},{name: item[0] + ' Top10',type: 'lines',coordinateSystem: 'geo', // 添加坐標系統zlevel: 2,effect: {show: true,period: 6,trailLength: 0,symbol: planePath,symbolSize: 15},lineStyle: {normal: {color: color[i],width: 1,opacity: 0.4,curveness: 0.2}},data: convertData(item[1])},{name: item[0] + ' Top10',type: 'effectScatter',coordinateSystem: 'geo',zlevel: 2,rippleEffect: {brushType: 'stroke'},label: {normal: {show: true,position: 'right',formatter: '{b}'}},symbolSize(val) {return val[2] / 8},itemStyle: {normal: {color: color[i]}},data: item[1].map(dataItem => ({name: dataItem[1].name,value: geoCoordMap[dataItem[1].name].concat([dataItem[1].value])}))})})return {tooltip: {trigger: 'item'},geo: {map: 'world',roam: true,silent: true,itemStyle: {normal: {borderColor: 'rgba(0, 0, 0, 0.2)'}}},series}
}
</script><style scoped>
.container {width: 840px;height: 570px;margin: 50px auto;border: 1px solid #42B983;position: relative;
}#vue-openlayers {width: 800px;height: 450px;margin: 0 auto;border: 1px solid #42B983;position: relative;
}
</style>

🔍 五、關鍵說明

? 為什么用 ol-echarts

  • 官方維護,輕量集成 ECharts 圖層到 OpenLayers

  • 支持地圖縮放拖拽不丟失動畫

  • 自動將 ECharts 轉換為地圖坐標系

? 為什么要注冊地圖數據?

ECharts 默認不包含地圖底圖,注冊 worldchina 是必須的。

? 常見問題:

  • ? 地圖加載失敗:檢查 /map/china.json 路徑是否正確

  • ? 飛機不動:確認 symbol 使用了合法的 SVG path

  • ? 加載慢:地圖數據盡量緩存到本地,避免 CDN 延遲


🔚 六、結語與拓展建議

這只是地理可視化的一個小案例,你還可以嘗試:

  • 🌟 動態航線實時更新(結合 WebSocket)

  • 🧭 飛機移動+轉向效果(結合 Cesium)

  • 📡 與后端數據庫聯動(顯示實時航班位置)

  • 🎯 鼠標交互事件,如點擊城市展示信息面板


📁 七、項目源碼 & 參考

  • OpenLayers 官網:https://openlayers.org/

  • ECharts 官網:https://echarts.apache.org/

  • ol-echarts 項目地址:https://github.com/sakitam-gis/ol-echarts

  • 阿里地圖數據源:https://datav.aliyun.com/tools/atlas/


如果你覺得這篇文章對你有幫助,歡迎點贊 👍、收藏 ?、關注我獲取更多前端 + 地圖可視化實戰教程!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/88223.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/88223.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/88223.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OCR與PDF解析的區別

我們日常所接觸的文檔中&#xff0c;經常能碰到多語言混合的文檔。比如論文試卷、財報研報、跨國票據都含有多種語言和文字。要將文檔中的內容識別并提取務必需要使用到OCR技術&#xff0c;而傳統的OCR工具在處理這類型文檔的時候有局限性。早期的 OCR 系統識別精度有限&#x…

Java 單例類詳解:從基礎到高級,掌握線程安全與高效設計

作為一名Java開發工程師&#xff0c;你一定對**單例模式&#xff08;Singleton Pattern&#xff09;**不陌生。它是23種經典設計模式中最簡單也是最常用的一種&#xff0c;用于確保一個類在整個應用程序中只有一個實例存在。單例廣泛應用于系統配置、數據庫連接池、日志管理器、…

面向對象設計

你列出的這些屬于 C 高級開發中面向對象設計與架構設計的核心知識&#xff0c;也是面試高級工程師崗位必問的內容。下面我按順序&#xff0c;深入講解每一項概念、原理、用途&#xff0c;并穿插 C 示例。? 1. 設計原則&#xff08;SOLID&#xff09;SOLID 是面向對象設計的五大…

IntelliJ IDEA讓我的開發效率翻倍:從新手到高效開發者的進階之路

IntelliJ IDEA讓我的開發效率翻倍&#xff1a;從新手到高效開發者的進階之路 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用…

css sprites使用

CSS Sprites 是一種將多個小圖標或背景圖像合并到一個大圖中的技術。通過減少HTTP請求次數&#xff0c;可以顯著提高頁面加載速度。其核心原理是&#xff1a;通過設置元素的背景圖&#xff08;background-image&#xff09;為這個大圖&#xff0c;然后調整背景位置&#xff08;…

分布式爬蟲在電商平臺商品數據大規模采集中的技術應用

在電商平臺商品數據大規模采集場景中&#xff0c;分布式爬蟲憑借其高效、可擴展、抗風險的特性&#xff0c;成為突破單節點爬蟲性能瓶頸的核心技術方案。以下從技術架構、關鍵技術點、電商場景適配及挑戰應對四個維度&#xff0c;解析其具體應用&#xff1a;一、分布式爬蟲的核…

Linux的`if test`和`if [ ]中括號`的取反語法比較 筆記250709

Linux的if test和if 中括號的取反語法比較 筆記250709 Linux的 test命令&#xff08;或等價中括號寫法 [空格expression空格]&#xff09;的用法詳解. 筆記250709 四種取反語法: if ! test -e xxx ;then... 和 if test ! -e xxx ;then... 和 if ! [ -e xxx ] ;then... 和 if …

記錄使用ubuntu16.04編譯aosp(android8.1與10)遇到的問題

一、前言&#xff1a; 本來打算用wsl來編譯AOSP&#xff0c;但是折騰了好幾天&#xff0c;以失敗告終。后來使用vmware反而成功了。 本篇同樣會把wsl遇到的問題與嘗試記錄下來。 環境&#xff1a;vmware ubuntu16.04。 為什么會使用ubuntu16.04呢&#xff0c;因為在公司有一…

hiredis window之RFDMap

簡介 RFDMap用于將socket分配映射成連續的文件描述符&#xff0c;同時管理回收的文件描述符&#xff0c;因為ae構架中管理fd與對應事件處理器使用的是數據&#xff0c;fd作為數組下標 結構 #mermaid-svg-zQz2LTrKRi0LQTII {font-family:"trebuchet ms",verdana,arial…

RustFS一款Rust 驅動的 高性能 分布式存儲系統

演示地址&#xff1a;https://play.rustfs.com/browser 訪問賬號&#xff08;默認 rustfsadmin&#xff09;。 訪問密鑰&#xff08;默認 rustfsadmin&#xff09;。 下載mc https://dl.min.io/client/mc/release可以直接在 Linux 系統上安裝 mc&#xff08;&#xff0c;然后訪…

微軟 Bluetooth LE Explorer 實用工具的詳細使用分析

微軟 Bluetooth LE Explorer 實用工具的詳細使用分析 文章目錄 微軟 **Bluetooth LE Explorer** 實用工具的詳細使用分析1. **工具定位與核心功能**2. **關鍵特性與更新**3. **使用場景示例**4. **系統要求與依賴**5. **與專業工具對比**6. **局限性**7. **實踐建議**結論以下是…

centos 7.6安裝mysql8

在 CentOS 7.6 上安裝 MySQL 8.0.42 的步驟如下&#xff0c;基于搜索結果中的最新信息&#xff1a; 下載 MySQL 8.0.42 安裝包 https://dev.mysql.com/downloads/mysql/從 MySQL 官方網站下載 mysql-8.0.42-1.el7.x86_64.rpm-bundle.tar 文件&#xff1a; 官方下載地址&#xf…

CentOS7更換阿里云yum源

問題&#xff1a;剛剛在本地安裝了CentOS7虛擬機&#xff0c;使用yum安裝vim軟件時&#xff08;最小化安裝只有vi沒有vim&#xff09;出現下面的報錯原因 &#xff1a;CentOS7 已于2024-6-30停止維護&#xff0c;官方鏡像源已不可用&#xff0c;可以更換為阿里云鏡像源解決&…

UE5內置插件 AnimToTexture 簡單入門

開啟插件 首先安裝插件&#xff0c;然后重啟。打開顯示插件內容我們就可以找到插件自帶的轉換內容將骨骼網格體轉換為頂點動畫有兩種方式&#xff1a; 最簡單的記錄每個頂點的位置然后通過切換拾取顏色偏移實現記錄骨骼的變換&#xff0c;然后通過貼圖去修改骨骼位置計算 這兩種…

如何搭建Appium環境?

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快1、安裝Java Development Kit&#xff08;JDK&#xff09;前往Oracle官網下載JDK。在https://www.oracle.com/java/technologies/javase-jdk11-downloads.html 找到…

Android kotlin 協程的詳細使用指南

Android Kotlin 協程的詳細使用指南&#xff0c;結合核心概念、實戰場景和最佳實踐&#xff1a;一、協程基礎概念?協程本質?協程是輕量級線程&#xff0c;通過掛起/恢復機制實現并發&#xff0c;相比線程節省90%以上的內存開銷。其核心優勢在于結構化并發和掛起函數的協作式調…

什么是 AMR 格式?簡鹿音頻轉換器輕松批量轉換 AMR 為 MP3

AMR 格式是一種比較特殊但又常見的音頻格式&#xff0c;而MP3 格式則是大家耳熟能詳的通用音頻格式。那么&#xff0c;它們之間有什么區別&#xff1f;又該如何把 AMR 文件轉換成更常用的 MP3 呢&#xff1f;下面我們就來通俗地了解一下。一、什么是 AMR 格式&#xff1f;AMR&a…

C++11 std::move與std::move_backward深度解析

文章目錄移動語義的革命性意義std::move&#xff1a;正向范圍移動函數原型與核心功能關鍵特性與實現原理適用場景與代碼示例危險區域&#xff1a;重疊范圍的未定義行為std::move_backward&#xff1a;反向安全移動函數原型與核心功能關鍵特性與實現原理適用場景與代碼示例重疊范…

訂單初版—2.生單鏈路中的技術問題說明文檔

大綱1.生單鏈路的業務代碼2.生單鏈路中可能會出現數據不一致的問題3.Seata AT模式下的分布式事務的原理4.Seata AT模式下的分布式事務的讀寫隔離原理5.Seata AT模式下的死鎖問題以及超時機制6.Seata AT模式下的讀寫隔離機制的影響7.生單鏈路使用Seata AT模式的具體步驟8.生單鏈…

跨平臺ROS2視覺數據流:服務器運行IsaacSim+Foxglove本地可視化全攻略

任務目標 本教程將完整實現&#xff1a; 在服務器無頭模式下運行IsaacSim&#xff0c;并在本地顯示GUI界面 通過IsaacSim的ROS2 Bridge發布圖像數據 在本地Foxglove中實時可視化服務器端的ROS2數據流 實現步驟 1. 服務器無頭運行IsaacSim 本地GUI顯示 在服務器端執行&am…