bruce-cesium 6.2.0 → 6.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11511,41 +11511,172 @@
11511
11511
  return newStates;
11512
11512
  }
11513
11513
  /**
11514
- * Applies a set of new states to override the existing ones.
11515
- * This can be a costly operation as it will update all visuals.
11514
+ * Calculates the difference between current states and new states.
11515
+ * Returns what needs to be added, removed, and updated.
11516
+ */
11517
+ calculateStateDifference(newStates) {
11518
+ const toAdd = [];
11519
+ const toRemove = [];
11520
+ const toUpdate = [];
11521
+ const affectedEntityIds = new Set();
11522
+ // State map for quick lookups.
11523
+ const newStatesMap = new Map();
11524
+ for (const state of newStates) {
11525
+ if (!state.entityId || isBlankState(state)) {
11526
+ continue;
11527
+ }
11528
+ const key = `${state.entityId}::${state.menuItemId || NO_MENU_ITEM_KEY}`;
11529
+ newStatesMap.set(key, state);
11530
+ }
11531
+ // Track existing states.
11532
+ const existingKeys = new Set();
11533
+ // Check existing states to see if they need removal or updating.
11534
+ this.ForEachState((existingState) => {
11535
+ const key = `${existingState.entityId}::${existingState.menuItemId || NO_MENU_ITEM_KEY}`;
11536
+ existingKeys.add(key);
11537
+ const newState = newStatesMap.get(key);
11538
+ // State exists in current but not in new.
11539
+ if (!newState) {
11540
+ toRemove.push({ ...existingState });
11541
+ affectedEntityIds.add(existingState.entityId);
11542
+ }
11543
+ // State exists in both.
11544
+ // See if changed.
11545
+ else {
11546
+ if (this.isStateDifferent(existingState, newState)) {
11547
+ toUpdate.push({ ...newState });
11548
+ affectedEntityIds.add(existingState.entityId);
11549
+ }
11550
+ }
11551
+ });
11552
+ // Check for new states that don't exist currently.
11553
+ for (const [key, newState] of newStatesMap) {
11554
+ if (!existingKeys.has(key)) {
11555
+ toAdd.push({ ...newState });
11556
+ affectedEntityIds.add(newState.entityId);
11557
+ }
11558
+ }
11559
+ return { toAdd, toRemove, toUpdate, affectedEntityIds };
11560
+ }
11561
+ /**
11562
+ * Compares two states to determine if they're different.
11563
+ * Only compares meaningful properties (not entityId/menuItemId).
11564
+ */
11565
+ isStateDifferent(state1, state2) {
11566
+ const keys1 = Object.keys(state1).filter(k => k !== "entityId" && k !== "menuItemId");
11567
+ const keys2 = Object.keys(state2).filter(k => k !== "entityId" && k !== "menuItemId");
11568
+ // Different number of properties.
11569
+ if (keys1.length !== keys2.length) {
11570
+ return true;
11571
+ }
11572
+ // Check if any property values differ.
11573
+ for (const key of keys1) {
11574
+ if (state1[key] !== state2[key]) {
11575
+ return true;
11576
+ }
11577
+ }
11578
+ return false;
11579
+ }
11580
+ /**
11581
+ * Applies a set of new states to override the existing ones using differential updates.
11582
+ * This is more efficient than clearing and re-applying all states.
11516
11583
  * @param states
11517
11584
  */
