I have a very big KML file (8MB | 8300+ features) and I need a way to load it offline. After some research I liked the clusterization method, using OpenLayers Cluster
, but it only works for points:
Layer source to cluster vector data. Works out of the box with point geometries. For other geometry types, or if not all geometries should be considered for clustering, a custom geometryFunction can be defined.
If I try to use the method with the polygons nothing shows up. So, I tried to 'transform' the features in points while zoom is out and and show these features as a point cluster, then revert to original geometry when zoom is close enough. I found some very similar problem that I relied on. But now I get an error that I didn't receive before when applying the method without converting to points:
AssertionError {
code: 10,
name: "AssertionError",
message: "Assertion failed. See https://openlayers.org/en/v5.3.3/doc/errors/#10 for details."
}
The default geometryFunction can only handle ol/geom/Point geometries.
I found it strange to receive this error, because in the problem link I mentioned the OP does the same procedure and does not receive any error.
Load layer function
// Create layer and sources
let newVectorSource = new VectorSource({})
let newVectorLayer = new VectorLayer({
source: new Cluster({
distance: 50,
source: newVectorSource,
}),
name: layer['layer_id'],
visible: false
});
// Read file and add to map
this.file.readAsText(path, filename).then(layer_file => {
let format = new KML({});
newVectorSource.addFeatures(format.readFeatures(layer_file, {
featureProjection:"EPSG:3857",
dataProjection: "EPSG:4326"
}));
this.map.addLayer(newVectorLayer);
for (let i = newVectorSource.getFeatures().length - 1; i >= 0; i--) {
/* Create style function to polygons act like points,
so we can show them like clusters
*/
let stroke = new Stroke({
color: 'orange',
width: 3
});
let fill = new Fill({
color: 'rgba(255, 165, 0, 0.1)'
})
// Create geometry function
let zoomInStyle = new Style({
stroke: stroke,
fill: fill,
geometry: (feature) => {
let originalFeature = newVectorSource.getFeatures()[i];
return originalFeature.getGeometry();
}
});
let zoomOutStyle = new Style({
stroke: stroke,
fill: fill,
geometry: (feature) => {
let type = feature.getGeometry().getType();
if (type === 'Polygon') {
return feature.getGeometry().getInteriorPoint();
} else if (type === 'LineString') {
// also tried feature.getClosestPoint();
return getCenter(feature.getGeometry().getExtent());
}
}
});
let featureStyleFunction = (feature, res) => {
if (res > 10) {
return zoomOutStyle;
} else {
return zoomInStyle;
}
};
// Set new style to feature
newVectorSource.getFeatures()[i].setStyle(featureStyleFunction);
}
});
EDIT Cache style
let styleCache = {};
let newVectorLayerCluster = new VectorLayer({
source: new Cluster({
distance: 100,
source: newVectorSource,
geometryFunction: (feature) => {
let resolution = this.map.getView().getResolution();
if (resolution > 10) {
let type = feature.getGeometry().getType();
if (type === 'Polygon') {
return feature.getGeometry().getInteriorPoint();
} else if (type === 'LineString') {
return feature.getGeometry().getCoordinateAt(0.5);
}
}
}
}),
style: (feature) => {
let size = feature.get('features').length;
let style = styleCache[size];
if (!style) {
style = new Style({
image: new CircleStyle({
radius: 10,
stroke: new Stroke({
color: '#fff',
}),
fill: new Fill({
color: '#3399CC',
}),
}),
text: new Text({
text: size.toString(),
fill: new Fill({
color: '#fff',
}),
})
});
styleCache[size] = style;
}
return style;
},
name: layer['layer_id'],
visible: false
});
The geometryFunction the documentation and the linked question refer to is an option in the cluster source
source: new Cluster({
distance: 50,
source: newVectorSource,
geometryFunction: function(feature) {
let type = feature.getGeometry().getType();
if (type === 'Polygon') {
return feature.getGeometry().getInteriorPoint();
} else if (type === 'LineString') {
return feature.getGeometry().getCoordinateAt(0.5);
}
},
}),
The midpoint (label point) of a linestring may be more convenient than the extent center