简介:本文详细介绍了如何基于Vue.js和Leaflet库实现天地图的离线访问,并添加动态飞线效果,帮助开发者解决网络依赖问题并提升地图交互体验。
在地理信息系统(GIS)开发中,天地图作为国内权威的在线地图服务,广泛应用于各类Web应用。然而,依赖在线API存在两大痛点:一是网络不稳定时地图加载失败,二是可能产生额外的API调用费用。尤其在离线环境(如野外作业、军事应用等)下,在线地图完全不可用。
核心需求:
Vue项目├─ src/│ ├─ assets/ # 存储离线瓦片│ ├─ components/ # 地图组件│ │ └─ OfflineMap.vue # 主地图组件│ ├─ utils/ # 工具函数│ │ └─ tileLoader.js # 自定义瓦片加载器└─ public/ # 静态资源
步骤:
wget或专业工具(如MapTiler)下载天地图瓦片
wget --recursive --accept-regex='\d+/\d+/\d+\.png' \-P ./tiles/tianditu https://t0.tianditu.gov.cn/vec_w/wmts?...
./tiles/tianditu/{z}/{x}/{y}.png) 在Leaflet中创建自定义图层类:
// tileLoader.jsclass OfflineTileLayer extends L.TileLayer {constructor(options) {super({...options,// 强制使用本地路径urlTemplate: '/tiles/tianditu/{z}/{x}/{y}.png'});}createTile(coords, done) {const tile = document.createElement('img');// 错误处理:回退到空白图层tile.onerror = () => {tile.src = '/tiles/blank.png';done(null, tile);};L.TileLayer.prototype.createTile.call(this, coords, done);return tile;}}
<!-- OfflineMap.vue --><template><div id="map-container"></div></template><script>import L from 'leaflet';import { OfflineTileLayer } from '@/utils/tileLoader';export default {mounted() {this.initMap();},methods: {initMap() {const map = L.map('map-container').setView([39.9, 116.4], 10);// 添加离线瓦片层const offlineLayer = new OfflineTileLayer({minZoom: 3,maxZoom: 18,attribution: '天地图离线版'}).addTo(map);// 添加其他图层...}}}</script>
使用Leaflet的Polyline和动画:
function createFlyLine(map, startCoord, endCoord) {const line = L.polyline([startCoord, endCoord], {color: '#ff0000',weight: 2}).addTo(map);// 创建动态点const dot = L.circleMarker(startCoord, {radius: 5,fillColor: '#ffff00',fillOpacity: 1}).addTo(map);// 动画逻辑let progress = 0;const interval = setInterval(() => {progress += 0.01;if (progress >= 1) {clearInterval(interval);dot.setLatLng(endCoord);return;}const point = getPointOnLine(line, progress);dot.setLatLng(point);}, 50);}function getPointOnLine(line, t) {const coords = line.getLatLngs();const n = coords.length - 1;const pos = n * t;const i = Math.floor(pos);const frac = pos - i;if (i >= n) return coords[n];const p0 = coords[i];const p1 = coords[i + 1];return [p0.lat + (p1.lat - p0.lat) * frac,p0.lng + (p1.lng - p0.lng) * frac];}
对于大量飞线,建议使用Canvas提升性能:
class FlyLineLayer extends L.Layer {onAdd(map) {this._map = map;this._canvas = L.DomUtil.create('canvas', 'leaflet-zoom-hide');const size = map.getSize();this._canvas.width = size.x;this._canvas.height = size.y;map.getPanes().overlayPane.appendChild(this._canvas);map.on('moveend', this._redraw, this);this._redraw();}_redraw() {const canvas = this._canvas;const ctx = canvas.getContext('2d');const topLeft = this._map.containerPointToLayerPoint([0, 0]);ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制所有飞线this._lines.forEach(line => {const start = this._map.latLngToContainerPoint(line.start);const end = this._map.latLngToContainerPoint(line.end);ctx.beginPath();ctx.moveTo(start.x - topLeft.x, start.y - topLeft.y);ctx.lineTo(end.x - topLeft.x, end.y - topLeft.y);ctx.strokeStyle = line.color || '#ff0000';ctx.lineWidth = line.width || 2;ctx.stroke();// 添加动态点...});}}
vue-leaflet-offline/├── public/│ ├── tiles/ # 离线瓦片目录│ │ ├── tianditu/ # 天地图瓦片│ │ └── blank.png # 错误回退图片├── src/│ ├── components/│ │ └── OfflineMap.vue│ ├── utils/│ │ ├── tileLoader.js│ │ └── flyLine.js│ ├── App.vue│ └── main.js└── vue.config.js # 配置publicPath指向离线资源
瓦片加载404错误
飞线动画卡顿
跨域问题(开发环境)
module.exports = {devServer: {proxy: {'/tiles': {target: 'http://localhost:8080',bypass: function(req) {if (req.headers.accept.indexOf('html') !== -1) {return '/index.html';}return false;}}}}}
本文详细阐述了基于Vue.js和Leaflet实现天地图离线访问的核心技术,包括瓦片离线化、自定义图层开发、动态飞线效果实现等关键环节。通过实际案例分析,开发者可以快速构建出既能在离线环境下稳定运行,又具备丰富交互效果的GIS应用。
未来发展方向:
完整实现代码已上传至GitHub:https://github.com/yourname/vue-leaflet-offline,欢迎交流与改进。