1.大量点标记的处理(点聚合||海量点)
普通点标记 Marker 是一个个 dom,当 Marker 太多时内存占用过高,页面会卡顿,可采用两种优化方案:
-
点聚合:设置 gridSize,相邻点进行聚合,减少 dom 数
示例:点聚合-点标记-示例中心-JS API 示例 | 高德地图API
// 聚合渲染
renderCluster() {
this.curVisibleType.map(type => {
this.dataMap[type].map(item => {
const marker = new AMap.Marker({
offset: new AMap.Pixel(this.markerOffset.x, this.markerOffset.y),
extData: { ...item, type },
position: item.position,
content: this.setCabinet(this.typeMap[type], item.hasCount)
});
marker.on("click", this.handleMarkerClick);
this[`markers${type}`].push(marker);
});
this[`cluster${type}`] = new AMap.MarkerClusterer(
this.mapInst,
this[`markers${type}`],
{
gridSize: 80,
maxZoom: 18,
renderClusterMarker: ({ count, marker, markers }) => {
this.customClusterMarker({ count, marker, markers }, type);
}
}
);
});
}
-
海量点:将同类点绘制到一个 canvas 图层里,提升性能,解决卡顿
注意 :海量点图层的创建、显隐、事件、自定义样式是否能达到需求效果
//创建海量点柜机图层
createMassMarks(index, data, type) {
let styleObjectArr = [
{
size: new AMap.Size(24, 24), // 图标大小
anchor: new AMap.Pixel(12, 12), // 图标显示位置偏移量,基准点为图标中心
url: require('@/assets/img/siteSel/usual-cabinet.svg')
}, //不动
{
size: new AMap.Size(24, 24),
anchor: new AMap.Pixel(12, 12),
url: require('@/assets/img/siteSel/add-cabinet.svg')
}, //扩容
{
size: new AMap.Size(24, 24),
anchor: new AMap.Pixel(12, 12),
url: require('@/assets/img/siteSel/sub-cabinet.svg')
}, //缩容
{
size: new AMap.Size(24, 24),
anchor: new AMap.Pixel(12, 12),
url: require('@/assets/img/siteSel/zero-cabinet.svg')
}, //0周转
{
size: new AMap.Size(20, 20),
anchor: new AMap.Pixel(10, 10),
url: require('@/assets/img/siteSel/nerveCabinet.svg')
} //最优普通||图神经普通
];
let massMarksList = new AMap.MassMarks(data, {
cursor: 'pointer',
style: styleObjectArr,
zIndex: index, // 海量点图层叠加的顺序
zooms: [3, 19] // 在指定地图缩放级别范围内展示海量点图层
});
}
效果图:
2.大量 polyline 时的处理
当地图内的 polyline 太多时,内存占用过高,页面会卡顿
解决思路:三重过滤数据:只加载可视区内的边->过滤太短的边->根据缩放等级确定加载量 缩放等级太低时加载少量边
-
加载可视区内的边(可通过绘制可视区区域或者高德自带计算线面关系 API(数学计算库-参考手册-地图 JS API | 高德地图API)
let tmapBounds = this.mapInst.getBounds();
let southWest = new AMap.LngLat(
tmapBounds.southwest.lng,
tmapBounds.southwest.lat
);
let northEast = new AMap.LngLat(
tmapBounds.northeast.lng,
tmapBounds.northeast.lat
);
//绘制地图可视区域
let bounds = new AMap.Bounds(southWest, northEast);
this.rectangle = new AMap.Rectangle({
bounds: bounds,
strokeColor: "red",
strokeWeight: 6,
strokeOpacity: 0,
strokeStyle: "dashed",
fillColor: "blue",
fillOpacity: 0,
cursor: "pointer",
zIndex: 50,
bubble: true,
});
this.rectangle.setMap(this.mapInst);
type == 0 &&
(ary = ary.filter(
(item) =>
this.rectangle.contains(item.originPosition) ||
this.rectangle.contains(item.endPosition)
)); //短物理边 两个端点在可视区内即加载
type == 1 &&
(ary = ary.filter(
(item) =>
this.rectangle.contains(item.originPosition) ||
this.rectangle.contains(item.endPosition) ||
AMap.GeometryUtil.doesSegmentRingIntersect(
item.originPosition,
item.endPosition,
[
southWest,
northEast,
[southWest.lng, northEast.lat],
[northEast.lat, southWest.lng],
]
)
)); //长频次边 两个端点在可视区内 或者 边与可视区交叉即加载
-
过滤短边
ary = ary.filter(item => this.calculateSideLength(item.originPosition, item.endPosition) > filterLength)
calculateSideLength(originPosition, endPosition) {
//计算边长度
let originLnglat = new AMap.LngLat(originPosition[0], originPosition[1]);
let originPixel = this.mapInst.lngLatToContainer(originLnglat);
let endLnglat = new AMap.LngLat(endPosition[0], endPosition[1]);
let endPixel = this.mapInst.lngLatToContainer(endLnglat);
let length = Math.sqrt(Math.pow(originPixel.x - endPixel.x, 2) + Math.pow(originPixel.y - endPixel.y, 2));
return length;
}
-
根据缩放等级过滤
let num = zoom >= 17 ? ary.length : ary.length > baseNum ? baseNum : ary.length;
[type == 0 || (type == 1 && zoom <= 13)] && (ary = ary.splice(0, num));
效果图:
3.地理围栏为环多边形或多多边形时的处理
问题:某个区域有多个多边形块时,只有第一个块可点击 hover;
解决思路:
1.对于多个多边形块应循环数组直接绘制,对于环多边形,应建立二维数组
2.区分多多边形和环多边形:
-
获取最大多边形块的 path 数组和除最大多边形块的其他多边形块 path 数组;
-
遍历除最大多边形块的其他多边形块 path 数组,包含在最大多边形块里则为环多边形, 否则为多多边形
效果图:
//地理围栏绘制和清除
gridShow() {
this.polygonList.length !== 0 && this.mapInst.remove(this.polygonList);
if (this.gridActive) {
this.polygonList = [];
this.edList.map(item => {
if (item.polygonNum == 1) {
const polygon = this.createPolygon(item, item.polygonList);
this.handlePolygon(polygon);
} else {
//某个区域有多个多边形块时 (解决多个多边形块只有第一个块可点击 hover的问题)
let lengthAry = [];
item.polygonList.map(item => {
lengthAry.push(item.length);
});
let maxLength = Math.max(...lengthAry);
let maxPolygonAry = item.polygonList.filter(item => item.length == maxLength); //最大多边形块的path数组
let otherPolygonAry = item.polygonList.filter(item => item.length !== maxLength); //除最大多边形块的其他多边形块path数组
const maxPolygon = this.createPolygon(item, maxPolygonAry); //最大多边形块
otherPolygonAry.map(items => {
if (maxPolygon.contains(items[0])) {
//如果其他多边形块的点包含在最大多边形块里,说明 为环多边形 建立二维数组
maxPolygonAry[maxPolygonAry.length] = items;
} else {
//如果其他多边形块的点不包含在最大多边形块里,则直接绘制多边形块
const polygon = this.createPolygon(item, items);
this.handlePolygon(polygon);
}
});
//绘制最终的最大多边形块 清除初始最大多边形块
const maxPolygonEnd = this.createPolygon(item, maxPolygonAry);
this.mapInst.remove(maxPolygon);
this.handlePolygon(maxPolygonEnd);
}
});
} else {
this.polygonList.length !== 0 && this.mapInst.remove(this.polygonList);
}
}