Files
gods-eye-view/src/annotations/worldAnnotationRenderer.test.mjs
T
Said Turksever 38eb98b8f8 Take a hidden shape off the globe whole, and keep every drawn shape
Answers the review of bdbbc3d7 and the IC8 pass after it.

A shape hidden from Draw's list was only set to alpha 0, so the line's
flowing stroke, which keeps its own colour, stayed painted. Now:
- the world renderer's sync() sets every entity of a hidden mark to
  show = false, and FlowMaterialProperty follows the mark's alpha;
- the screen renderer does not project a hidden callout, so it is not drawn
  and cannot push a visible label aside;
- hiding acts at once, even before a mark's first frame, and with every
  mark hidden the annotations render hold is released after one last frame;
- fly_route skips a hidden route.

Hand-drawn shapes are never merged as duplicates: every one is drawn on
purpose and unnamed until its row names it, so a second pin dropped near
the first was dropped, or replaced the first when its colour differed. A
restyle the renderer cannot draw now also syncs the renderer.

Tests cover each: renderer show/hide and flow alpha, the screen skip, the
render hold and its last frame, a show with no fade-in, hidden routes, two
nearby pins, and the restyle rollback.
2026-11-02 16:43:39 +00:00

71 lines
3.3 KiB
JavaScript

// A mark hidden from Draw's list leaves the globe whole: every entity it put
// there is taken out on sync and comes back when shown, and the line's
// flowing stroke, which keeps its own colour, follows the mark's alpha.
import test from 'node:test';
import assert from 'node:assert/strict';
import * as C from 'cesium';
import {
FlowMaterialProperty,
createWorldAnnotationRenderer,
} from './worldAnnotationRenderer.js';
const noop = () => {};
function viewer(t) {
for (const name of ['HTMLCanvasElement', 'HTMLImageElement', 'ImageBitmap', 'OffscreenCanvas']) {
const original = globalThis[name];
globalThis[name] = class {};
t.after(() => { if (original === undefined) delete globalThis[name]; else globalThis[name] = original; });
}
const before = globalThis.document;
globalThis.document = { addEventListener: noop, removeEventListener: noop };
t.after(() => { if (before === undefined) delete globalThis.document; else globalThis.document = before; });
return {
creditDisplay: { addStaticCredit: noop, removeStaticCredit: noop },
entities: new C.EntityCollection(),
dataSources: new C.DataSourceCollection(),
camera: { moveEnd: new C.Event(), positionCartographic: { height: 1000 } },
scene: { requestRender: noop, canvas: { addEventListener: noop, removeEventListener: noop }, preRender: new C.Event(),
primitives: { add: (p) => p, remove: noop }, screenSpaceCameraController: { enableInputs: true } },
};
}
const marks = () => [
{ id: 'route', type: 'route', color: 'amber', alpha: 1, anchor: { lat: 0, lon: 0 }, path: [{ lat: 0, lon: 0 }, { lat: 0.01, lon: 0.01 }] },
{ id: 'area', type: 'area', color: 'green', alpha: 1, anchor: { lat: 0.005, lon: 0.005 }, ring: [[0, 0], [0.01, 0], [0.01, 0.01], [0, 0]] },
{ id: 'pin', type: 'pin', color: 'primary', alpha: 1, anchor: { lat: 0.02, lon: 0.02 } },
];
test('a hidden mark has every entity taken off on sync, and back when shown', (t) => {
const renderer = createWorldAnnotationRenderer(viewer(t));
const [route, area, pin] = marks();
for (const anno of [route, area, pin]) renderer.add(anno);
const shown = (anno) => anno._entities.map((entity) => entity.show);
for (const anno of [route, area, pin]) assert.ok(anno._entities.length > 0, anno.id);
route.hidden = true;
area.hidden = true;
renderer.sync();
assert.ok(shown(route).every((show) => show === false), 'the line is off');
assert.ok(shown(area).every((show) => show === false), 'the area is off');
assert.ok(shown(pin).every((show) => show === true), 'a visible mark stays');
route.hidden = false;
renderer.sync();
assert.ok(shown(route).every((show) => show === true), 'the line is back');
renderer.remove(area);
renderer.sync();
assert.equal(area._entities, null, 'a removed mark is no longer synced');
renderer.destroy();
});
test('the line\'s flowing stroke follows its mark\'s alpha', () => {
let alpha = 1;
const material = new FlowMaterialProperty('#ffb547', () => alpha);
assert.ok(Math.abs(material.getValue(null, {}).color.alpha - 0.95) < 1e-9);
alpha = 0;
assert.equal(material.getValue(null, {}).color.alpha, 0, 'hidden: nothing painted');
alpha = 0.5;
assert.ok(Math.abs(material.getValue(null, {}).color.alpha - 0.475) < 1e-9, 'fading');
assert.equal(new FlowMaterialProperty('#fff').getValue(null, {}).color.alpha, 0.95, 'no alpha source: opaque as before');
});