maptalks本地缓存瓦片
前言
这篇是为了提升二次加载瓦片速度的文章。受到前一篇图片本地缓存 indexedDB 技术的启发,想把地图的瓦片缓存到本地,达到少请求,优化加载速度。想不到效果还不错,提升至少50%以上。特别在高分辨率地图的情况下。先看对比效果
高分辨率地图二次加载对比
高分辨率地图层级切换对比
一、需求分析
1.1 找到地图引擎中加载瓦片的方法,然后替换。
这一步很重要,如果找不到,很难实现缓存。这篇文章在maptalks的基础上实现的,主要参考官网这篇案例。《用base64编码载入瓦片》
1.2 缓存本地图片
这里和前面一篇相似,indexedDb操作代码参考这里。indexDB 大图缓存
二、核心功能实现
代码比较简单,主要是对baseLayer进行监听,把原本案例中生成base64的部分进行替换。PhotoPool类只是一个缓存本地图片的类。
import axios from 'axios';
import * as maptalks from 'maptalks'
// 图片池
class PhotoPool {
// 存储数据库名称
dbName: string = 'imageCacheDB'
// 存储空间名称
storeName: string = 'images'
constructor (dbName, storeName) {
this.dbName = dbName
this.storeName = storeName
// 1、打开或创建 IndexedDB 数据库
const dbPromise = indexedDB.open(this.dbName, 1);
// 定义对象存储空间, 只有在创建时会调用
dbPromise.onupgradeneeded = (event:any) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName, { keyPath: 'id' });
}
};
// dbPromise.onsuccess = (event:any) => {
// const db = event.target.result;
// if (!db.objectStoreNames.contains(this.storeName)) {
// db.createObjectStore(this.storeName, { keyPath: 'id' });
// }
// }
}
/**
* 获取图片
* @param id 存储时的key,这里用瓦片的横纵序号
* @param url 瓦片地址
* @param callback 回调函数
*/
getImageData (id: string, url: string, callback: Function) {
// 3、 读取
const dbPromise :IDBOpenDBRequest = indexedDB.open(this.dbName, 1);
dbPromise.onsuccess = (event:any) => {
const db = event.target.result;
const tx = db.transaction(this.storeName, 'readonly');
const store = tx.objectStore(this.storeName);
const request = store.get(id);
request.onsuccess = (event:any) => {
const blob = event.target.result;
if (blob) {
callback(blob.imageData)
} else {
this.downloadImage(id, url, callback)
}
};
};
}
/**
* 下载并存储图片
* @param id 存储时的key,这里用瓦片的横纵序号
* @param url 瓦片地址
* @param callback 回调函数
*/
downloadImage (id: string, url: string, callback: Function) {
// const req = axios.get( url, { responseType: 'arraybuffer' });
// 发送GET请求获取图片
axios.get(url, { responseType: 'blob' })
.then(response => {
// 创建一个Blob对象
const blob = new Blob([response.data], { type: 'image/jpeg' });
callback(blob)
// 2、 新增 or 修改
const dbPromise = indexedDB.open(this.dbName);
dbPromise.onsuccess = (event:any) => {
const db = event.target.result;
const tx = db.transaction(this.storeName, 'readwrite');
const store = tx.objectStore(this.storeName);
store.put({ id: id, imageData: blob }); // 将 Blob 对象存储到 IndexedDB
};
})
.catch(error => {
console.error('请求图片失败:', error);
});
}
}
// 主要方法
const pool = new PhotoPool('imageMapDB', 'mapData')
...
baseLayer.on('renderercreate', function (e) {
e.renderer.loadTileImage = function (img, url) {
// 主动获取图片
pool.getImageData(url, url, (blob) => {
// 为瓦片图片赋值
img.src = URL.createObjectURL(blob)
})
};
});
...
const map = new maptalks.Map(id, {
center : [120.1, 30.1],
zoom: 7,
dragPitch: true,
dragRotate: true,
dragRotatePitch: true,
// spatialReference,
baseLayer,
layers: [],
// centerCross: true,
doubleClickZoom: false
})