🧩 效果預覽
👇 飛機從多個城市起飛并向其他城市飛行,動畫流暢,地圖可縮放拖拽:
📦 一、項目技術棧
技術 | 用途 |
---|---|
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 + TypeScript
或 Vue 3 + JavaScript
皆可。
2. 安裝必要依賴
npm install ol echarts ol-echarts
如果你使用的是 Vite 構建工具,也可以添加 ECharts 按需引入優化:
🌍 三、準備地圖 JSON 數據
我們需要一個 GeoJSON 格式的中國地圖數據 作為 ECharts 的底圖。你有兩種方式下載:
? 方法一:使用阿里官方提供的地圖數據
-
打開:https://geo.datav.aliyun.com/areas/bound/100000_full.json
-
將其放入你的項目
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 默認不包含地圖底圖,注冊 world
或 china
是必須的。
? 常見問題:
-
? 地圖加載失敗:檢查
/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/
如果你覺得這篇文章對你有幫助,歡迎點贊 👍、收藏 ?、關注我獲取更多前端 + 地圖可視化實戰教程!