Skip to content

Commit ad7149d

Browse files
remarema
authored andcommitted
Add declusteredEvent to EntityCluster
Fixes #5760 by adding declusteredEvent that provides both clustered and declustered entities, plus new API methods for accessing clustering state. Maintains backward compatibility.
1 parent a158b2f commit ad7149d

File tree

2 files changed

+161
-2
lines changed

2 files changed

+161
-2
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
431431
- [Easy Mahaffey](https://github.com/easymaahffey)
432432
- [Pamela Augustine](https://github.com/pamelaAugustine)
433433
- [宋时旺](https://github.com/BlockCnFuture)
434+
- [Alexander Remer](https://github.com/Oko-Tester)

packages/engine/Source/DataSources/EntityCluster.js

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ function EntityCluster(options) {
6767

6868
this._clusterEvent = new Event();
6969

70+
this._declusteredEvent = new Event();
71+
this._allProcessedEntities = [];
72+
this._lastClusteredEntities = [];
73+
this._lastDeclusteredEntities = [];
74+
7075
/**
7176
* Determines if entities in this collection will be shown.
7277
*
@@ -127,6 +132,10 @@ function getBoundingBox(item, coord, pixelRange, entityCluster, result) {
127132
function addNonClusteredItem(item, entityCluster) {
128133
item.clusterShow = true;
129134

135+
if (defined(item.id)) {
136+
entityCluster._lastDeclusteredEntities.push(item.id);
137+
}
138+
130139
if (
131140
!defined(item._labelCollection) &&
132141
defined(item.id) &&
@@ -157,7 +166,16 @@ function addCluster(position, numPoints, ids, entityCluster) {
157166
cluster.point.position =
158167
position;
159168

169+
entityCluster._lastClusteredEntities =
170+
entityCluster._lastClusteredEntities.concat(ids);
171+
160172
entityCluster._clusterEvent.raiseEvent(ids, cluster);
173+
174+
entityCluster._declusteredEvent.raiseEvent({
175+
clustered: ids,
176+
declustered: entityCluster._lastDeclusteredEntities.slice(),
177+
cluster: cluster,
178+
});
161179
}
162180

163181
function hasLabelIndex(entityCluster, entityId) {
@@ -207,6 +225,10 @@ function getScreenSpacePositions(
207225
continue;
208226
}
209227

228+
if (defined(item.id)) {
229+
entityCluster._allProcessedEntities.push(item.id);
230+
}
231+
210232
points.push({
211233
index: i,
212234
collection: collection,
@@ -216,7 +238,7 @@ function getScreenSpacePositions(
216238
}
217239
}
218240

219-
const pointBoundinRectangleScratch = new BoundingRectangle();
241+
const pointBoundingRectangleScratch = new BoundingRectangle();
220242
const totalBoundingRectangleScratch = new BoundingRectangle();
221243
const neighborBoundingRectangleScratch = new BoundingRectangle();
222244

@@ -226,6 +248,10 @@ function createDeclutterCallback(entityCluster) {
226248
return;
227249
}
228250

251+
entityCluster._allProcessedEntities = [];
252+
entityCluster._lastClusteredEntities = [];
253+
entityCluster._lastDeclusteredEntities = [];
254+
229255
const scene = entityCluster._scene;
230256

231257
const labelCollection = entityCluster._labelCollection;
@@ -240,6 +266,11 @@ function createDeclutterCallback(entityCluster) {
240266
!entityCluster._clusterLabels &&
241267
!entityCluster._clusterPoints)
242268
) {
269+
entityCluster._declusteredEvent.raiseEvent({
270+
clustered: [],
271+
declustered: [],
272+
cluster: null,
273+
});
243274
return;
244275
}
245276

@@ -414,7 +445,7 @@ function createDeclutterCallback(entityCluster) {
414445
point.coord,
415446
pixelRange,
416447
entityCluster,
417-
pointBoundinRectangleScratch,
448+
pointBoundingRectangleScratch,
418449
);
419450
const totalBBox = BoundingRectangle.clone(
420451
bbox,
@@ -485,6 +516,18 @@ function createDeclutterCallback(entityCluster) {
485516
}
486517
}
487518

519+
if (
520+
entityCluster._lastClusteredEntities.length > 0 ||
521+
entityCluster._lastDeclusteredEntities.length > 0
522+
) {
523+
entityCluster._declusteredEvent.raiseEvent({
524+
clustered: entityCluster._lastClusteredEntities.slice(),
525+
declustered: entityCluster._lastDeclusteredEntities.slice(),
526+
cluster: null,
527+
allProcessed: entityCluster._allProcessedEntities.slice(),
528+
});
529+
}
530+
488531
if (clusteredLabelCollection.length === 0) {
489532
clusteredLabelCollection.destroy();
490533
entityCluster._clusterLabelCollection = undefined;
@@ -567,6 +610,16 @@ Object.defineProperties(EntityCluster.prototype, {
567610
return this._clusterEvent;
568611
},
569612
},
613+
/**
614+
* Gets the event that will be raised when clustering is processed, including both clustered and declustered entities.
615+
* @memberof EntityCluster.prototype
616+
* @type {Event}
617+
*/
618+
declusteredEvent: {
619+
get: function () {
620+
return this._declusteredEvent;
621+
},
622+
},
570623
/**
571624
* Gets or sets whether clustering billboard entities is enabled.
572625
* @memberof EntityCluster.prototype
@@ -852,6 +905,35 @@ function updateEnable(entityCluster) {
852905
return;
853906
}
854907

908+
const allVisibleEntities = [];
909+
910+
if (defined(entityCluster._labelCollection)) {
911+
for (let i = 0; i < entityCluster._labelCollection.length; i++) {
912+
const label = entityCluster._labelCollection.get(i);
913+
if (defined(label.id) && label.show) {
914+
allVisibleEntities.push(label.id);
915+
}
916+
}
917+
}
918+
919+
if (defined(entityCluster._billboardCollection)) {
920+
for (let i = 0; i < entityCluster._billboardCollection.length; i++) {
921+
const billboard = entityCluster._billboardCollection.get(i);
922+
if (defined(billboard.id) && billboard.show) {
923+
allVisibleEntities.push(billboard.id);
924+
}
925+
}
926+
}
927+
928+
if (defined(entityCluster._pointCollection)) {
929+
for (let i = 0; i < entityCluster._pointCollection.length; i++) {
930+
const point = entityCluster._pointCollection.get(i);
931+
if (defined(point.id) && point.show) {
932+
allVisibleEntities.push(point.id);
933+
}
934+
}
935+
}
936+
855937
if (defined(entityCluster._clusterLabelCollection)) {
856938
entityCluster._clusterLabelCollection.destroy();
857939
}
@@ -869,6 +951,32 @@ function updateEnable(entityCluster) {
869951
disableCollectionClustering(entityCluster._labelCollection);
870952
disableCollectionClustering(entityCluster._billboardCollection);
871953
disableCollectionClustering(entityCluster._pointCollection);
954+
955+
if (allVisibleEntities.length > 0) {
956+
const uniqueEntities = [...new Set(allVisibleEntities)];
957+
958+
entityCluster._declusteredEvent.raiseEvent({
959+
clustered: [],
960+
declustered: uniqueEntities,
961+
cluster: null,
962+
allProcessed: uniqueEntities,
963+
});
964+
965+
entityCluster._lastClusteredEntities = [];
966+
entityCluster._lastDeclusteredEntities = uniqueEntities.slice();
967+
entityCluster._allProcessedEntities = uniqueEntities.slice();
968+
} else {
969+
entityCluster._declusteredEvent.raiseEvent({
970+
clustered: [],
971+
declustered: [],
972+
cluster: null,
973+
allProcessed: [],
974+
});
975+
976+
entityCluster._lastClusteredEntities = [];
977+
entityCluster._lastDeclusteredEntities = [];
978+
entityCluster._allProcessedEntities = [];
979+
}
872980
}
873981

874982
/**
@@ -998,9 +1106,37 @@ EntityCluster.prototype.destroy = function () {
9981106
this._pixelRangeDirty = false;
9991107
this._minimumClusterSizeDirty = false;
10001108

1109+
this._allProcessedEntities = [];
1110+
this._lastClusteredEntities = [];
1111+
this._lastDeclusteredEntities = [];
1112+
10011113
return undefined;
10021114
};
10031115

1116+
/**
1117+
* Returns the last set of clustered entities from the most recent clustering operation.
1118+
* @returns {Entity[]} Array of entities that were clustered
1119+
*/
1120+
EntityCluster.prototype.getLastClusteredEntities = function () {
1121+
return this._lastClusteredEntities.slice();
1122+
};
1123+
1124+
/**
1125+
* Returns the last set of declustered entities from the most recent clustering operation.
1126+
* @returns {Entity[]} Array of entities that were not clustered
1127+
*/
1128+
EntityCluster.prototype.getLastDeclusteredEntities = function () {
1129+
return this._lastDeclusteredEntities.slice();
1130+
};
1131+
1132+
/**
1133+
* Returns all entities that were processed in the most recent clustering operation.
1134+
* @returns {Entity[]} Array of all processed entities
1135+
*/
1136+
EntityCluster.prototype.getAllProcessedEntities = function () {
1137+
return this._allProcessedEntities.slice();
1138+
};
1139+
10041140
/**
10051141
* A event listener function used to style clusters.
10061142
* @callback EntityCluster.newClusterCallback
@@ -1019,4 +1155,26 @@ EntityCluster.prototype.destroy = function () {
10191155
* cluster.label.text = entities.length.toLocaleString();
10201156
* });
10211157
*/
1158+
1159+
/**
1160+
* A event listener function for enhanced clustering information.
1161+
* @callback EntityCluster.declusteredCallback
1162+
*
1163+
* @param {object} clusteringData An object containing clustering information.
1164+
* @param {Entity[]} clusteringData.clustered An array of entities that were clustered.
1165+
* @param {Entity[]} clusteringData.declustered An array of entities that were not clustered.
1166+
* @param {object|null} clusteringData.cluster The cluster object (if this event is for a specific cluster) or null for summary events.
1167+
* @param {Entity[]} [clusteringData.allProcessed] An array of all entities processed (only in summary events).
1168+
*
1169+
* @example
1170+
* // Using the enhanced declusteredEvent to access both clustered and declustered entities
1171+
* dataSource.clustering.declusteredEvent.addEventListener(function(data) {
1172+
* console.log('Clustered entities:', data.clustered.length);
1173+
* console.log('Declustered entities:', data.declustered.length);
1174+
* if (data.allProcessed) {
1175+
* console.log('Total processed entities:', data.allProcessed.length);
1176+
* }
1177+
* });
1178+
*/
1179+
10221180
export default EntityCluster;

0 commit comments

Comments
 (0)