11518
11585
  OverrideStates(states) {
11519
- // Clear current states.
11520
- this.ClearOpacity();
11521
- this.ClearLabelled();
11522
- this.ClearSelected();
11523
- this.ClearHighlighted();
11524
- this.ClearIsolated();
11525
- this.ClearHidden();
11526
- this.states = {};
11527
- let newStates = {};
11528
- for (let i = 0; i < states.length; i++) {
11529
- const state = states[i];
11530
- if (!state.menuItemId && state.hasOwnProperty("menuItemId")) {
11531
- delete state.menuItemId;
11586
+ // Calculate what needs to change.
11587
+ const diff = this.calculateStateDifference(states);
11588
+ // If nothing changed, exit early.
11589
+ if (diff.toAdd.length === 0 && diff.toRemove.length === 0 && diff.toUpdate.length === 0) {
11590
+ return;
11591
+ }
11592
+ // Track which visual properties need refreshing per entity.
11593
+ const refreshMap = new Map();
11594
+ const updateRefreshForEntity = (entityId, props) => {
11595
+ const existing = refreshMap.get(entityId) || {};
11596
+ refreshMap.set(entityId, {
11597
+ highlighted: existing.highlighted || props.highlighted || false,
11598
+ selected: existing.selected || props.selected || false,
11599
+ opacity: existing.opacity || props.opacity || false
11600
+ });
11601
+ };
11602
+ // Process removals.
11603
+ for (const state of diff.toRemove) {
11604
+ // Create a state with inverted/cleared values.
11605
+ const clearState = {
11606
+ entityId: state.entityId,
11607
+ menuItemId: state.menuItemId
11608
+ };
11609
+ // For each property that exists, set it to null to clear it.
11610
+ // This will cause setStateValues to delete the property.
11611
+ if (state.highlighted != null) {
11612
+ clearState.highlighted = null;
11613
+ updateRefreshForEntity(state.entityId, {
11614
+ highlighted: true
11615
+ });
11532
11616
  }
11533
- if (!state.entityId) {
11534
- continue;
11617
+ if (state.selected != null) {
11618
+ clearState.selected = null;
11619
+ updateRefreshForEntity(state.entityId, {
11620
+ selected: true
11621
+ });
11535
11622
  }
11536
- if (isBlankState(state)) {
11537
- continue;
11623
+ if (state.opacity != null) {
11624
+ clearState.opacity = null;
11625
+ updateRefreshForEntity(state.entityId, {
11626
+ opacity: true
11627
+ });
11538
11628
  }
11539
- if (!newStates[state.entityId]) {
11540
- newStates[state.entityId] = {};
11629
+ if (state.labelled != null) {
11630
+ clearState.labelled = null;
11631
+ updateRefreshForEntity(state.entityId, {});
11541
11632
  }
11542
- newStates[state.entityId][state.menuItemId ? state.menuItemId : NO_MENU_ITEM_KEY] = {
11543
- ...state
11544
- };
11633
+ if (state.hidden != null) {
11634
+ clearState.hidden = null;
11635
+ updateRefreshForEntity(state.entityId, {});
11636
+ }
11637
+ if (state.isolated != null) {
11638
+ clearState.isolated = null;
11639
+ updateRefreshForEntity(state.entityId, {});
11640
+ }
11641
+ this.setStateValues(clearState);
11545
11642
  }
11546
- this.states = newStates;
11547
- // Reflect the rest of the changes.
11548
- this.updateAllEntities();
11643
+ // Process additions and updates.
11644
+ const statesToSet = [...diff.toAdd, ...diff.toUpdate];
11645
+ for (const state of statesToSet) {
11646
+ // Determine what needs visual refresh based on what's changing.
11647
+ if (state.hasOwnProperty("highlighted")) {
11648
+ updateRefreshForEntity(state.entityId, {
11649
+ highlighted: true
11650
+ });
11651
+ }
11652
+ if (state.hasOwnProperty("selected")) {
11653
+ updateRefreshForEntity(state.entityId, {
11654
+ selected: true
11655
+ });
11656
+ }
11657
+ if (state.hasOwnProperty("opacity")) {
11658
+ updateRefreshForEntity(state.entityId, {
11659
+ opacity: true
11660
+ });
11661
+ }
11662
+ if (state.hasOwnProperty("labelled")) {
11663
+ updateRefreshForEntity(state.entityId, {});
11664
+ }
11665
+ if (state.hasOwnProperty("hidden") || state.hasOwnProperty("isolated")) {
11666
+ updateRefreshForEntity(state.entityId, {});
11667
+ }
11668
+ this.setStateValues(state);
11669
+ }
11670
+ // Queue updates for all affected entities.
11671
+ // TODO: if a massive list we should async batch this.
11672
+ for (const entityId of diff.affectedEntityIds) {
11673
+ const refresh = refreshMap.get(entityId);
11674
+ this.queueUpdate({
11675
+ entityId: entityId,
11676
+ refresh: refresh || true
11677
+ });
11678
+ }
11679
+ this.viewer.scene.requestRender();
11549
11680
  }
11550
11681
  /**
11551
11682
  * Returns all states with the first detected Menu Item ID settings included.
@@ -11993,7 +12124,7 @@
11993
12124
  }
11994
12125
  SetIsolated(params) {
11995
12126
  var _a;
11996
- const { entityIds, isolated: isolate, requestRender, menuItemId, source } = params;
12127
+ const { entityIds, isolated: isolate, requestRender, menuItemId, source, doUpdate } = params;
11997
12128
  for (let i = 0; i < entityIds.length; i++) {
11998
12129
  const entityId = entityIds[i];
11999
12130
  this.setStateValues({
@@ -12014,12 +12145,14 @@
12014
12145
  (_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.Trigger(update);
12015
12146
  }
12016
12147
  }
12017
- this.updateAllEntities({
12018
- requestRender: false,
12019
- refresh: isolate
12020
- });
12021
- if (requestRender != false) {
12022
- this.viewer.scene.requestRender();
12148
+ if (doUpdate !== false) {
12149
+ this.updateAllEntities({
12150
+ requestRender: false,
12151
+ refresh: isolate
12152
+ });
12153
+ if (requestRender != false) {
12154
+ this.viewer.scene.requestRender();
12155
+ }
12023
12156
  }
12024
12157
  }
12025
12158
  GetIsIsolated(params) {
@@ -12055,7 +12188,7 @@
12055
12188
  }
12056
12189
  delete state.isolated;
12057
12190
  });
12058
- if (changed) {
12191
+ if (changed && params.doUpdate !== false) {
12059
12192
  this.updateAllEntities({
12060
12193
  requestRender: params === null || params === void 0 ? void 0 : params.requestRender,
12061
12194
  refresh: true
@@ -12109,7 +12242,7 @@
12109
12242
  }
12110
12243
  delete state.hidden;
12111
12244
  });
12112
- if (changed) {
12245
+ if (changed && params.doUpdate !== false) {
12113
12246
  this.updateAllEntities({
12114
12247
  requestRender: params === null || params === void 0 ? void 0 : params.requestRender,
12115
12248
  refresh: true
@@ -12503,16 +12636,27 @@
12503
12636
  }
12504
12637
  }
12505
12638
  }
12506
- updateAllEntities(params) {
12507
- for (const entityId in this.rego) {
12508
- const regos = this.rego[entityId];
12509
- if (regos && regos.length) {
12510
- this.queueUpdate({
12511
- entityId: entityId,
12512
- refresh: (params === null || params === void 0 ? void 0 : params.refresh) == null ? true : params.refresh
12513
- });
12639
+ async updateAllEntities(params) {
12640
+ const ids = Object.keys(this.rego);
12641
+ const interval = setInterval(() => {
12642
+ const batch = ids.splice(0, 3000);
12643
+ if (!batch.length || (params.isCancelled && params.isCancelled())) {
12644
+ clearInterval(interval);
12645
+ return;
12514
12646
  }
12515
- }
12647
+ for (const entityId of batch) {
12648
+ const regos = this.rego[entityId];
12649
+ if (regos && regos.length) {
12650
+ this.queueUpdate({
12651
+ entityId: entityId,
12652
+ refresh: (params === null || params === void 0 ? void 0 : params.refresh) == null ? true : params.refresh
12653
+ });
12654
+ }
12655
+ }
12656
+ if ((params === null || params === void 0 ? void 0 : params.requestRender) !== false) {
12657
+ this.viewer.scene.requestRender();
12658
+ }
12659
+ }, 10);
12516
12660
  }
12517
12661
  /**
12518
12662
  * Sets opacity for given set of entities.
@@ -18907,28 +19051,36 @@
18907
19051
  }
18908
19052
  }
18909
19053
  }
18910
- // Latest path.
18911
19054
  if (!rego.entityId) {
19055
+ // Latest path.
18912
19056
  const entityIdProp = this.featurePropCache.get("entityId");
18913
19057
  if (entityIdProp) {
18914
19058
  rego.entityId = feature.getProperty(entityIdProp);
18915
19059
  }
18916
- }
18917
- // Super legacy.
18918
- if (!rego.entityId) {
18919
- const brucePathProp = this.featurePropCache.get("brucePath");
18920
- if (brucePathProp) {
18921
- const pathStr = feature.getProperty(brucePathProp);
18922
- if (pathStr) {
18923
- let path = pathStr.split("|");
18924
- let entityTypeId = this.getEntityTypeByPath(path);
18925
- rego.entityTypeId = entityTypeId;
18926
- rego.entityId = path[path.length - 1];
19060
+ // Super legacy.
19061
+ if (!rego.entityId) {
19062
+ const brucePathProp = this.featurePropCache.get("brucePath");
19063
+ if (brucePathProp) {
19064
+ const pathStr = feature.getProperty(brucePathProp);
19065
+ if (pathStr) {
19066
+ let path = pathStr.split("|");
19067
+ let entityTypeId = this.getEntityTypeByPath(path);
19068
+ rego.entityTypeId = entityTypeId;
19069
+ rego.entityId = path[path.length - 1];
19070
+ }
18927
19071
  }
18928
19072
  }
18929
- }
18930
- if (!rego.entityId) {
18931
- return null;
19073
+ if (!rego.entityId) {
19074
+ return null;
19075
+ }
19076
+ const meta = this.getMetaByEntityId(rego.entityId);
19077
+ if (meta) {
19078
+ rego.entityTypeId = meta.typeId;
19079
+ rego.name = meta.name;
19080
+ rego.parentId = meta.parentId;
19081
+ // Might be a different ID due to collapsed parents.
19082
+ rego.entityId = meta.entityId;
19083
+ }
18932
19084
  }
18933
19085
  // Optional menu item restriction.
18934
19086
  // Allows only showing certain entities from a tileset.
@@ -18993,6 +19145,15 @@
18993
19145
  });
18994
19146
  return rego;
18995
19147
  }
19148
+ getMetaByEntityId(entityId) {
19149
+ if (this.treeNodeByEntityId == null) {
19150
+ if (!this.modelTree) {
19151
+ return null;
19152
+ }
19153
+ this.buildModelTreeNodes(this.modelTree);
19154
+ }
19155
+ return this.treeNodeByEntityId[entityId] || null;
19156
+ }
18996
19157
  getMetaByGeomId(geomId) {
18997
19158
  if (this.treeNodeByGeomId == null) {
18998
19159
  if (!this.modelTree) {
@@ -34200,7 +34361,7 @@
34200
34361
  }
34201
34362
  }
34202
34363
 
34203
- const VERSION = "6.2.0";
34364
+ const VERSION = "6.2.2";
34204
34365
 
34205
34366
  exports.VERSION = VERSION;
34206
34367
  exports.isOutlineChanged = isOutlineChanged;