In case the point is part of a cluster (i.e. it has more than one feature), I want to show the quantity of features. I used to do it like this with a VectorLayer
:
const clusterSource = new Cluster({
distance: 50,
minDistance: 10,
source: source,
});
const noClusterStyle = new Style({
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: '#ffcc33',
}),
}),
});
const clusterStyle = new Style({
text: new Text({
fill: new Fill({
color: '#fff',
}),
}),
})
const vectorLayer = new VectorLayer({
source: clusterSource,
style: function (feature) {
const size = feature.get('features').length;
if (size > 1) {
clusterStyle.getText().setText(size.toString());
return clusterStyle;
}
return noClusterStyle;
},
});
Now I want to use a WebGLVectorLayer
instead of a VectorLayer
, however, its style must be a FlatStyleLike
.
I tried the following:
import WebGLVectorLayer from 'ol/layer/WebGLVector';
const generateTextLabel = (featuresAmount) => {
return (
`<svg width="10" height="10" version="1.1" xmlns="http://www.w3.org/2000/svg">
<text x="0" y="18" fill="white" font-size="16">${featuresAmount}</text>
</svg>`
)
}
const flatLikeStyle = [
{
style: {
'shape-fill-color': 'black',
'shape-points': 4,
'shape-radius': 10,
}
},
{
filter: ['>', ['get', 'features'], 1],
style: {
'icon-src': 'data:image/svg+xml;utf8,' + generateTextLabel(0),
},
},
]
const webglVectorLayer = new WebGLVectorLayer({
source: clusterSource,
style: flatLikeStyle
})
But I don't know how to make the filter work with the size of features. I don't know how to pass the amount of features to the generateTextLabel()
function either.
To obtain the length of an array you would need to save that as a feature property when the cluster is created. Also you cannot have more than one value for icon-src
, you would need to create a sprite containing all possible values
const canvas = document.createElement('canvas');
const max = 200;
const size = 20;
canvas.width = max * size;
canvas.heigth = size;
const context = canvas.getContext('2d');
context.textAlign = 'center';
context.textBaseline = 'middle';
context.font = '10px sans-serif';
const match = [];
for (let i = 0; i < max; ++i) {
context.fillStyle = '#3399CC';
context.fillRect(i * size, 0, size, size);
context.fillStyle = 'white';
context.fillText(`${i + 1}`, i * size + size / 2, size / 2);
match.push(i, [i * size, 0]);
}
const sprite = canvas.toDataURL();
const source = new VectorSource({
features: features,
});
const clusterSource = new Cluster({
distance: parseInt(distanceInput.value, 10),
minDistance: parseInt(minDistanceInput.value, 10),
source: source,
});
clusterSource.on('addfeature', (e) => {
e.feature.set('size', e.feature.get('features').length);
});
const clusters = new WebGLVectorLayer({
source: clusterSource,
style: {
'icon-src': sprite,
'icon-offset': ['match', ['get', 'size'], ...match, [0, 0]],
'icon-size': [20, 20],
},
});
Working example https://stackblitz.com/edit/js-hfsqdrec?file=package.json,index.html,index.js