Port ALPR camera visuals into the shared layer

Add camera badges, gradient direction wedges and animated tactical selection cards while preserving bounded loading and layer lifecycle. Align the ALPR data-layer header and retain native pick ownership for overlay badges.

Co-authored-by: manjunath22466 <[email protected]>
This commit is contained in:
Sameh Khamisandmanjunath22466 committed 2026-09-14 17:35:24 -07:00
1 parent 687edc4da7
commit 87629ac175
21 files changed
+951 -97

No files matched your search

+14 -18
View File
@@ -462,29 +462,25 @@ test('all manufacturers share one ALPR title and color; only supplied metadata a
assert.equal(alprCamerasLayer.name, 'ALPR Cameras');
assert.deepEqual(
entities.map((entity) => entity.gevLabelModel.title),
Array(3).fill('ALPR CAMERA'),
['ALPR-0042', 'ALPR-0043', 'ALPR-0044'],
);
assert.equal(
new Set(
entities.map((entity) =>
entity.point.color.getValue().toCssColorString(),
),
).size,
new Set(entities.map((entity) => entity.billboard.image.getValue())).size,
1,
);
assert.deepEqual(entities[0].gevLabelModel.details, [
'Manufacturer: Flock Safety',
'Operator: City Police',
'Type: fixed',
'Source: OpenStreetMap',
'OSM MAPPED',
'FLOCK SAFETY · CITY POLICE · FIXED',
'PUBLIC MAP DATA',
]);
assert.deepEqual(entities[1].gevLabelModel.details, [
'Manufacturer: Motorola Solutions',
'Source: OpenStreetMap',
'OSM MAPPED',
'MOTOROLA SOLUTIONS',
'PUBLIC MAP DATA',
]);
assert.deepEqual(
entities[2].gevLabelModel.details,
['Source: OpenStreetMap'],
['OSM MAPPED', 'PUBLIC MAP DATA'],
'unknown metadata is not guessed, but the source is always named',
);
for (const entity of entities) {
@@ -523,8 +519,8 @@ test('clicking the selected camera or empty map deselects, including after refre
await alprCamerasLayer.update();
assert.equal(getSelectedEntityContext(), null);
assert.equal(
h.source.entities.getById('alpr:42').point.pixelSize.getValue(),
8,
h.source.entities.getById('alpr:42').billboard.width.getValue(),
38,
);
}
} finally {
@@ -582,8 +578,8 @@ test('disable removes contexts and highlight; cache reuse after re-enable does n
await alprCamerasLayer.update();
assert.equal(getSelectedEntityContext(), null);
assert.equal(
h.source.entities.getById('alpr:42').point.pixelSize.getValue(),
8,
h.source.entities.getById('alpr:42').billboard.width.getValue(),
38,
);
} finally {
h.restore();
@@ -1100,7 +1096,7 @@ test('nearby count and discovery control frame a real loaded camera without fetc
await alprCamerasLayer.update();
assert.equal(alprCamerasLayer.getStats().countLabel, '1 nearby');
const controls = alprCamerasLayer.getRowControls();
assert.equal(controls.legend[0].label, 'Purple dots');
assert.equal(controls.legend[0].label, 'Camera badges');
assert.equal(controls.chips[0].onClick(), true);
assert.equal(flights.length, 1);
assert.equal(getSelectedEntityContext().id, 'alpr:42');
+10 -2
View File
@@ -142,8 +142,16 @@ export function createTrackedOverlayEntry(entity) {
title,
details: Array.isArray(model.details) ? model.details.map((line) => String(line)) : [],
accent: model.accent || WORLD_OVERLAY_STYLE.accent,
anchorRadiusPx: 10,
anchorRadiusScale: TRACKED_BILLBOARD_SCALE,
cardStyle: model.cardStyle,
selected: model.selected === true,
leaderStyle: model.leaderStyle,
leaderAnimationMs: model.leaderAnimationMs,
leaderAnimationStartedAt: model.leaderAnimationStartedAt,
leaderDrawRatio: model.leaderDrawRatio,
anchorRadiusPx: Number.isFinite(Number(model.anchorRadiusPx))
? Math.max(0, Number(model.anchorRadiusPx)) : 10,
anchorRadiusScale: Object.prototype.hasOwnProperty.call(model, 'anchorRadiusScale')
? model.anchorRadiusScale : TRACKED_BILLBOARD_SCALE,
minAnchorGapPx: 16,
anchorGapPaddingPx: 10,
verticalOnly: true,
+20
View File
@@ -121,6 +121,26 @@ test('tracked entry factory pins the production protected-lane policy', () => {
assert.equal(entry.edgeFade, 'keyhole');
});
test('selected camera readout carries tactical animation and fixed badge clearance', () => {
const entry = createTrackedOverlayEntry({
id: 'alpr:42', gevDisplayPosition: () => ({ x: 1, y: 2, z: 3 }),
gevLabelModel: {
title: 'ALPR-0042', details: ['OSM MAPPED'], accent: '#ff6474',
cardStyle: 'tactical', selected: true, leaderStyle: 'elbow',
leaderAnimationMs: 440, leaderAnimationStartedAt: 100, leaderDrawRatio: 0.68,
anchorRadiusPx: 30, anchorRadiusScale: null,
},
});
assert.equal(entry.cardStyle, 'tactical');
assert.equal(entry.selected, true);
assert.equal(entry.leaderStyle, 'elbow');
assert.equal(entry.leaderAnimationMs, 440);
assert.equal(entry.leaderAnimationStartedAt, 100);
assert.equal(entry.leaderDrawRatio, 0.68);
assert.equal(entry.anchorRadiusPx, 30);
assert.equal(entry.anchorRadiusScale, null);
});
test('tracked entity publishes a protected host entry backed by the frame cache', () => {
const originalWindow = globalThis.window;
const fakeWindow = new EventTarget();