Skip to content

Commit

Permalink
Merge pull request #291 from reaviz/dragging-refactor
Browse files Browse the repository at this point in the history
Refactor Dragging State
  • Loading branch information
amcdnl authored Oct 31, 2024
2 parents ff19c2a + e7a763b commit 520655c
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 48 deletions.
6 changes: 3 additions & 3 deletions src/CameraControls/CameraControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const CameraControls: FC<
const gl = useThree(state => state.gl);
const isOrbiting = mode === 'orbit';
const setPanning = useStore(state => state.setPanning);
const draggingId = useStore(state => state.draggingId);
const isDragging = useStore(state => state.draggingIds.length > 0);

useFrame((_state, delta) => {
if (cameraRef.current?.enabled) {
Expand Down Expand Up @@ -277,7 +277,7 @@ export const CameraControls: FC<

useEffect(() => {
// If a node is being dragged, disable the camera controls
if (draggingId) {
if (isDragging) {
cameraRef.current.mouseButtons.left = ThreeCameraControls.ACTION.NONE;
} else {
if (mode === 'rotate') {
Expand All @@ -288,7 +288,7 @@ export const CameraControls: FC<
ThreeCameraControls.ACTION.TRUCK;
}
}
}, [draggingId, mode]);
}, [isDragging, mode]);

useHotkeys([
{
Expand Down
8 changes: 4 additions & 4 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ export interface GraphState {
setEdgeContextMenus: (edges: Set<string>) => void;
edgeMeshes: Array<Mesh<BufferGeometry>>;
setEdgeMeshes: (edgeMeshes: Array<Mesh<BufferGeometry>>) => void;
draggingId?: string | null;
draggingIds?: string[];
drags?: DragReferences;
panning?: boolean;
theme: Theme;
setTheme: (theme: Theme) => void;
setClusters: (clusters: Map<string, ClusterGroup>) => void;
setPanning: (panning: boolean) => void;
setDrags: (drags: DragReferences) => void;
setDraggingId: (id: string | null) => void;
setDraggingIds: (id: string[]) => void;
setActives: (actives: string[]) => void;
setSelections: (selections: string[]) => void;
setNodes: (nodes: InternalGraphNode[]) => void;
Expand Down Expand Up @@ -74,7 +74,7 @@ export const createStore = ({
collapsedNodeIds,
clusters: new Map(),
panning: false,
draggingId: null,
draggingIds: [],
actives,
edgeContextMenus: new Set(),
edgeMeshes: [],
Expand All @@ -91,7 +91,7 @@ export const createStore = ({
setEdgeMeshes: edgeMeshes => set(state => ({ ...state, edgeMeshes })),
setPanning: panning => set(state => ({ ...state, panning })),
setDrags: drags => set(state => ({ ...state, drags })),
setDraggingId: draggingId => set(state => ({ ...state, draggingId })),
setDraggingIds: draggingIds => set(state => ({ ...state, draggingIds })),
setActives: actives => set(state => ({ ...state, actives })),
setSelections: selections => set(state => ({ ...state, selections })),
setNodes: nodes =>
Expand Down
6 changes: 3 additions & 3 deletions src/symbols/Arrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const Arrow: FC<ArrowProps> = ({
}) => {
const normalizedColor = useMemo(() => new Color(color), [color]);
const meshRef = useRef<Mesh | null>(null);
const draggingId = useStore(state => state.draggingId);
const isDragging = useStore(state => state.draggingIds.length > 0);
const center = useStore(state => state.centerPosition);

const [{ pos, arrowOpacity }] = useSpring(
Expand All @@ -81,10 +81,10 @@ export const Arrow: FC<ArrowProps> = ({
},
config: {
...animationConfig,
duration: animated && !draggingId ? undefined : 0
duration: animated && !isDragging ? undefined : 0
}
}),
[animated, draggingId, opacity, position]
[animated, isDragging, opacity, position]
);

const setQuaternion = useCallback(() => {
Expand Down
8 changes: 4 additions & 4 deletions src/symbols/Edge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export const Edge: FC<EdgeProps> = ({
onPointerOut
}) => {
const theme = useStore(state => state.theme);
const draggingId = useStore(state => state.draggingId);
const isDragging = useStore(state => state.draggingIds.length > 0);

// UI states
const [active, setActive] = useState<boolean>(false);
Expand Down Expand Up @@ -229,10 +229,10 @@ export const Edge: FC<EdgeProps> = ({
},
config: {
...animationConfig,
duration: animated && !draggingId ? undefined : 0
duration: animated && !isDragging ? undefined : 0
}
}),
[midPoint, animated, draggingId]
[midPoint, animated, isDragging]
);

const labelRotation = useMemo(
Expand All @@ -256,7 +256,7 @@ export const Edge: FC<EdgeProps> = ({
]
);

useCursor(active && !draggingId && onClick !== undefined, 'pointer');
useCursor(active && !isDragging && onClick !== undefined, 'pointer');

const { pointerOver, pointerOut } = useHoverIntent({
disabled,
Expand Down
6 changes: 3 additions & 3 deletions src/symbols/Line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const Line: FC<LineProps> = ({
onPointerOut
}) => {
const tubeRef = useRef<TubeGeometry | null>(null);
const draggingId = useStore(state => state.draggingId);
const isDragging = useStore(state => state.draggingIds.length > 0);
const normalizedColor = useMemo(() => new Color(color), [color]);
const center = useStore(state => state.centerPosition);
const mounted = useRef<boolean>(false);
Expand Down Expand Up @@ -132,10 +132,10 @@ export const Line: FC<LineProps> = ({
},
config: {
...animationConfig,
duration: animated && !draggingId ? undefined : 0
duration: animated && !isDragging ? undefined : 0
}
};
}, [animated, draggingId, curve, size]);
}, [animated, isDragging, curve, size]);

useEffect(() => {
// Handle mount operation for initial render
Expand Down
40 changes: 21 additions & 19 deletions src/symbols/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ export const Node: FC<NodeProps> = ({
const theme = useStore(state => state.theme);
const node = useStore(state => state.nodes.find(n => n.id === id));
const edges = useStore(state => state.edges);
const draggingId = useStore(state => state.draggingId);
const draggingIds = useStore(state => state.draggingIds);
const collapsedNodeIds = useStore(state => state.collapsedNodeIds);
const setDraggingId = useStore(state => state.setDraggingId);
const setDraggingIds = useStore(state => state.setDraggingIds);
const setNodePosition = useStore(state => state.setNodePosition);
const setCollapsedNodeIds = useStore(state => state.setCollapsedNodeIds);
const isCollapsed = useStore(state => state.collapsedNodeIds.includes(id));
Expand All @@ -151,7 +151,9 @@ export const Node: FC<NodeProps> = ({
const center = useStore(state => state.centerPosition);
const cluster = useStore(state => state.clusters.get(node.cluster));

const isDragging = draggingId === id;
const isDraggingCurrent = draggingIds.includes(id);
const isDragging = draggingIds.length > 0;

const {
position,
label,
Expand Down Expand Up @@ -209,10 +211,10 @@ export const Node: FC<NodeProps> = ({
},
config: {
...animationConfig,
duration: animated && !draggingId ? undefined : 0
duration: animated && !isDragging ? undefined : 0
}
}),
[isDragging, position, animated, nodeSize, shouldHighlight]
[isDraggingCurrent, position, animated, nodeSize, shouldHighlight]
);

const bind = useDrag({
Expand All @@ -223,30 +225,30 @@ export const Node: FC<NodeProps> = ({
// @ts-ignore
set: pos => setNodePosition(id, pos),
onDragStart: () => {
setDraggingId(id);
setDraggingIds([...new Set([...draggingIds, id])]);
setActive(true);
},
onDragEnd: () => {
setDraggingId(null);
setDraggingIds(draggingIds.filter(id => id !== id));
setActive(false);
onDragged?.(node);
}
});

useCursor(active && !draggingId && onClick !== undefined, 'pointer');
useCursor(active && !isDragging && onClick !== undefined, 'pointer');
useCursor(
active && draggable && !isDragging && onClick === undefined,
active && draggable && !isDraggingCurrent && onClick === undefined,
'grab'
);
useCursor(isDragging, 'grabbing');
useCursor(isDraggingCurrent, 'grabbing');

const combinedActiveState = shouldHighlight || isDragging;
const combinedActiveState = shouldHighlight || isDraggingCurrent;
const color = combinedActiveState
? theme.node.activeFill
: node.fill || theme.node.fill;

const { pointerOver, pointerOut } = useHoverIntent({
disabled: disabled || isDragging,
disabled: disabled || isDraggingCurrent,
onPointerOver: (event: ThreeEvent<PointerEvent>) => {
cameraControls.controls.truckSpeed = 0;
setActive(true);
Expand Down Expand Up @@ -325,9 +327,9 @@ export const Node: FC<NodeProps> = ({
fontUrl={labelFontUrl}
opacity={selectionOpacity}
stroke={theme.node.label.stroke}
active={isSelected || active || isDragging || isActive}
active={isSelected || active || isDraggingCurrent || isActive}
color={
isSelected || active || isDragging || isActive
isSelected || active || isDraggingCurrent || isActive
? theme.node.label.activeColor
: theme.node.label.color
}
Expand All @@ -341,9 +343,9 @@ export const Node: FC<NodeProps> = ({
fontSize={5}
opacity={selectionOpacity}
stroke={theme.node.subLabel?.stroke}
active={isSelected || active || isDragging || isActive}
active={isSelected || active || isDraggingCurrent || isActive}
color={
isSelected || active || isDragging || isActive
isSelected || active || isDraggingCurrent || isActive
? theme.node.subLabel?.activeColor
: theme.node.subLabel?.color
}
Expand All @@ -355,7 +357,7 @@ export const Node: FC<NodeProps> = ({
[
active,
isActive,
isDragging,
isDraggingCurrent,
isSelected,
label,
labelFontUrl,
Expand Down Expand Up @@ -399,7 +401,7 @@ export const Node: FC<NodeProps> = ({
onPointerOver={pointerOver}
onPointerOut={pointerOut}
onClick={(event: ThreeEvent<MouseEvent>) => {
if (!disabled && !isDragging) {
if (!disabled && !isDraggingCurrent) {
onClick?.(
node,
{
Expand All @@ -411,7 +413,7 @@ export const Node: FC<NodeProps> = ({
}
}}
onDoubleClick={(event: ThreeEvent<MouseEvent>) => {
if (!disabled && !isDragging) {
if (!disabled && !isDraggingCurrent) {
onDoubleClick?.(node, event);
}
}}
Expand Down
6 changes: 3 additions & 3 deletions src/symbols/edges/Edge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const Edge: FC<EdgeProps> = ({
const nodes = useStore(store => store.nodes);
const from = nodes.find(node => node.id === source);
const to = nodes.find(node => node.id === target);
const draggingId = useStore(state => state.draggingId);
const isDragging = useStore(state => state.draggingIds.length > 0);

const labelOffset = (size + theme.edge.label.fontSize) / 2;

Expand All @@ -109,10 +109,10 @@ export const Edge: FC<EdgeProps> = ({
},
config: {
...animationConfig,
duration: animated && !draggingId ? undefined : 0
duration: animated && !isDragging ? undefined : 0
}
}),
[midPoint, animated, draggingId]
[midPoint, animated, isDragging]
);

const removeContextMenu = useCallback(
Expand Down
24 changes: 15 additions & 9 deletions src/symbols/edges/Edges.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const Edges: FC<EdgesProps> = ({
interpolation
);

const draggingId = useStore(state => state.draggingId);
const draggingIds = useStore(state => state.draggingIds);
const edgeMeshes = useStore(state => state.edgeMeshes);
const setEdgeMeshes = useStore(state => state.setEdgeMeshes);
const actives = useStore(state => state.actives || []);
Expand All @@ -113,7 +113,10 @@ export const Edges: FC<EdgesProps> = ({
const draggingActive: Array<InternalGraphEdge> = [];
const draggingInactive: Array<InternalGraphEdge> = [];
edges.forEach(edge => {
if (draggingId === edge.source || draggingId === edge.target) {
if (
draggingIds.includes(edge.source) ||
draggingIds.includes(edge.target)
) {
if (selections.includes(edge.id) || actives.includes(edge.id)) {
draggingActive.push(edge);
} else {
Expand All @@ -129,7 +132,7 @@ export const Edges: FC<EdgesProps> = ({
}
});
return [active, inactive, draggingActive, draggingInactive];
}, [edges, actives, selections, draggingId]);
}, [edges, actives, selections, draggingIds]);

const hasSelections = !!selections.length;

Expand All @@ -147,12 +150,12 @@ export const Edges: FC<EdgesProps> = ({
useEdgePositionAnimation(staticEdgesGeometry, animated);

useEffect(() => {
if (draggingId === null) {
if (draggingIds.length === 0) {
const edgeGeometries = getGeometries(edges);
const edgeMeshes = edgeGeometries.map(edge => new Mesh(edge));
setEdgeMeshes(edgeMeshes);
}
}, [getGeometries, setEdgeMeshes, edges, draggingId]);
}, [getGeometries, setEdgeMeshes, edges, draggingIds.length]);

const staticEdgesRef = useRef(new Mesh());
const dynamicEdgesRef = useRef(new Mesh());
Expand Down Expand Up @@ -186,7 +189,7 @@ export const Edges: FC<EdgesProps> = ({
disabled
);

const draggingIdRef = useRef<string | null>(null);
const draggingIdRef = useRef<string[]>([]);
const intersectingRef = useRef<Array<InternalGraphEdge>>([]);

useFrame(state => {
Expand All @@ -197,15 +200,18 @@ export const Edges: FC<EdgesProps> = ({
}

const previousDraggingId = draggingIdRef.current;
if (draggingId || (draggingId === null && previousDraggingId !== null)) {
if (
draggingIds.length ||
(draggingIds.length === 0 && previousDraggingId !== null)
) {
dynamicEdgesRef.current.geometry = getGeometry(
draggingActive,
draggingInactive
);
}

draggingIdRef.current = draggingId;
if (draggingId) {
draggingIdRef.current = draggingIds;
if (draggingIds.length) {
return;
}

Expand Down

0 comments on commit 520655c

Please sign in to comment.