interactivity budget: pickable, hitArea, skip children
모든 node를 항상 정확하게 hit test하면 단순하지만 비쌉니다. 어떤 node가 입력 대상인지 명시해야 합니다.
hit test budget을 줄이는 코드
입력 대상이 아닌 node는 최대한 빨리 제외합니다.
function shouldHitTest(node) {
if (node.hidden || node.locked) return false;
if (node.pickable === false) return false;
return true;
}
function hitTestNode(node, worldPoint) {
if (!shouldHitTest(node)) return null;
const bounds = node.hitAreaOverride ?? node.worldBounds;
if (!pointInRect(worldPoint, bounds)) return null;
if (node.skipChildrenHitTest) return node;
for (let i = node.children.length - 1; i >= 0; i -= 1) {
const hit = hitTestNode(node.children[i], worldPoint);
if (hit) return hit;
}
return pointInPreciseShape(worldPoint, node) ? node : null;
}
입력 정책 필드
pickable
locked
hidden
hitAreaOverride
skipChildrenHitTest
복잡한 vector path도 대략적인 hit area로 충분한 경우가 있습니다. 반대로 text caret처럼 정밀한 입력이 필요한 node도 있습니다.
spatial index와 함께 사용한다
function hitTestScene(sceneIndex, worldPoint) {
const candidates = sceneIndex.queryPoint(worldPoint)
.filter(shouldHitTest)
.sort((a, b) => b.zIndex - a.zIndex);
for (const node of candidates) {
const hit = hitTestNode(node, worldPoint);
if (hit) return hit;
}
return null;
}
모든 node를 매번 순회하지 않고 spatial index로 후보를 줄인 뒤, 그 후보에만 정확한 hit test를 적용합니다. pickable, locked, skipChildrenHitTest는 이 후보 단계에서도 적용할 수 있습니다.
오늘의 핵심
interactivity도 budget입니다. draw하지 않는 node, 선택 불가능한 node, children을 볼 필요 없는 group은 hit test에서 빨리 제외합니다.