refactor(wrapNode): simplify dragging behaviour

This commit is contained in:
moklick
2020-09-11 16:36:23 +02:00
parent 36a81ff499
commit d17e6ebaea
4 changed files with 32 additions and 48 deletions
+24 -48
View File
@@ -11,16 +11,12 @@ import React, {
} from 'react';
import { DraggableCore } from 'react-draggable';
import cc from 'classcat';
import { ResizeObserver } from 'resize-observer';
import { useStoreActions } from '../../store/hooks';
import { useStoreActions } from '../../store/hooks';
import { Provider } from '../../contexts/NodeIdContext';
import { Node, NodeComponentProps, WrapNodeProps } from '../../types';
const getMouseEvent = (event: MouseEvent | TouchEvent) =>
typeof TouchEvent !== 'undefined' && event instanceof TouchEvent ? event.touches[0] : (event as MouseEvent);
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
const NodeWrapper = ({
id,
@@ -47,18 +43,20 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
targetPosition,
isHidden,
isInitialized,
snapToGrid,
snapGrid,
}: WrapNodeProps) => {
const updateNodeDimensions = useStoreActions((actions) => actions.updateNodeDimensions);
const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements);
const updateNodePos = useStoreActions((actions) => actions.updateNodePos);
const updateNodePosDiff = useStoreActions((actions) => actions.updateNodePosDiff);
const unsetNodesSelection = useStoreActions((actions) => actions.unsetNodesSelection);
const nodeElement = useRef<HTMLDivElement>(null);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const [isDragging, setDragging] = useState(false);
const position = useMemo(() => ({ x: xPos, y: yPos }), [xPos, yPos]);
const node = useMemo(() => ({ id, type, position, data }), [id, type, position, data]);
const node = useMemo(() => ({ id, type, position: { x: xPos, y: yPos }, data }), [id, type, xPos, yPos, data]);
const grid = useMemo(() => (snapToGrid ? snapGrid : [1, 1])! as [number, number], [snapToGrid, snapGrid]);
const nodeStyle: CSSProperties = useMemo(
() => ({
zIndex: selected ? 10 : 3,
@@ -109,9 +107,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
setSelectedElements({ id: node.id, type: node.type } as Node);
}
if (onClick) {
onClick(event, node);
}
onClick?.(event, node);
}
},
[isSelectable, isDraggable, onClick, node]
@@ -119,66 +115,47 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
const onDragStart = useCallback(
(event) => {
const startEvent = getMouseEvent(event);
const scaledClientX = startEvent.clientX / transform[2];
const scaledClientY = startEvent.clientY / transform[2];
const offsetX = scaledClientX - position.x - transform[0];
const offsetY = scaledClientY - position.y - transform[1];
setOffset({ x: offsetX, y: offsetY });
if (onNodeDragStart) {
onNodeDragStart(event as MouseEvent, node);
}
onNodeDragStart?.(event as MouseEvent, node);
if (selectNodesOnDrag && isSelectable) {
unsetNodesSelection();
setSelectedElements({ id: node.id, type: node.type } as Node);
}
},
[node, transform, position, selectNodesOnDrag, isSelectable, onNodeDragStart]
[node, transform, selectNodesOnDrag, isSelectable, onNodeDragStart]
);
const onDrag = useCallback(
(event) => {
const dragEvent = getMouseEvent(event);
const scaledClientX = dragEvent.clientX / transform[2];
const scaledClientY = dragEvent.clientY / transform[2];
(_, data) => {
setDragging(true);
updateNodePos({
updateNodePosDiff({
id,
pos: {
x: scaledClientX - transform[0] - offset.x,
y: scaledClientY - transform[1] - offset.y,
diff: {
x: data.deltaX,
y: data.deltaY,
},
});
},
[id, transform, offset]
[id, transform]
);
const onDragStop = useCallback(
(event) => {
// onDragStop also gets called when user just clicks on a node.
// Because of that we set dragging to true inside the onDrag handler and handle the click here
if (!isDragging) {
if (isSelectable && !selectNodesOnDrag) {
setSelectedElements({ id: node.id, type: node.type } as Node);
}
if (onClick) {
onClick(event as MouseEvent, node);
}
onClick?.(event as MouseEvent, node);
return;
}
setDragging(false);
if (onNodeDragStop) {
onNodeDragStop(event as MouseEvent, node);
}
onNodeDragStop?.(event as MouseEvent, node);
},
[node, isDragging, isSelectable, selectNodesOnDrag, onClick, onNodeDragStop]
);
@@ -187,11 +164,9 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
if (nodeElement.current) {
updateNodeDimensions({ id, nodeElement: nodeElement.current });
const resizeObserver = new ResizeObserver((entries) => {
for (let _ of entries) {
if (nodeElement.current) {
updateNodeDimensions({ id, nodeElement: nodeElement.current });
}
const resizeObserver = new ResizeObserver(() => {
if (nodeElement.current) {
updateNodeDimensions({ id, nodeElement: nodeElement.current });
}
});
@@ -230,6 +205,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
disabled={!isDraggable}
cancel=".nodrag"
nodeRef={nodeElement}
grid={grid}
>
<div
className={nodeClasses}
+2
View File
@@ -279,6 +279,8 @@ const GraphView = ({
onNodeDragStart={onNodeDragStart}
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
selectNodesOnDrag={selectNodesOnDrag}
snapToGrid={snapToGrid}
snapGrid={snapGrid}
/>
<EdgeRenderer
edgeTypes={edgeTypes}
+4
View File
@@ -15,6 +15,8 @@ interface NodeRendererProps {
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
onlyRenderVisibleNodes?: boolean;
snapToGrid?: boolean;
snapGrid?: [number, number];
}
function renderNode(
@@ -66,6 +68,8 @@ function renderNode(
selectNodesOnDrag={props.selectNodesOnDrag}
isHidden={node.isHidden}
isInitialized={isInitialized}
snapGrid={props.snapGrid}
snapToGrid={props.snapToGrid}
/>
);
}
+2
View File
@@ -172,6 +172,8 @@ export interface WrapNodeProps {
targetPosition?: Position;
isHidden?: boolean;
isInitialized?: boolean;
snapToGrid?: boolean;
snapGrid?: [number, number];
}
export type FitViewParams = {