mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
feat(data): the selection dispatcher treats an unowned pick as empty space
Task 10a moves flights onto the dispatcher; its old handler deselected on a pick nobody owns (an unclaimed entity), and only another layer's pick was not empty space. The dispatcher now does the same (after drill-through owners had their chance), and selectionDispatcherFor(engine) gives the application one dispatcher per engine. Tests for both.
This commit is contained in:
1 parent
9f1a0611fa
commit
8e702f0c3b
2 files changed
+56
-3
No files matched your search
@@ -9,8 +9,8 @@
|
|||||||
// onEmptyClick(ctx) a clean click (short, no drag) on the map or nothing;
|
// onEmptyClick(ctx) a clean click (short, no drag) on the map or nothing;
|
||||||
// onEscape() Escape.
|
// onEscape() Escape.
|
||||||
// The rules are the old handlers': a pick another layer owns is not empty
|
// The rules are the old handlers': a pick another layer owns is not empty
|
||||||
// space; `passThrough` picks (trails) never take the click, the next pick
|
// space (a pick nobody owns is); `passThrough` picks (trails) never take the
|
||||||
// does; a `drillThrough` owner (local ADS-B) takes its object from under
|
// click, the next pick does; a `drillThrough` owner (local ADS-B) takes its object from under
|
||||||
// another layer's; a drag selects nothing; a pointer owned by a tool
|
// another layer's; a drag selects nothing; a pointer owned by a tool
|
||||||
// (inputOwnership) selects nothing. Layers not moved yet keep their own
|
// (inputOwnership) selects nothing. Layers not moved yet keep their own
|
||||||
// handlers: the dispatcher never acts on an id it does not own.
|
// handlers: the dispatcher never acts on an id it does not own.
|
||||||
@@ -125,6 +125,10 @@ export function createSelectionDispatcher(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// A pick no layer owns (an unclaimed entity) is empty space, as it was
|
||||||
|
// for the old handlers: only another layer's object is not.
|
||||||
|
if (first.owner === null && isTrackingClickGesture(gesture))
|
||||||
|
for (const owner of [...owners.values()]) owner.onEmptyClick?.(ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKey = (event) => {
|
const onKey = (event) => {
|
||||||
@@ -186,6 +190,23 @@ export function createSelectionDispatcher(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dispatchers = new WeakMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's one dispatcher for `engine`, created on first use (the
|
||||||
|
* layers that moved onto the engine share it).
|
||||||
|
* @param {import('../globe/contract.js').GlobeEngine} engine
|
||||||
|
*/
|
||||||
|
export function selectionDispatcherFor(engine) {
|
||||||
|
if (!engine) return null;
|
||||||
|
let dispatcher = dispatchers.get(engine);
|
||||||
|
if (!dispatcher) {
|
||||||
|
dispatcher = createSelectionDispatcher(engine);
|
||||||
|
dispatchers.set(engine, dispatcher);
|
||||||
|
}
|
||||||
|
return dispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
function safely(run) {
|
function safely(run) {
|
||||||
try {
|
try {
|
||||||
return run();
|
return run();
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import test from 'node:test';
|
import test from 'node:test';
|
||||||
import { createFakeEngine } from '../globe/testing/fakeEngine.js';
|
import { createFakeEngine } from '../globe/testing/fakeEngine.js';
|
||||||
import { createSelectionDispatcher } from './selectionDispatcher.js';
|
import {
|
||||||
|
createSelectionDispatcher,
|
||||||
|
selectionDispatcherFor,
|
||||||
|
} from './selectionDispatcher.js';
|
||||||
import {
|
import {
|
||||||
isOwnedByOtherLayer,
|
isOwnedByOtherLayer,
|
||||||
registerPickOwner,
|
registerPickOwner,
|
||||||
@@ -95,6 +98,22 @@ test("another layer's pick is not empty space, owned through the shared registry
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a pick no layer owns is empty space, as for the old handlers', () => {
|
||||||
|
const { dispatcher, click } = setup({ 10: [{ id: 'unclaimed-entity' }] });
|
||||||
|
const flights = recorder();
|
||||||
|
dispatcher.register('flights', {
|
||||||
|
owns: (id) => id === 'x',
|
||||||
|
...flights.handlers,
|
||||||
|
});
|
||||||
|
click(10);
|
||||||
|
click(10, { ms: 900 });
|
||||||
|
assert.deepEqual(
|
||||||
|
flights.calls,
|
||||||
|
[['empty', 0]],
|
||||||
|
'a long press does not deselect',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('trails do not take clicks: the object under a trail is selected', () => {
|
test('trails do not take clicks: the object under a trail is selected', () => {
|
||||||
const { dispatcher, click } = setup({
|
const { dispatcher, click } = setup({
|
||||||
10: [{ id: 'trail-ae01ce', owner: 'flights-trail' }, { id: 'ae01ce' }],
|
10: [{ id: 'trail-ae01ce', owner: 'flights-trail' }, { id: 'ae01ce' }],
|
||||||
@@ -173,3 +192,16 @@ test('unregister and destroy remove the subscriptions', () => {
|
|||||||
assert.equal(isOwnedByOtherLayer('other', 'a'), false);
|
assert.equal(isOwnedByOtherLayer('other', 'a'), false);
|
||||||
assert.ok(engine.fake.callsOf('input.on').length >= 1);
|
assert.ok(engine.fake.callsOf('input.on').length >= 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the application has one dispatcher per engine', () => {
|
||||||
|
const engine = createFakeEngine();
|
||||||
|
const other = createFakeEngine();
|
||||||
|
assert.equal(selectionDispatcherFor(engine), selectionDispatcherFor(engine));
|
||||||
|
assert.notEqual(
|
||||||
|
selectionDispatcherFor(engine),
|
||||||
|
selectionDispatcherFor(other),
|
||||||
|
);
|
||||||
|
assert.equal(selectionDispatcherFor(null), null);
|
||||||
|
selectionDispatcherFor(engine).destroy();
|
||||||
|
selectionDispatcherFor(other).destroy();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user