perf: Cache hits in collision detection (#10648)

* feat: Cache hits and scene lookups

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* chore: Remove debug

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* fix: Consider hit threshold and inside override too

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* chore: Remove Map caching

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* fix: incorrect threshold

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* fix: threshold setting

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* fix: Hit caching

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

* fix: cache override

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>

---------

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Márk Tolmács
2026-01-26 20:50:44 +01:00
committed by GitHub
parent 28691e14b1
commit dfdd994dbb
3 changed files with 217 additions and 4 deletions
+34 -1
View File
@@ -105,6 +105,12 @@ export type HitTestArgs = {
overrideShouldTestInside?: boolean;
};
let cachedPoint: GlobalPoint | null = null;
let cachedElement: WeakRef<ExcalidrawElement> | null = null;
let cachedThreshold: number = Infinity;
let cachedHit: boolean = false;
let cachedOverrideShouldTestInside = false;
export const hitElementItself = ({
point,
element,
@@ -113,6 +119,24 @@ export const hitElementItself = ({
frameNameBound = null,
overrideShouldTestInside = false,
}: HitTestArgs) => {
// Return cached result if the same point and element version is tested again
if (
cachedPoint &&
pointsEqual(point, cachedPoint) &&
cachedThreshold <= threshold &&
overrideShouldTestInside === cachedOverrideShouldTestInside
) {
const derefElement = cachedElement?.deref();
if (
derefElement &&
derefElement.id === element.id &&
derefElement.version === element.version &&
derefElement.versionNonce === element.versionNonce
) {
return cachedHit;
}
}
// Hit test against a frame's name
const hitFrameName = frameNameBound
? isPointWithinBounds(
@@ -153,7 +177,16 @@ export const hitElementItself = ({
isPointOnElementOutline(point, element, elementsMap, threshold)
: isPointOnElementOutline(point, element, elementsMap, threshold);
return hitElement || hitFrameName;
const result = hitElement || hitFrameName;
// Cache end result
cachedPoint = point;
cachedElement = new WeakRef(element);
cachedThreshold = threshold;
cachedOverrideShouldTestInside = overrideShouldTestInside;
cachedHit = result;
return result;
};
export const hitElementBoundingBox = (