openlayers - How to show the amount of features if a cluster is being showed - Stack Overflow

admin2025-04-15  4

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=";>
      <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.

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.

Share Improve this question edited Feb 5 at 8:02 Basheer Jarrah 6264 silver badges16 bronze badges asked Feb 4 at 11:40 semihhersemihher 33 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

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

转载请注明原文地址:http://anycun.com/QandA/1744722902a86724.html