This repository has been archived by the owner on Mar 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: no longer recalculate the mouse target on each mouseMove event
- Loading branch information
1 parent
a740ee3
commit 3ed79d1
Showing
4 changed files
with
161 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* find the smallest element in an array based on a certain criteria | ||
* | ||
* @param isSmaller The compare function | ||
* @param arr The array to search trough | ||
* @param def Fallback in case of empty arrays | ||
*/ | ||
export const minBy = <T>( | ||
isSmaller: (a: T, b: T) => boolean, | ||
arr: T[] | ||
): T | null => | ||
arr.reduce((acc, curr) => { | ||
if (acc === null) { | ||
return curr | ||
} | ||
|
||
if (curr === null) { | ||
return acc | ||
} | ||
|
||
return isSmaller(curr, acc) ? curr : acc | ||
}, null as T | null) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { NodeGeometry, NodeId, GeometryCache } from "./types/Node" | ||
import { ADT } from "ts-adt" | ||
import * as g from "@thi.ng/geom" | ||
import { Vec, dist, distSq2 } from "@thi.ng/vectors" | ||
import { minBy } from "./helpers/minBy" | ||
import { pickDistance } from "./constants" | ||
import { closestPoint } from "@thi.ng/geom" | ||
|
||
interface IHasNode { | ||
node: NodeGeometry | ||
} | ||
|
||
export enum MouseTargetKind { | ||
Nothing, | ||
Node, | ||
NodeInput, | ||
NodeOutput | ||
} | ||
|
||
export type MouseTarget = ADT<{ | ||
[MouseTargetKind.NodeInput]: IHasNode & { index: number; geom: g.Arc } | ||
[MouseTargetKind.Node]: IHasNode & { id: NodeId } | ||
[MouseTargetKind.NodeOutput]: IHasNode | ||
[MouseTargetKind.Nothing]: {} | ||
}> | ||
|
||
/** | ||
* Finds the object in the scene the mouse is hovering over | ||
* | ||
* @param mousePosition The position the mouse is at | ||
* @param cache The geometry cache to search trough | ||
*/ | ||
export const getMouseTarget = ( | ||
mousePosition: Vec, | ||
cache: GeometryCache | ||
): MouseTarget => { | ||
if (cache.nodes.size === 0) { | ||
return { | ||
_type: MouseTargetKind.Nothing | ||
} | ||
} | ||
|
||
const nodes = [...cache.nodes.values()] | ||
|
||
const distanceToMouse = (position: Vec) => dist(mousePosition, position) | ||
|
||
const distanceToMouseSq = (position: Vec) => distSq2(mousePosition, position) | ||
|
||
const closestOutput = minBy((a, b) => { | ||
return distanceToMouseSq(a.output!.pos) < distanceToMouseSq(b.output!.pos) | ||
}, nodes) | ||
|
||
if ( | ||
closestOutput !== null && | ||
distanceToMouse(closestOutput.output.pos) < pickDistance.output | ||
) { | ||
return { | ||
_type: MouseTargetKind.NodeOutput, | ||
node: closestOutput | ||
} | ||
} | ||
|
||
const closestInput = minBy( | ||
(a, b) => { | ||
return distanceToMouse(a.closest) < distanceToMouse(b.closest) | ||
}, | ||
nodes.flatMap((node) => | ||
node.inputs[0].attribs?.selectable | ||
? node.inputs.map((input, index) => ({ | ||
index, | ||
node, | ||
closest: closestPoint(input, mousePosition)! | ||
})) | ||
: [] | ||
) | ||
) | ||
|
||
if ( | ||
closestInput && | ||
distanceToMouse(closestInput.closest) < pickDistance.input | ||
) { | ||
return { | ||
_type: MouseTargetKind.NodeInput, | ||
node: closestInput.node, | ||
index: closestInput.index, | ||
geom: closestInput.node.inputs[closestInput.index] as g.Arc | ||
} | ||
} | ||
|
||
// Rn this is the same as the output one but in the future nodes might not have outputs. | ||
const closestNode = minBy( | ||
([, a], [, b]) => { | ||
return distanceToMouseSq(a.output!.pos) < distanceToMouseSq(b.output!.pos) | ||
}, | ||
[...cache.nodes.entries()] | ||
) | ||
|
||
if ( | ||
closestNode && | ||
distanceToMouse(closestNode[1].output!.pos) < pickDistance.node | ||
) { | ||
return { | ||
_type: MouseTargetKind.Node, | ||
node: closestNode[1], | ||
id: closestNode[0] | ||
} | ||
} | ||
|
||
return { | ||
_type: MouseTargetKind.Nothing | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters