Keep cable pick info and the prewarm flag off Cesium objects

Submarine cables wrote each pick's info both to a per-load WeakMap and to a
__gevTeleGeography expando, always together; one cablePicks store replaces
both and resolves the same objects. The voice view-target prewarm marks its
viewer in a WeakSet instead of a __gevViewTargetPrewarmInstalled property.
This commit is contained in:
Sameh Khamis committed 2026-11-03 10:01:12 -08:00
1 parent f86dcc9179
commit a40e5c334c
9 files changed
+31 -23

No files matched your search

+4
View File
@@ -2045,6 +2045,8 @@
"src/layers/submarineCables/index.js", "src/layers/submarineCables/index.js",
"src/layers/submarineCables/ingestion.js", "src/layers/submarineCables/ingestion.js",
"src/layers/submarineCables/interaction.js", "src/layers/submarineCables/interaction.js",
"src/layers/submarineCables/pickState.js",
"src/data/entityRecords.js",
"src/layers/submarineCables/lifecycle.js", "src/layers/submarineCables/lifecycle.js",
"src/layers/submarineCables/overlay.js", "src/layers/submarineCables/overlay.js",
"src/layers/submarineCables/policy.js", "src/layers/submarineCables/policy.js",
@@ -2622,6 +2624,7 @@
"src/layers/submarineCables/index.js", "src/layers/submarineCables/index.js",
"src/layers/submarineCables/ingestion.js", "src/layers/submarineCables/ingestion.js",
"src/layers/submarineCables/interaction.js", "src/layers/submarineCables/interaction.js",
"src/layers/submarineCables/pickState.js",
"src/layers/submarineCables/lifecycle.js", "src/layers/submarineCables/lifecycle.js",
"src/layers/submarineCables/overlay.js", "src/layers/submarineCables/overlay.js",
"src/layers/submarineCables/policy.js", "src/layers/submarineCables/policy.js",
@@ -3529,6 +3532,7 @@
"src/layers/submarineCables/index.js", "src/layers/submarineCables/index.js",
"src/layers/submarineCables/ingestion.js", "src/layers/submarineCables/ingestion.js",
"src/layers/submarineCables/interaction.js", "src/layers/submarineCables/interaction.js",
"src/layers/submarineCables/pickState.js",
"src/layers/submarineCables/lifecycle.js", "src/layers/submarineCables/lifecycle.js",
"src/layers/submarineCables/overlay.js", "src/layers/submarineCables/overlay.js",
"src/layers/submarineCables/policy.js", "src/layers/submarineCables/policy.js",
@@ -22,6 +22,7 @@ import {
selectCableReferenceLabelWinners, selectCableReferenceLabelWinners,
updateCableReferenceStem, updateCableReferenceStem,
} from './telegeographySubmarineCables.js'; } from './telegeographySubmarineCables.js';
import { cablePicks } from '../layers/submarineCables/pickState.js';
test('cable reference winners remain nearest-first and hard-capped', () => { test('cable reference winners remain nearest-first and hard-capped', () => {
const records = Array.from({ length: 300 }, (_, index) => ({ const records = Array.from({ length: 300 }, (_, index) => ({
@@ -1840,7 +1841,7 @@ test('multipart association accepts frozen provider collections without modifyin
for (const dataSource of env.dataSources.slice(0, 2)) { for (const dataSource of env.dataSources.slice(0, 2)) {
assert.deepEqual( assert.deepEqual(
dataSource.entities.values.map( dataSource.entities.values.map(
(entity) => entity.__gevTeleGeography?.label, (entity) => cablePicks.read(entity)?.info.label,
), ),
['Alpha cable', 'Alpha cable', 'Alpha cable', 'Beta cable'], ['Alpha cable', 'Alpha cable', 'Alpha cable', 'Beta cable'],
); );
@@ -1866,7 +1867,7 @@ test('multipart cables retain their own styling, picking and culling on every se
assert.equal(entities.length, 4); assert.equal(entities.length, 4);
for (const [index, entity] of entities.entries()) { for (const [index, entity] of entities.entries()) {
const feature = features[index < 3 ? 0 : 1]; const feature = features[index < 3 ? 0 : 1];
const info = entity.__gevTeleGeography; const info = cablePicks.read(entity)?.info;
assert.equal(info?.label, feature.properties.name, entity.id); assert.equal(info?.label, feature.properties.name, entity.id);
assert.deepEqual(info.reference, { assert.deepEqual(info.reference, {
lon: feature.properties.coordinates[0], lon: feature.properties.coordinates[0],
@@ -1922,7 +1923,7 @@ test('multipart association supports missing and repeated IDs without guessing C
['alpha', 'alpha_2', 'alpha_3', 'alpha_2_2', 'cable-2', 'alpha_4'], ['alpha', 'alpha_2', 'alpha_3', 'alpha_2_2', 'cable-2', 'alpha_4'],
); );
assert.deepEqual( assert.deepEqual(
entities.map((entity) => entity.__gevTeleGeography?.label), entities.map((entity) => cablePicks.read(entity)?.info.label),
[ [
'Alpha cable', 'Alpha cable',
'Alpha cable', 'Alpha cable',
@@ -1934,7 +1935,7 @@ test('multipart association supports missing and repeated IDs without guessing C
); );
assert.deepEqual( assert.deepEqual(
env.dataSources[2].entities.values.map( env.dataSources[2].entities.values.map(
(entity) => entity.__gevTeleGeography.featureId, (entity) => cablePicks.read(entity)?.info.featureId,
), ),
['alpha', 'alpha_2', 'cable-2', 'alpha'], ['alpha', 'alpha_2', 'cable-2', 'alpha'],
); );
@@ -1951,12 +1952,12 @@ test('multipart landing geometry keeps every pick with one reference per feature
try { try {
const entities = env.dataSources[1].entities.values; const entities = env.dataSources[1].entities.values;
assert.deepEqual( assert.deepEqual(
entities.map((entity) => entity.__gevTeleGeography?.label), entities.map((entity) => cablePicks.read(entity)?.info.label),
['Alpha cable', 'Alpha cable', 'Alpha cable', 'Beta cable'], ['Alpha cable', 'Alpha cable', 'Alpha cable', 'Beta cable'],
); );
assert.ok( assert.ok(
entities.every( entities.every(
(entity) => entity.__gevTeleGeography.kind === 'landing-point', (entity) => cablePicks.read(entity)?.info.kind === 'landing-point',
), ),
); );
assert.equal(env.dataSources[2].entities.values.length, 2); assert.equal(env.dataSources[2].entities.values.length, 2);
@@ -1989,11 +1990,11 @@ test('every bundled cable segment is associated with its source feature', async
for (const [index, entity] of entities.entries()) { for (const [index, entity] of entities.entries()) {
const feature = expandedFeatures[index]; const feature = expandedFeatures[index];
assert.equal( assert.equal(
entity.__gevTeleGeography?.label, cablePicks.read(entity)?.info.label,
feature.properties.name, feature.properties.name,
entity.id, entity.id,
); );
assert.deepEqual(entity.__gevTeleGeography.reference, { assert.deepEqual(cablePicks.read(entity)?.info.reference, {
lon: feature.properties.coordinates[0], lon: feature.properties.coordinates[0],
lat: feature.properties.coordinates[1], lat: feature.properties.coordinates[1],
}); });
-1
View File
@@ -142,7 +142,6 @@ export function createIngestion({ state, parts, source }) {
const cableEntities = state._cableDataSource.entities.values; const cableEntities = state._cableDataSource.entities.values;
const landingEntities = state._landingDataSource.entities.values; const landingEntities = state._landingDataSource.entities.values;
state._pickByEntity = new WeakMap();
state._referenceRecords = []; state._referenceRecords = [];
state._surfaceRecords = []; state._surfaceRecords = [];
+4 -6
View File
@@ -1,10 +1,10 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import { isPointerFree } from '../../data/inputOwnership.js'; import { isPointerFree } from '../../data/inputOwnership.js';
import { cablePicks } from './pickState.js';
export function createInteraction({ state, screenSpaceEventHandlerFactory }) { export function createInteraction({ state, screenSpaceEventHandlerFactory }) {
function registerPickEntity(entity, info) { function registerPickEntity(entity, info) {
entity.__gevTeleGeography = info; cablePicks.write(entity).info = info;
state._pickByEntity.set(entity, info);
} }
function beginInteraction(viewer) { function beginInteraction(viewer) {
@@ -25,9 +25,8 @@ export function createInteraction({ state, screenSpaceEventHandlerFactory }) {
if (!picked) return null; if (!picked) return null;
const primitive = picked.primitive; const primitive = picked.primitive;
if (primitive) { if (primitive) {
const primitiveInfo = state._pickByEntity.get(primitive); const primitiveInfo = cablePicks.read(primitive)?.info;
if (primitiveInfo) return primitiveInfo; if (primitiveInfo) return primitiveInfo;
if (primitive.__gevTeleGeography) return primitive.__gevTeleGeography;
if ( if (
primitive.id && primitive.id &&
typeof primitive.id === 'object' && typeof primitive.id === 'object' &&
@@ -39,9 +38,8 @@ export function createInteraction({ state, screenSpaceEventHandlerFactory }) {
const entity = picked.id; const entity = picked.id;
if (entity) { if (entity) {
const entityInfo = state._pickByEntity.get(entity); const entityInfo = cablePicks.read(entity)?.info;
if (entityInfo) return entityInfo; if (entityInfo) return entityInfo;
if (entity.__gevTeleGeography) return entity.__gevTeleGeography;
if (entity.id && typeof entity.id === 'object' && entity.id.reference) { if (entity.id && typeof entity.id === 'object' && entity.id.reference) {
return entity.id; return entity.id;
} }
-1
View File
@@ -133,7 +133,6 @@ export function createLifecycle({ state, parts, source, mapStackEventTarget }) {
state._referenceDataSource = null; state._referenceDataSource = null;
state._referenceRecords = []; state._referenceRecords = [];
state._surfaceRecords = []; state._surfaceRecords = [];
state._pickByEntity = new WeakMap();
state._referenceLabelCount = 0; state._referenceLabelCount = 0;
state._publishScratch.length = 0; state._publishScratch.length = 0;
state._markerBlendDone = false; state._markerBlendDone = false;
+7
View File
@@ -0,0 +1,7 @@
import { createEntityStore } from '../../data/entityRecords.js';
/**
* The reference a picked cable, landing point or reference marker flies to:
* `info` is `{ label, kind, featureId, reference: { lon, lat } }`.
*/
export const cablePicks = createEntityStore();
+2 -3
View File
@@ -10,6 +10,7 @@ import {
selectCableReferenceLabelWinners, selectCableReferenceLabelWinners,
cableReferencePriority, cableReferencePriority,
} from './overlay.js'; } from './overlay.js';
import { cablePicks } from './pickState.js';
export function createRendering({ state }) { export function createRendering({ state }) {
function resetPublishSignature() { function resetPublishSignature() {
@@ -40,7 +41,6 @@ export function createRendering({ state }) {
state._referenceDataSource = null; state._referenceDataSource = null;
state._referenceRecords = []; state._referenceRecords = [];
state._surfaceRecords = []; state._surfaceRecords = [];
state._pickByEntity = new WeakMap();
state._referenceLabelCount = 0; state._referenceLabelCount = 0;
state._publishScratch.length = 0; state._publishScratch.length = 0;
// The blend pass targets the collections being dropped; the rebuilt // The blend pass targets the collections being dropped; the rebuilt
@@ -180,8 +180,7 @@ export function createRendering({ state }) {
}, },
}); });
entity.__gevTeleGeography = info; cablePicks.write(entity).info = info;
state._pickByEntity.set(entity, info);
const record = { const record = {
id: entity.id, id: entity.id,
entity, entity,
-2
View File
@@ -69,8 +69,6 @@ export function createState({ sweepClock, overlayHost }) {
state._markerBlendInvariantWarned = false; state._markerBlendInvariantWarned = false;
state._pickByEntity = new WeakMap();
state._referenceLabelCount = 0; state._referenceLabelCount = 0;
state._referenceSweepGate = createCableReferenceSweepGate({ state._referenceSweepGate = createCableReferenceSweepGate({
+5 -2
View File
@@ -2869,9 +2869,12 @@ async function basemapLabelsAt(
}; };
} }
/** Viewers that already prewarm view targets on camera settle. */
const prewarmedViewers = new WeakSet();
function installViewTargetPrewarm(viewer) { function installViewTargetPrewarm(viewer) {
if (viewer.__gevViewTargetPrewarmInstalled) return; if (prewarmedViewers.has(viewer)) return;
viewer.__gevViewTargetPrewarmInstalled = true; prewarmedViewers.add(viewer);
let timer = null; let timer = null;
let reportedPrewarmFailure = false; let reportedPrewarmFailure = false;
viewer.camera.moveEnd.addEventListener(() => { viewer.camera.moveEnd.addEventListener(() => {