refactor(updates): only trigger dim updates when dim changed
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
|||||||
import initialItems from './initial-elements';
|
import initialItems from './initial-elements';
|
||||||
|
|
||||||
import styles from './layouting.module.css';
|
import styles from './layouting.module.css';
|
||||||
|
import ReactFlowDevTools from '../DevTools/DevTools';
|
||||||
|
|
||||||
const dagreGraph = new dagre.graphlib.Graph();
|
const dagreGraph = new dagre.graphlib.Graph();
|
||||||
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
||||||
@@ -98,6 +99,7 @@ const LayoutFlow = () => {
|
|||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
|
<ReactFlowDevTools />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<Panel position="top-right">
|
<Panel position="top-right">
|
||||||
<button onClick={() => onLayout('TB')}>vertical layout</button>
|
<button onClick={() => onLayout('TB')}>vertical layout</button>
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
## Patch changes
|
## Patch changes
|
||||||
|
|
||||||
- fix hidden nodes
|
- fix hidden nodes
|
||||||
|
- use `direction=ltr` for outer wrapper to support rtl sites
|
||||||
|
- allow pinch zoom even if `preventScrolling=false`
|
||||||
|
- export node and edge change related types
|
||||||
|
|
||||||
## 12.0.0-next.13
|
## 12.0.0-next.13
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
if (targetPosChanged) {
|
if (targetPosChanged) {
|
||||||
prevTargetPosition.current = node.targetPosition;
|
prevTargetPosition.current = node.targetPosition;
|
||||||
}
|
}
|
||||||
store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, force: true }]]));
|
store.getState().updateNodeInternals(new Map([[id, { id, nodeElement: nodeRef.current, force: true }]]));
|
||||||
}
|
}
|
||||||
}, [id, nodeType, node.sourcePosition, node.targetPosition]);
|
}, [id, nodeType, node.sourcePosition, node.targetPosition]);
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { useEffect, useMemo, useRef } from 'react';
|
|||||||
|
|
||||||
import { ReactFlowState } from '../../types';
|
import { ReactFlowState } from '../../types';
|
||||||
import { useStore } from '../../hooks/useStore';
|
import { useStore } from '../../hooks/useStore';
|
||||||
import { NodeDimensionUpdate } from '@xyflow/system';
|
import { InternalNodeUpdate } from '@xyflow/system';
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => s.updateNodeDimensions;
|
const selector = (s: ReactFlowState) => s.updateNodeInternals;
|
||||||
|
|
||||||
export function useResizeObserver() {
|
export function useResizeObserver() {
|
||||||
const updateNodeDimensions = useStore(selector);
|
const updateNodeInternals = useStore(selector);
|
||||||
const resizeObserverRef = useRef<ResizeObserver>();
|
const resizeObserverRef = useRef<ResizeObserver>();
|
||||||
|
|
||||||
const resizeObserver = useMemo(() => {
|
const resizeObserver = useMemo(() => {
|
||||||
@@ -16,7 +16,7 @@ export function useResizeObserver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
const observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||||
const updates = new Map<string, NodeDimensionUpdate>();
|
const updates = new Map<string, InternalNodeUpdate>();
|
||||||
|
|
||||||
entries.forEach((entry: ResizeObserverEntry) => {
|
entries.forEach((entry: ResizeObserverEntry) => {
|
||||||
const id = entry.target.getAttribute('data-id') as string;
|
const id = entry.target.getAttribute('data-id') as string;
|
||||||
@@ -26,7 +26,7 @@ export function useResizeObserver() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
updateNodeDimensions(updates);
|
updateNodeInternals(updates);
|
||||||
});
|
});
|
||||||
|
|
||||||
resizeObserverRef.current = observer;
|
resizeObserverRef.current = observer;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { UpdateNodeInternals, NodeDimensionUpdate } from '@xyflow/system';
|
import type { UpdateNodeInternals, InternalNodeUpdate } from '@xyflow/system';
|
||||||
|
|
||||||
import { useStoreApi } from '../hooks/useStore';
|
import { useStoreApi } from '../hooks/useStore';
|
||||||
|
|
||||||
@@ -13,9 +13,9 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
|
|||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
|
|
||||||
return useCallback<UpdateNodeInternals>((id: string | string[]) => {
|
return useCallback<UpdateNodeInternals>((id: string | string[]) => {
|
||||||
const { domNode, updateNodeDimensions } = store.getState();
|
const { domNode, updateNodeInternals } = store.getState();
|
||||||
const updateIds = Array.isArray(id) ? id : [id];
|
const updateIds = Array.isArray(id) ? id : [id];
|
||||||
const updates = new Map<string, NodeDimensionUpdate>();
|
const updates = new Map<string, InternalNodeUpdate>();
|
||||||
|
|
||||||
updateIds.forEach((updateId) => {
|
updateIds.forEach((updateId) => {
|
||||||
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`) as HTMLDivElement;
|
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`) as HTMLDivElement;
|
||||||
@@ -25,6 +25,6 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
requestAnimationFrame(() => updateNodeDimensions(updates));
|
requestAnimationFrame(() => updateNodeInternals(updates));
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
adoptUserNodes,
|
adoptUserNodes,
|
||||||
updateAbsolutePositions,
|
updateAbsolutePositions,
|
||||||
panBy as panBySystem,
|
panBy as panBySystem,
|
||||||
updateNodeDimensions as updateNodeDimensionsSystem,
|
updateNodeInternals as updateNodeInternalsSystem,
|
||||||
updateConnectionLookup,
|
updateConnectionLookup,
|
||||||
handleParentExpand,
|
handleParentExpand,
|
||||||
NodeChange,
|
NodeChange,
|
||||||
@@ -71,7 +71,7 @@ const createRFStore = ({
|
|||||||
// Every node gets registerd at a ResizeObserver. Whenever a node
|
// Every node gets registerd at a ResizeObserver. Whenever a node
|
||||||
// changes its dimensions, this function is called to measure the
|
// changes its dimensions, this function is called to measure the
|
||||||
// new dimensions and update the nodes.
|
// new dimensions and update the nodes.
|
||||||
updateNodeDimensions: (updates) => {
|
updateNodeInternals: (updates) => {
|
||||||
const {
|
const {
|
||||||
onNodesChange,
|
onNodesChange,
|
||||||
fitView,
|
fitView,
|
||||||
@@ -84,9 +84,9 @@ const createRFStore = ({
|
|||||||
debug,
|
debug,
|
||||||
} = get();
|
} = get();
|
||||||
|
|
||||||
const changes = updateNodeDimensionsSystem(updates, nodeLookup, domNode, nodeOrigin);
|
const { changes, updatedInternals } = updateNodeInternalsSystem(updates, nodeLookup, domNode, nodeOrigin);
|
||||||
|
|
||||||
if (changes.length === 0) {
|
if (!updatedInternals) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
ConnectionMode,
|
ConnectionMode,
|
||||||
type ConnectionStatus,
|
type ConnectionStatus,
|
||||||
type CoordinateExtent,
|
type CoordinateExtent,
|
||||||
type NodeDimensionUpdate,
|
type InternalNodeUpdate,
|
||||||
type UpdateNodePositions,
|
type UpdateNodePositions,
|
||||||
type NodeOrigin,
|
type NodeOrigin,
|
||||||
type OnConnect,
|
type OnConnect,
|
||||||
@@ -154,7 +154,7 @@ export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
|||||||
setNodes: (nodes: NodeType[]) => void;
|
setNodes: (nodes: NodeType[]) => void;
|
||||||
setEdges: (edges: EdgeType[]) => void;
|
setEdges: (edges: EdgeType[]) => void;
|
||||||
setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: EdgeType[]) => void;
|
setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: EdgeType[]) => void;
|
||||||
updateNodeDimensions: (updates: Map<string, NodeDimensionUpdate>) => void;
|
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>) => void;
|
||||||
updateNodePositions: UpdateNodePositions;
|
updateNodePositions: UpdateNodePositions;
|
||||||
resetSelectedElements: () => void;
|
resetSelectedElements: () => void;
|
||||||
unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void;
|
unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
nodeDragThreshold,
|
nodeDragThreshold,
|
||||||
selectNodesOnDrag,
|
selectNodesOnDrag,
|
||||||
handleNodeSelection,
|
handleNodeSelection,
|
||||||
updateNodeDimensions
|
updateNodeInternals
|
||||||
} = store;
|
} = store;
|
||||||
|
|
||||||
let nodeRef: HTMLDivElement;
|
let nodeRef: HTMLDivElement;
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
if (doUpdate) {
|
if (doUpdate) {
|
||||||
requestAnimationFrame(() =>
|
requestAnimationFrame(() =>
|
||||||
updateNodeDimensions(
|
updateNodeInternals(
|
||||||
new Map([
|
new Map([
|
||||||
[
|
[
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
nodesDraggable,
|
nodesDraggable,
|
||||||
nodesConnectable,
|
nodesConnectable,
|
||||||
elementsSelectable,
|
elementsSelectable,
|
||||||
updateNodeDimensions
|
updateNodeInternals
|
||||||
} = useStore();
|
} = useStore();
|
||||||
|
|
||||||
const resizeObserver: ResizeObserver | null =
|
const resizeObserver: ResizeObserver | null =
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
updateNodeDimensions(updates);
|
updateNodeInternals(updates);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useStore } from '$lib/store';
|
|||||||
* @returns function for updating node internals
|
* @returns function for updating node internals
|
||||||
*/
|
*/
|
||||||
export function useUpdateNodeInternals(): UpdateNodeInternals {
|
export function useUpdateNodeInternals(): UpdateNodeInternals {
|
||||||
const { domNode, updateNodeDimensions } = useStore();
|
const { domNode, updateNodeInternals } = useStore();
|
||||||
|
|
||||||
// @todo: do we want to add this to system?
|
// @todo: do we want to add this to system?
|
||||||
const updateInternals = (id: string | string[]) => {
|
const updateInternals = (id: string | string[]) => {
|
||||||
@@ -27,7 +27,7 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
requestAnimationFrame(() => updateNodeDimensions(updates));
|
requestAnimationFrame(() => updateNodeInternals(updates));
|
||||||
};
|
};
|
||||||
|
|
||||||
return updateInternals;
|
return updateInternals;
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import {
|
|||||||
fitView as fitViewUtil,
|
fitView as fitViewUtil,
|
||||||
getElementsToRemove,
|
getElementsToRemove,
|
||||||
panBy as panBySystem,
|
panBy as panBySystem,
|
||||||
updateNodeDimensions as updateNodeDimensionsSystem,
|
updateNodeInternals as updateNodeInternalsSystem,
|
||||||
addEdge as addEdgeUtil,
|
addEdge as addEdgeUtil,
|
||||||
type UpdateNodePositions,
|
type UpdateNodePositions,
|
||||||
type NodeDimensionUpdate,
|
type InternalNodeUpdate,
|
||||||
type ViewportHelperFunctionOptions,
|
type ViewportHelperFunctionOptions,
|
||||||
type Connection,
|
type Connection,
|
||||||
type XYPosition,
|
type XYPosition,
|
||||||
@@ -78,16 +78,16 @@ export function createStore({
|
|||||||
store.nodes.update((nds) => nds);
|
store.nodes.update((nds) => nds);
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateNodeDimensions(updates: Map<string, NodeDimensionUpdate>) {
|
function updateNodeInternals(updates: Map<string, InternalNodeUpdate>) {
|
||||||
const nodeLookup = get(store.nodeLookup);
|
const nodeLookup = get(store.nodeLookup);
|
||||||
const changes = updateNodeDimensionsSystem(
|
const { changes, updatedInternals } = updateNodeInternalsSystem(
|
||||||
updates,
|
updates,
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
get(store.domNode),
|
get(store.domNode),
|
||||||
get(store.nodeOrigin)
|
get(store.nodeOrigin)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!changes) {
|
if (!updatedInternals) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +400,7 @@ export function createStore({
|
|||||||
setEdgeTypes,
|
setEdgeTypes,
|
||||||
addEdge,
|
addEdge,
|
||||||
updateNodePositions,
|
updateNodePositions,
|
||||||
updateNodeDimensions,
|
updateNodeInternals,
|
||||||
zoomIn,
|
zoomIn,
|
||||||
zoomOut,
|
zoomOut,
|
||||||
fitView: (options?: FitViewOptions) => fitView(options),
|
fitView: (options?: FitViewOptions) => fitView(options),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Writable } from 'svelte/store';
|
import type { Writable } from 'svelte/store';
|
||||||
import type {
|
import type {
|
||||||
NodeDimensionUpdate,
|
InternalNodeUpdate,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
ViewportHelperFunctionOptions,
|
ViewportHelperFunctionOptions,
|
||||||
Connection,
|
Connection,
|
||||||
@@ -27,7 +27,7 @@ export type SvelteFlowStoreActions = {
|
|||||||
setTranslateExtent: (extent: CoordinateExtent) => void;
|
setTranslateExtent: (extent: CoordinateExtent) => void;
|
||||||
fitView: (options?: FitViewOptions) => boolean;
|
fitView: (options?: FitViewOptions) => boolean;
|
||||||
updateNodePositions: UpdateNodePositions;
|
updateNodePositions: UpdateNodePositions;
|
||||||
updateNodeDimensions: (updates: Map<string, NodeDimensionUpdate>) => void;
|
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>) => void;
|
||||||
unselectNodesAndEdges: (params?: { nodes?: Node[]; edges?: Edge[] }) => void;
|
unselectNodesAndEdges: (params?: { nodes?: Node[]; edges?: Edge[] }) => void;
|
||||||
addSelectedNodes: (ids: string[]) => void;
|
addSelectedNodes: (ids: string[]) => void;
|
||||||
addSelectedEdges: (ids: string[]) => void;
|
addSelectedEdges: (ids: string[]) => void;
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export type NodeHandleBounds = {
|
|||||||
target: HandleElement[] | null;
|
target: HandleElement[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NodeDimensionUpdate = {
|
export type InternalNodeUpdate = {
|
||||||
id: string;
|
id: string;
|
||||||
nodeElement: HTMLDivElement;
|
nodeElement: HTMLDivElement;
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
NodeBase,
|
NodeBase,
|
||||||
CoordinateExtent,
|
CoordinateExtent,
|
||||||
NodeDimensionUpdate,
|
InternalNodeUpdate,
|
||||||
NodeOrigin,
|
NodeOrigin,
|
||||||
PanZoomInstance,
|
PanZoomInstance,
|
||||||
Transform,
|
Transform,
|
||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
EdgeBase,
|
EdgeBase,
|
||||||
EdgeLookup,
|
EdgeLookup,
|
||||||
InternalNodeBase,
|
InternalNodeBase,
|
||||||
NodeChange,
|
|
||||||
NodeLookup,
|
NodeLookup,
|
||||||
Rect,
|
Rect,
|
||||||
NodeDimensionChange,
|
NodeDimensionChange,
|
||||||
@@ -213,16 +212,17 @@ export function handleParentExpand(
|
|||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateNodeDimensions<NodeType extends InternalNodeBase>(
|
export function updateNodeInternals<NodeType extends InternalNodeBase>(
|
||||||
updates: Map<string, NodeDimensionUpdate>,
|
updates: Map<string, InternalNodeUpdate>,
|
||||||
nodeLookup: Map<string, NodeType>,
|
nodeLookup: Map<string, NodeType>,
|
||||||
domNode: HTMLElement | null,
|
domNode: HTMLElement | null,
|
||||||
nodeOrigin?: NodeOrigin
|
nodeOrigin?: NodeOrigin
|
||||||
): (NodeDimensionChange | NodePositionChange)[] {
|
): { changes: (NodeDimensionChange | NodePositionChange)[]; updatedInternals: boolean } {
|
||||||
const viewportNode = domNode?.querySelector('.xyflow__viewport');
|
const viewportNode = domNode?.querySelector('.xyflow__viewport');
|
||||||
|
let updatedInternals = false;
|
||||||
|
|
||||||
if (!viewportNode) {
|
if (!viewportNode) {
|
||||||
return [];
|
return { changes: [], updatedInternals };
|
||||||
}
|
}
|
||||||
|
|
||||||
const changes: (NodeDimensionChange | NodePositionChange)[] = [];
|
const changes: (NodeDimensionChange | NodePositionChange)[] = [];
|
||||||
@@ -242,24 +242,20 @@ export function updateNodeDimensions<NodeType extends InternalNodeBase>(
|
|||||||
handleBounds: undefined,
|
handleBounds: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
updatedInternals = true;
|
||||||
} else if (node) {
|
} else if (node) {
|
||||||
const dimensions = getDimensions(update.nodeElement);
|
const dimensions = getDimensions(update.nodeElement);
|
||||||
|
const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
|
||||||
const doUpdate = !!(
|
const doUpdate = !!(
|
||||||
dimensions.width &&
|
dimensions.width &&
|
||||||
dimensions.height &&
|
dimensions.height &&
|
||||||
(node.measured?.width !== dimensions.width ||
|
(dimensionChanged || !node.internals.handleBounds || update.force)
|
||||||
node.measured?.height !== dimensions.height ||
|
|
||||||
!node.internals.handleBounds ||
|
|
||||||
update.force)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (doUpdate) {
|
if (doUpdate) {
|
||||||
const newNode = {
|
const newNode = {
|
||||||
...node,
|
...node,
|
||||||
measured: {
|
measured: dimensions,
|
||||||
...node.measured,
|
|
||||||
...dimensions,
|
|
||||||
},
|
|
||||||
internals: {
|
internals: {
|
||||||
...node.internals,
|
...node.internals,
|
||||||
handleBounds: {
|
handleBounds: {
|
||||||
@@ -270,15 +266,18 @@ export function updateNodeDimensions<NodeType extends InternalNodeBase>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
nodeLookup.set(node.id, newNode);
|
nodeLookup.set(node.id, newNode);
|
||||||
|
updatedInternals = true;
|
||||||
|
|
||||||
changes.push({
|
if (dimensionChanged) {
|
||||||
id: newNode.id,
|
changes.push({
|
||||||
type: 'dimensions',
|
id: newNode.id,
|
||||||
dimensions,
|
type: 'dimensions',
|
||||||
});
|
dimensions,
|
||||||
|
});
|
||||||
|
|
||||||
if (newNode.expandParent) {
|
if (newNode.expandParent) {
|
||||||
triggerChangeNodes.push(newNode);
|
triggerChangeNodes.push(newNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,7 +288,7 @@ export function updateNodeDimensions<NodeType extends InternalNodeBase>(
|
|||||||
changes.push(...parentExpandChanges);
|
changes.push(...parentExpandChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
return changes;
|
return { changes, updatedInternals };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function panBy({
|
export function panBy({
|
||||||
|
|||||||
Reference in New Issue
Block a user