Merge pull request #2738 from wbkd/fix/fitview-subflow

Fix/fitview subflow
This commit is contained in:
Moritz Klack
2023-01-10 17:11:25 +01:00
committed by GitHub
6 changed files with 75 additions and 58 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@reactflow/core': patch
---
fix: fitView for subflows, context manu on right mouse pan
+1
View File
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite --port 3000 --open",
"serve": "vite serve --port 3000",
"build": "vite build",
"test:dev": "cypress open",
"test": "pnpm test-component && pnpm test-e2e",
"test-component": "cypress run --component",
@@ -22,7 +22,6 @@ const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
const defaultViewport = { x: 0, y: 0, zoom: 1.5 };
const initialNodes: Node[] = [
{
id: '1',
+29 -25
View File
@@ -76,6 +76,7 @@ const ZoomPane = ({
const prevTransform = useRef<Viewport>({ x: 0, y: 0, zoom: 0 });
const { d3Zoom, d3Selection, d3ZoomHandler, userSelectionActive } = useStore(selector, shallow);
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
const mouseButton = useRef<number>(0);
useResizeHandler(zoomPane);
@@ -164,30 +165,6 @@ const ZoomPane = ({
noWheelClassName,
]);
useEffect(() => {
if (d3Zoom) {
if (userSelectionActive && !isZoomingOrPanning.current) {
d3Zoom.on('zoom', null);
} else if (!userSelectionActive) {
d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
const { onViewportChange } = store.getState();
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] });
zoomedWithRightMouseButton.current = !!(
onPaneContextMenu && isRightClickPan(panOnDrag, event.sourceEvent?.button)
);
if (onMove || onViewportChange) {
const flowTransform = eventToFlowTransform(event.transform);
onViewportChange?.(flowTransform);
onMove?.(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
}
});
}
}
}, [userSelectionActive, d3Zoom, onMove, panOnDrag, onPaneContextMenu]);
useEffect(() => {
if (d3Zoom) {
d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
@@ -195,6 +172,9 @@ const ZoomPane = ({
return null;
}
// we need to remember it here, because it's always 0 in the "zoom" event
mouseButton.current = event.sourceEvent.button;
const { onViewportChangeStart } = store.getState();
isZoomingOrPanning.current = true;
@@ -213,6 +193,30 @@ const ZoomPane = ({
}
}, [d3Zoom, onMoveStart]);
useEffect(() => {
if (d3Zoom) {
if (userSelectionActive && !isZoomingOrPanning.current) {
d3Zoom.on('zoom', null);
} else if (!userSelectionActive) {
d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
const { onViewportChange } = store.getState();
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] });
zoomedWithRightMouseButton.current = !!(
onPaneContextMenu && isRightClickPan(panOnDrag, mouseButton.current ?? 0)
);
if (onMove || onViewportChange) {
const flowTransform = eventToFlowTransform(event.transform);
onViewportChange?.(flowTransform);
onMove?.(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
}
});
}
}
}, [userSelectionActive, d3Zoom, onMove, panOnDrag, onPaneContextMenu]);
useEffect(() => {
if (d3Zoom) {
d3Zoom.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
@@ -226,7 +230,7 @@ const ZoomPane = ({
if (
onPaneContextMenu &&
isRightClickPan(panOnDrag, event.sourceEvent?.button) &&
isRightClickPan(panOnDrag, mouseButton.current ?? 0) &&
!zoomedWithRightMouseButton.current
) {
onPaneContextMenu(event.sourceEvent);
+3 -1
View File
@@ -3,7 +3,7 @@ import { createStore } from 'zustand';
import { clampPosition, getDimensions, internalsSymbol } from '../utils';
import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
import { getHandleBounds } from '../components/Nodes/utils';
import { createNodeInternals, fitView, updateNodesAndEdgesSelections } from './utils';
import { createNodeInternals, fitView, updateAbsoluteNodePositions, updateNodesAndEdgesSelections } from './utils';
import initialState from './initialState';
import type {
ReactFlowState,
@@ -99,6 +99,8 @@ const createRFStore = () =>
return res;
}, []);
updateAbsoluteNodePositions(nodeInternals, nodeOrigin);
const nextFitViewOnInitDone =
fitViewOnInitDone ||
(fitViewOnInit && !fitViewOnInitDone && fitView(get, { initial: true, ...fitViewOnInitOptions }));
+37 -31
View File
@@ -20,7 +20,6 @@ type ParentNodes = Record<string, boolean>;
function calculateXYZPosition(
node: Node,
nodeInternals: NodeInternals,
parentNodes: ParentNodes,
result: XYZPosition,
nodeOrigin: NodeOrigin
): XYZPosition {
@@ -33,7 +32,6 @@ function calculateXYZPosition(
return calculateXYZPosition(
parentNode,
nodeInternals,
parentNodes,
{
x: (result.x ?? 0) + parentNodePosition.x,
y: (result.y ?? 0) + parentNodePosition.y,
@@ -43,6 +41,41 @@ function calculateXYZPosition(
);
}
export function updateAbsoluteNodePositions(
nodeInternals: NodeInternals,
nodeOrigin: NodeOrigin,
parentNodes?: ParentNodes
) {
nodeInternals.forEach((node) => {
if (node.parentNode && !nodeInternals.has(node.parentNode)) {
throw new Error(`Parent node ${node.parentNode} not found`);
}
if (node.parentNode || parentNodes?.[node.id]) {
const { x, y, z } = calculateXYZPosition(
node,
nodeInternals,
{
...node.position,
z: node[internalsSymbol]?.z ?? 0,
},
nodeOrigin
);
node.positionAbsolute = {
x,
y,
};
node[internalsSymbol]!.z = z;
if (parentNodes?.[node.id]) {
node[internalsSymbol]!.isParent = true;
}
}
});
}
export function createNodeInternals(
nodes: Node[],
nodeInternals: NodeInternals,
@@ -83,35 +116,7 @@ export function createNodeInternals(
nextNodeInternals.set(node.id, internals);
});
nextNodeInternals.forEach((node) => {
if (node.parentNode && !nextNodeInternals.has(node.parentNode)) {
throw new Error(`Parent node ${node.parentNode} not found`);
}
if (node.parentNode || parentNodes[node.id]) {
const { x, y, z } = calculateXYZPosition(
node,
nextNodeInternals,
parentNodes,
{
...node.position,
z: node[internalsSymbol]?.z ?? 0,
},
nodeOrigin
);
node.positionAbsolute = {
x,
y,
};
node[internalsSymbol]!.z = z;
if (parentNodes[node.id]) {
node[internalsSymbol]!.isParent = true;
}
}
});
updateAbsoluteNodePositions(nextNodeInternals, nodeOrigin, parentNodes);
return nextNodeInternals;
}
@@ -142,6 +147,7 @@ export function fitView(get: StoreApi<ReactFlowState>['getState'], options: Inte
if (nodes.length > 0 && nodesInitialized) {
const bounds = getRectOfNodes(nodes, nodeOrigin);
const [x, y, zoom] = getTransformForBounds(
bounds,
width,