diff --git a/src/ol/source/Cluster.js b/src/ol/source/Cluster.js index 5c19ca3ab6..45276a733f 100644 --- a/src/ol/source/Cluster.js +++ b/src/ol/source/Cluster.js @@ -40,6 +40,18 @@ import {getUid} from '../util.js'; * ``` * See {@link module:ol/geom/Polygon~Polygon#getInteriorPoint} for a way to get a cluster * calculation point for polygons. + * @property {function(Point, Array):Feature} [createClusterFeature] + * Function that takes the cluster's center {@link module:ol/geom/Point} and an array + * of {@link module:ol/Feature} included in this cluster. Must return a + * {@link module:ol/Feature} that will be used to render. Default implementation is: + * ```js + * function(point, features) { + * return new Feature({ + * geometry: point, + * features: features + * }); + * } + * ``` * @property {VectorSource} [source] Source. * @property {boolean} [wrapX=true] Whether to wrap the world horizontally. */ @@ -108,6 +120,12 @@ class Cluster extends VectorSource { return geometry; }; + /** + * @type {function(Point, Array):Feature} + * @protected + */ + this.createClusterFeature = options.createClusterFeature; + /** * @type {VectorSource} * @protected @@ -294,9 +312,14 @@ class Cluster extends VectorSource { centroid[0] * (1 - ratio) + searchCenter[0] * ratio, centroid[1] * (1 - ratio) + searchCenter[1] * ratio, ]); - const cluster = new Feature(geometry); - cluster.set('features', features, true); - return cluster; + if (this.createClusterFeature) { + return this.createClusterFeature(geometry, features); + } else { + return new Feature({ + geometry, + features, + }); + } } } diff --git a/test/browser/spec/ol/source/cluster.test.js b/test/browser/spec/ol/source/cluster.test.js index 3b11e384eb..5487e4be7d 100644 --- a/test/browser/spec/ol/source/cluster.test.js +++ b/test/browser/spec/ol/source/cluster.test.js @@ -75,6 +75,30 @@ describe('ol.source.Cluster', function () { expect(source.getFeatures().length).to.be(1); expect(source.getFeatures()[0].get('features').length).to.be(2); }); + it('custom cluster feature with additional fields', function () { + const feature1 = new Feature(new Point([0, 0])); + const feature2 = new Feature(new Point([0, 0])); + feature1.set('value', 1); + feature2.set('value', 2); + const source = new Cluster({ + source: new VectorSource({ + features: [feature1, feature2], + }), + createClusterFeature: function (clusterPoint, features) { + let sum = 0; + for (const ft of features) { + sum += ft.get('value'); + } + return new Feature({ + geometry: clusterPoint, + sum: sum, + }); + }, + }); + source.loadFeatures(extent, 1, projection); + expect(source.getFeatures().length).to.be(1); + expect(source.getFeatures()[0].get('sum')).to.be(3); + }); }); describe('#setDistance', function () {