大量图标方案
此处的大量图标方案,不涉及服务器端,如果图标不进行交互,可以把图标渲染到底图上。 此处只介绍说明在前端可交互的大量图标方案,在图标数量不大的情况,无论使用什么方式加载,都不会有性能问题,当图标多了之后,就会出现卡顿,内存占用增大等问题。 在OpenLayers 3开发中,可以考虑下面两个方案来解决这个问题。
复用样式减少内存占用
在应用大量图标的时候,其实图标样式差异化并不大,比如快餐店,公共厕所,公交站点等等有很多,但都是用同样的图标在地图上标准,在不注意的时候,我们是采用下面的方式来添加图标的:
for (var index = 0; index < 10000; index++) {
var feature = new ol.Feature({
geometry: new ol.geom.Point([latlon[index].lon, latlon[index].lat])
});
feature.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker.png'
})
}));
}
注意上面代码,对每个feature
设置style
的时候,都是直接new
的,这样势必会创建很多对象,占用很多内存。 那么复用必然减少很多内存,重构上面的代码为:
var style = new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker.png'
})
});
for (var index = 0; index < 10000; index++) {
var feature = new ol.Feature({
geometry: new ol.geom.Point([latlon[index].lon, latlon[index].lat])
});
feature.setStyle(style);
}
这样,我们就只创建了一个style
对象,那么势必减少内存占用。 如果有多类图标,可以用数组缓存下来:
var styles = [
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker1.png'
})
}),
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker2.png'
})
}),
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker3.png'
})
})
];
for (var index = 0; index < 10000; index++) {
var feature = new ol.Feature({
geometry: new ol.geom.Point([latlon[index].lon, latlon[index].lat])
});
feature.setStyle(styles[index % styles.length]);
}
由于官网有实际的例子,大家请移步到icon-sprite-webgl。 下面是其中的一些代码片段,在里面加入了一些注释,便于大家理解:
// 预先设置好要使用的style,并缓存在icons数组中
for (i = 0; i < iconCount; ++i) {
var info = iconInfo[i];
icons[i] = new ol.style.Icon({
offset: info.offset,
opacity: info.opacity,
rotateWithView: info.rotateWithView,
rotation: info.rotation,
scale: info.scale,
size: info.size,
src: 'data/Butterfly.png'
});
}
......
for (i = 0; i < featureCount; ++i) {
geometry = new ol.geom.Point(
[2 * e * Math.random() - e, 2 * e * Math.random() - e]);
feature = new ol.Feature(geometry);
feature.setStyle(
new ol.style.Style({
// 直接使用上面缓存的icons里面的样式
image: icons[i % (iconCount - 1)]
})
);
features[i] = feature;
}
大家可在官网例子的基础上修改一下代码,验证一下复用和不复用的情况下,内存占用相差多少。
复用Canvas提高效率
采用上一种方式基本能解决掉绝大部分的问题,但是OpenLayers 3还提供了一种复用图标渲染使用的Canvas
的方式,对应的类是ol.style.AtlasManager
。 在了解其作用之前,需要先了解一点图标的渲染机制,比如ol.style.Circle
和ol.style.RegularShape
这样的图标,在内部渲染时,都会创建一个HTML的canvas
,然后在这个画布上绘制图像,然后再把图像复制到地图上。 这样创建一个图标,就会在内部创建一个canvas
。 ol.style.AtlasManager
解决的问题就是,用一个大的canvas
来绘制多个图标,这样就能减少canvas
的数量,从而提高效率。
官网有一个具体的例子来说明这种方法的使用,参见Symbols with WebGL。 其中,关键的代码在:
var atlasManager = new ol.style.AtlasManager({
// we increase the initial size so that all symbols fit into
// a single atlas image
initialSize: 512
});
......
// circle symbol
symbols.push(new ol.style.Circle({
opacity: info.opacity,
scale: info.scale,
radius: radiuses[j],
fill: new ol.style.Fill({
color: info.fillColor
}),
stroke: new ol.style.Stroke({
color: info.strokeColor,
width: 1
}),
// by passing the atlas manager to the symbol,
// the symbol will be added to an atlas
atlasManager: atlasManager // 注意:在创建style的这个地方设置了 atlasManager
}));
需要注意的是,在API官方文档上,并没有这个属性的设置,但内部实现是有这个优化的。 同时需要注意的是经常使用的ol.style.Icon
目前是没有实现这个优化的。