项目中使用的是高德地图,官网api:lbs.amap.com/api/javascr…
使用过程中,因为图层很多,导致操作地图时越来越卡,故需要优化,从以下几点开始尝试,本文仅做笔记记录。
setFitView去掉过渡动画效果
amapObj.map.setFitView(polygon);
改成
amapObj.map.setFitView(polygon, true);
- svg改成批量请求
store.showFenceBoundary.listen((showFenceBoundary) => {
if (!amapObj.map) return;
const _svgUrl = Remote.gridMap.getSvg;
if (showFenceBoundary) {
if (amapObj.map.getZoom() < 11) return;
gridFlexibleLayer = new AMap.TileLayer.Flexible({
createTile: (x, y, z, success, fail) => {
if (z < 12) return;
$.get(_svgUrl, { x, y, z }, (packVo) => {
if (!packVo) return;
let vo;
if (typeof packVo === 'string') {
try {
vo = JSON.parse(packVo);
} catch (e) {
fail('解析packVo出错');
return;
}
}
if (vo && vo.msgs && vo.msgs.length) {
fail('packVo包含错误消息');
return;
}
if (typeof packVo === 'object' && !Array.isArray(packVo) && packVo !== null && packVo.messages) {
fail('packVo包含错误消息');
return;
}
const canvasEle = document.createElement('canvas');
canvasEle.width = canvasEle.height = 256;
const content = canvasEle.getContext('2d');
let str = `${XML2String(packVo)}`.replace(
'<svg height="256" width="256">',
'<svg xmlns="http://www.w3.org/2000/svg" style="fill-opacity: 0;stroke:#1890ff;stroke-width:1;">',
);
const img = new Image();
img.src = 'data:image/svg+xml;base64,' + window.btoa(str);
img.onload = () => {
content.drawImage(img, 0, 0);
success(canvasEle);
};
});
},
});
amapObj.map.add(gridFlexibleLayer);
} else {
const { operateMode } = store.state;
gridFlexibleLayer && amapObj.map.remove(gridFlexibleLayer);
gridFlexibleLayer = null;
if (operateMode === 'fenceDrawing') actions.operateModeChange('default');
}
});
改成
// 队列存储请求参数
const gridRequestQueue = [];
let gridTimer = null;
// 批量请求发送逻辑
const batchSendGridRequests = () => {
if (!gridRequestQueue.length) return;
// 获取所有队列数据并清空
const paramsList = gridRequestQueue.splice(0);
// 按批次组织请求参数
const batchedParams = paramsList.map(({ x, y, z }) => ({ x, y, z }));
$.postJSONBody(Remote.gridMap.listSvg, batchedParams, (responseList) => {
// 遍历批量请求的返回结果,按顺序处理
if (responseList && responseList.voList && responseList.voList.length) {
responseList.voList.forEach((packVo, index) => {
const { success, fail } = paramsList[index];
const canvasEle = document.createElement('canvas');
canvasEle.width = canvasEle.height = 256;
const content = canvasEle.getContext('2d', { willReadFrequently: true });
let str = `${packVo}`.replace(
'<svg height="256" width="256">',
'<svg xmlns="http://www.w3.org/2000/svg" style="fill-opacity: 0;stroke:#1890ff;stroke-width:1;">',
);
const img = new Image();
img.src = 'data:image/svg+xml;base64,' + window.btoa(str);
img.onload = () => {
content.drawImage(img, 0, 0);
success(canvasEle);
};
});
}
});
};
// 定时启动批量请求逻辑
const startBatching = () => {
if (!gridTimer) {
gridTimer = setInterval(batchSendGridRequests, 500); // 每隔1秒处理一次队列
}
};
// 主逻辑
store.showFenceBoundary.listen((showFenceBoundary) => {
if (!amapObj.map) return;
if (showFenceBoundary) {
if (amapObj.map.getZoom() < 12) return;
gridFlexibleLayer = new AMap.TileLayer.Flexible({
createTile: (x, y, z, success, fail) => {
if (z < 12) return; // 过滤掉z<12的参数
// 将请求加入队列
gridRequestQueue.push({ x, y, z, success, fail });
// 启动批量处理
startBatching();
},
});
amapObj.map.add(gridFlexibleLayer);
} else {
const { operateMode } = store.state;
// 移除图层并清理定时任务
gridFlexibleLayer && amapObj.map.remove(gridFlexibleLayer);
gridFlexibleLayer = null;
if (operateMode === 'fenceDrawing') {
actions.operateModeChange('default');
}
// 清理批量请求逻辑
clearInterval(gridTimer);
gridTimer = null;
gridRequestQueue.length = 0; // 清空队列
}
});
- 网点图层优化 保存近3次的搜索批次的结果,更早的结果在地图上清除掉。为什么要保存最近几次是为了交互上有隐藏的过渡效果,看上去没有闪烁。
// mapStoreListener.js文件
let geoSiteMapOverlay = {}; // 网点geojson图层
let batchSiteMapNumbers = []; // 每一批搜索的网点geojson的批号
/**
* 网点区域展示
*/
store.siteMapListVo.listen((siteMapListVo) => {
const { features = [] } = siteMapListVo || {};
// 网关,清除网点图层
if (!features.length && !store.state.showSiteCanton) {
const sitePolygonOverlays = amapObj.map.getAllOverlays('polygon').filter((overlay) => {
const extData = overlay.getExtData();
return extData && extData.flag === 'siteMap';
});
const siteMarkerOverlays = amapObj.map.getAllOverlays('marker').filter((overlay) => {
const extData = overlay.getExtData();
return extData && extData.flag === 'siteMapMarker';
});
const siteOverlays = [...sitePolygonOverlays, ...siteMarkerOverlays];
amapObj.map.remove(siteOverlays);
geoSiteMapOverlay = {};
}
if (!features.length) return;
const currentBatchNumber = Math.random().toString(36).slice(2, 11);
batchSiteMapNumbers.push(currentBatchNumber);
const geojson = new AMap.GeoJSON({
geoJSON: siteMapListVo,
getPolygon: function (item, lnglats) {
const { properties = {} } = item;
const { id, siteId, siteName } = properties;
const key = `${id}-${siteId}`;
let polygon = geoSiteMapOverlay && geoSiteMapOverlay[key] && geoSiteMapOverlay[key].polygon;
if (!polygon) {
polygon = new AMap.Polygon({
path: lnglats,
// strokeColor: 'black',
fillColor: getSiteRandomFillColor(properties),
strokeWeight: 1,
fillOpacity: 0.2,
bubble: true,
zIndex: 13,
extData: {
sitePolygonId: `${id}-${siteId}`,
flag: 'siteMap',
batchNumber: currentBatchNumber,
},
});
if (!geoSiteMapOverlay[key]) {
geoSiteMapOverlay[key] = {};
}
geoSiteMapOverlay[key].polygon = polygon;
} else {
polygon.setExtData({
sitePolygonId: `${id}-${siteId}`,
flag: 'siteMap',
batchNumber: currentBatchNumber,
});
}
let labelMarker = geoSiteMapOverlay && geoSiteMapOverlay[key] && geoSiteMapOverlay[key].labelMarker;
if (!labelMarker) {
labelMarker = new AMap.Marker({
position: polygon.getBounds().getCenter(),
content: `<div class="amap_marker_content">${siteName}</div>`,
offset: new AMap.Pixel(0, -10),
// bubble: true,
zIndex: 16,
extData: {
siteLabelId: `${id}-${siteId}`,
flag: 'siteMapMarker',
batchNumber: currentBatchNumber,
},
});
geoSiteMapOverlay[key].labelMarker = labelMarker;
labelMarker.on('click', function (event) {
// 查看模式下才能点击网点标签
if (!store.state.editMode) {
actions.updateHighlightedPolygon(
{
type: 'FeatureCollection',
features: [item],
},
'site',
'click',
);
}
});
labelMarker.setMap(amapObj.map);
} else {
labelMarker.setExtData({
sitePolygonId: `${id}-${siteId}`,
flag: 'siteMapMarker',
batchNumber: currentBatchNumber,
});
}
return polygon;
},
});
amapObj.map.add(geojson);
if (batchSiteMapNumbers.length > 3) {
const newSiteMapBatchNumbers = _.takeRight(batchSiteMapNumbers, 3);
const oldSitetBatchNumbers = _.difference(batchSiteMapNumbers, newSiteMapBatchNumbers);
// 清理对应批次的覆盖物
const oldSitePolygonOverlays = amapObj.map.getAllOverlays('polygon').filter((overlay) => {
const extData = overlay.getExtData();
return extData && oldSitetBatchNumbers.includes(extData.batchNumber);
});
const oldSiteMarkerOverlays = amapObj.map.getAllOverlays('marker').filter((overlay) => {
const extData = overlay.getExtData();
return extData && oldSitetBatchNumbers.includes(extData.batchNumber);
});
const oldSiteOverlays = [...oldSitePolygonOverlays, ...oldSiteMarkerOverlays];
amapObj.map.remove(oldSiteOverlays); // 移除最早批次的所有覆盖物
batchSiteMapNumbers = newSiteMapBatchNumbers;
}
});
// store.js文件
// --- 加载网点
onLoadSiteMapCompleted(res = {}) {
const result = res.vo || {};
// const newSiteMapFeatures = handleFeatures(this.state.siteMapListVo.features, result.features);
this.setState({
siteMapListVo: {
features: result.features || [],
type: 'FeatureCollection',
},
});
},