From 9fd25dddbfab2a9ea163e8534f6343f8ae09b4a3 Mon Sep 17 00:00:00 2001 From: jkonieczny Date: Thu, 8 Jul 2021 20:06:18 +0200 Subject: [PATCH 1/3] allow hydrating clustered features --- src/ol/source/Cluster.js | 11 +++++++++++ test/browser/spec/ol/source/cluster.test.js | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/ol/source/Cluster.js b/src/ol/source/Cluster.js index 5c19ca3ab6..11b6affd64 100644 --- a/src/ol/source/Cluster.js +++ b/src/ol/source/Cluster.js @@ -38,6 +38,8 @@ import {getUid} from '../util.js'; * return feature.getGeometry(); * } * ``` + * @property {function(Feature, Array):any} [hydrate] Function called after creating + * cluster feature * See {@link module:ol/geom/Polygon~Polygon#getInteriorPoint} for a way to get a cluster * calculation point for polygons. * @property {VectorSource} [source] Source. @@ -108,6 +110,12 @@ class Cluster extends VectorSource { return geometry; }; + /** + * @type {function(Feature, Array):any} + * @protected + */ + this.hydrate = options.hydrate; + /** * @type {VectorSource} * @protected @@ -295,6 +303,9 @@ class Cluster extends VectorSource { centroid[1] * (1 - ratio) + searchCenter[1] * ratio, ]); const cluster = new Feature(geometry); + if (this.hydrate) { + this.hydrate(cluster, features); + } cluster.set('features', features, true); return cluster; } diff --git a/test/browser/spec/ol/source/cluster.test.js b/test/browser/spec/ol/source/cluster.test.js index 3b11e384eb..655381b802 100644 --- a/test/browser/spec/ol/source/cluster.test.js +++ b/test/browser/spec/ol/source/cluster.test.js @@ -75,6 +75,23 @@ describe('ol.source.Cluster', function () { expect(source.getFeatures().length).to.be(1); expect(source.getFeatures()[0].get('features').length).to.be(2); }); + it('hydrates 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], + }), + hydrate: function (clusterFeature, features) { + clusterFeature.set('sum', 3); + }, + }); + source.loadFeatures(extent, 1, projection); + expect(source.getFeatures().length).to.be(1); + expect(source.getFeatures()[0].get('sum')).to.be(3); + }); }); describe('#setDistance', function () { From a8f7d955af64090c13a55eba20cf1f955ffca4c7 Mon Sep 17 00:00:00 2001 From: jkonieczny Date: Mon, 12 Jul 2021 19:24:23 +0200 Subject: [PATCH 2/3] rename to createClusterFeature --- src/ol/source/Cluster.js | 52 +++++++++++++++++---- test/browser/spec/ol/source/cluster.test.js | 33 +++++++++++-- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/ol/source/Cluster.js b/src/ol/source/Cluster.js index 11b6affd64..33ce42063a 100644 --- a/src/ol/source/Cluster.js +++ b/src/ol/source/Cluster.js @@ -38,10 +38,20 @@ import {getUid} from '../util.js'; * return feature.getGeometry(); * } * ``` - * @property {function(Feature, Array):any} [hydrate] Function called after creating - * cluster feature * 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 cluster's ceter {@link module:ol/geom/Point} and array + * of {@link module:ol/Feature} included in this cluster, must return + * {@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. */ @@ -111,10 +121,10 @@ class Cluster extends VectorSource { }; /** - * @type {function(Feature, Array):any} + * @type {function(Point, Array):Feature} * @protected */ - this.hydrate = options.hydrate; + this.createClusterFeature = options.createClusterFeature; /** * @type {VectorSource} @@ -188,6 +198,28 @@ class Cluster extends VectorSource { this.updateDistance(this.distance, minDistance); } + /** + * Current function used to create cluster features + * @return {function(Point, Array):Feature | undefined} cluster creation function + * @api + */ + getCreateClusterFeature() { + return this.createClusterFeature; + } + + /** + * Set function used to create cluster features + * @param {function(Point, Array):Feature | undefined} createClusterFeature creation function + * @api + */ + setCreateClusterFeature(createClusterFeature) { + const changed = this.createClusterFeature != createClusterFeature; + this.createClusterFeature = createClusterFeature; + if (changed) { + this.refresh(); + } + } + /** * The configured minimum distance between clusters. * @return {number} The minimum distance in pixels. @@ -302,12 +334,14 @@ class Cluster extends VectorSource { centroid[0] * (1 - ratio) + searchCenter[0] * ratio, centroid[1] * (1 - ratio) + searchCenter[1] * ratio, ]); - const cluster = new Feature(geometry); - if (this.hydrate) { - this.hydrate(cluster, features); + if (this.createClusterFeature) { + return this.createClusterFeature(geometry, features); + } else { + return new Feature({ + geometry, + features, + }); } - cluster.set('features', features, true); - return cluster; } } diff --git a/test/browser/spec/ol/source/cluster.test.js b/test/browser/spec/ol/source/cluster.test.js index 655381b802..961962f2cf 100644 --- a/test/browser/spec/ol/source/cluster.test.js +++ b/test/browser/spec/ol/source/cluster.test.js @@ -75,7 +75,7 @@ describe('ol.source.Cluster', function () { expect(source.getFeatures().length).to.be(1); expect(source.getFeatures()[0].get('features').length).to.be(2); }); - it('hydrates cluster feature with additional fields', function () { + 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); @@ -84,14 +84,41 @@ describe('ol.source.Cluster', function () { source: new VectorSource({ features: [feature1, feature2], }), - hydrate: function (clusterFeature, features) { - clusterFeature.set('sum', 3); + 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); }); + it('reacts setCreateClusterFeature', function () { + const feature1 = new Feature(new Point([0, 0])); + const feature2 = new Feature(new Point([0, 0])); + const source = new Cluster({ + source: new VectorSource({ + features: [feature1, feature2], + }), + }); + source.loadFeatures(extent, 1, projection); + expect(source.getFeatures().length).to.be(1); + expect(source.getFeatures()[0].get('sum')).to.be(undefined); + source.setCreateClusterFeature(function (clusterPoint, features) { + return new Feature({ + geometry: clusterPoint, + sum: features.length, + }); + }); + expect(source.getFeatures().length).to.be(1); + expect(source.getFeatures()[0].get('sum')).to.be(2); + }); }); describe('#setDistance', function () { From e1b161bbbe85744f52283f812864d38765dff1d3 Mon Sep 17 00:00:00 2001 From: jkonieczny Date: Thu, 15 Jul 2021 09:06:13 +0200 Subject: [PATCH 3/3] remove setter/getter --- src/ol/source/Cluster.js | 26 ++------------------- test/browser/spec/ol/source/cluster.test.js | 20 ---------------- 2 files changed, 2 insertions(+), 44 deletions(-) diff --git a/src/ol/source/Cluster.js b/src/ol/source/Cluster.js index 33ce42063a..45276a733f 100644 --- a/src/ol/source/Cluster.js +++ b/src/ol/source/Cluster.js @@ -41,8 +41,8 @@ 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 cluster's ceter {@link module:ol/geom/Point} and array - * of {@link module:ol/Feature} included in this cluster, must return + * 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) { @@ -198,28 +198,6 @@ class Cluster extends VectorSource { this.updateDistance(this.distance, minDistance); } - /** - * Current function used to create cluster features - * @return {function(Point, Array):Feature | undefined} cluster creation function - * @api - */ - getCreateClusterFeature() { - return this.createClusterFeature; - } - - /** - * Set function used to create cluster features - * @param {function(Point, Array):Feature | undefined} createClusterFeature creation function - * @api - */ - setCreateClusterFeature(createClusterFeature) { - const changed = this.createClusterFeature != createClusterFeature; - this.createClusterFeature = createClusterFeature; - if (changed) { - this.refresh(); - } - } - /** * The configured minimum distance between clusters. * @return {number} The minimum distance in pixels. diff --git a/test/browser/spec/ol/source/cluster.test.js b/test/browser/spec/ol/source/cluster.test.js index 961962f2cf..5487e4be7d 100644 --- a/test/browser/spec/ol/source/cluster.test.js +++ b/test/browser/spec/ol/source/cluster.test.js @@ -99,26 +99,6 @@ describe('ol.source.Cluster', function () { expect(source.getFeatures().length).to.be(1); expect(source.getFeatures()[0].get('sum')).to.be(3); }); - it('reacts setCreateClusterFeature', function () { - const feature1 = new Feature(new Point([0, 0])); - const feature2 = new Feature(new Point([0, 0])); - const source = new Cluster({ - source: new VectorSource({ - features: [feature1, feature2], - }), - }); - source.loadFeatures(extent, 1, projection); - expect(source.getFeatures().length).to.be(1); - expect(source.getFeatures()[0].get('sum')).to.be(undefined); - source.setCreateClusterFeature(function (clusterPoint, features) { - return new Feature({ - geometry: clusterPoint, - sum: features.length, - }); - }); - expect(source.getFeatures().length).to.be(1); - expect(source.getFeatures()[0].get('sum')).to.be(2); - }); }); describe('#setDistance', function () {