Merge pull request #5528 from xyflow/resizer-update-keep-aspect
NodeResizer: Make parameters dynamic
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/system': patch
|
||||||
|
'@xyflow/react': patch
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Let NodeResizer props change during ongoing resize
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { memo, FC } from 'react';
|
import { memo, FC } from 'react';
|
||||||
import { Handle, Position, NodeProps, NodeResizer } from '@xyflow/react';
|
import { Handle, Position, NodeProps, NodeResizer, useKeyPress } from '@xyflow/react';
|
||||||
|
|
||||||
const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
|
const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
|
||||||
|
const keepAspectRatio = useKeyPress('k');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NodeResizer
|
<NodeResizer
|
||||||
@@ -14,7 +16,7 @@ const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
|
|||||||
onResizeStart={data.onResizeStart ?? undefined}
|
onResizeStart={data.onResizeStart ?? undefined}
|
||||||
onResize={data.onResize ?? undefined}
|
onResize={data.onResize ?? undefined}
|
||||||
onResizeEnd={data.onResizeEnd ?? undefined}
|
onResizeEnd={data.onResizeEnd ?? undefined}
|
||||||
keepAspectRatio={data.keepAspectRatio ?? undefined}
|
keepAspectRatio={keepAspectRatio || (data.keepAspectRatio ?? undefined)}
|
||||||
/>
|
/>
|
||||||
<Handle type="target" position={Position.Left} />
|
<Handle type="target" position={Position.Left} />
|
||||||
<div>{data.label}</div>
|
<div>{data.label}</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
import type { ResizeNode } from './types';
|
import type { ResizeNode } from './types';
|
||||||
|
import { store } from './store.svelte';
|
||||||
|
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
defaultResizer: DefaultResizer,
|
defaultResizer: DefaultResizer,
|
||||||
@@ -139,6 +140,15 @@
|
|||||||
let snapToGrid = $state(false);
|
let snapToGrid = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window
|
||||||
|
on:keydown={(e) => {
|
||||||
|
if (e.key === 'k') store.keepAspectRatio = true;
|
||||||
|
}}
|
||||||
|
on:keyup={(e) => {
|
||||||
|
if (e.key === 'k') store.keepAspectRatio = false;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<SvelteFlow
|
<SvelteFlow
|
||||||
bind:nodes
|
bind:nodes
|
||||||
bind:edges
|
bind:edges
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Handle, Position, type NodeProps, NodeResizeControl, type Node } from '@xyflow/svelte';
|
import { Handle, Position, type NodeProps, NodeResizeControl, type Node } from '@xyflow/svelte';
|
||||||
import type { ResizeNode } from './types';
|
import type { ResizeNode } from './types';
|
||||||
|
import { store } from './store.svelte';
|
||||||
|
|
||||||
let { data }: NodeProps<ResizeNode> = $props();
|
let { data }: NodeProps<ResizeNode> = $props();
|
||||||
</script>
|
</script>
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
onResizeStart={data.onResizeStart ?? undefined}
|
onResizeStart={data.onResizeStart ?? undefined}
|
||||||
onResize={data.onResize ?? undefined}
|
onResize={data.onResize ?? undefined}
|
||||||
onResizeEnd={data.onResizeEnd ?? undefined}
|
onResizeEnd={data.onResizeEnd ?? undefined}
|
||||||
keepAspectRatio={data.keepAspectRatio ?? undefined}
|
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
|
||||||
style="background: transparent; border: none;"
|
style="background: transparent; border: none;"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
import { Handle, NodeResizer, Position, type NodeProps } from '@xyflow/svelte';
|
import { Handle, NodeResizer, Position, type NodeProps } from '@xyflow/svelte';
|
||||||
import type { ResizeNode } from './types';
|
import type { ResizeNode } from './types';
|
||||||
|
|
||||||
|
import { store } from './store.svelte';
|
||||||
|
|
||||||
let { data, selected }: NodeProps<ResizeNode> = $props();
|
let { data, selected }: NodeProps<ResizeNode> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -15,7 +17,7 @@
|
|||||||
onResizeStart={data.onResizeStart ?? undefined}
|
onResizeStart={data.onResizeStart ?? undefined}
|
||||||
onResize={data.onResize ?? undefined}
|
onResize={data.onResize ?? undefined}
|
||||||
onResizeEnd={data.onResizeEnd ?? undefined}
|
onResizeEnd={data.onResizeEnd ?? undefined}
|
||||||
keepAspectRatio={data.keepAspectRatio ?? undefined}
|
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
|
||||||
/>
|
/>
|
||||||
<Handle type="target" position={Position.Left} />
|
<Handle type="target" position={Position.Left} />
|
||||||
<div>{data.label}</div>
|
<div>{data.label}</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
||||||
import type { ResizeNode } from './types';
|
import type { ResizeNode } from './types';
|
||||||
|
import { store } from './store.svelte';
|
||||||
|
|
||||||
let { data }: NodeProps<ResizeNode> = $props();
|
let { data }: NodeProps<ResizeNode> = $props();
|
||||||
</script>
|
</script>
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
onResizeStart={data.onResizeStart ?? undefined}
|
onResizeStart={data.onResizeStart ?? undefined}
|
||||||
onResize={data.onResize ?? undefined}
|
onResize={data.onResize ?? undefined}
|
||||||
onResizeEnd={data.onResizeEnd ?? undefined}
|
onResizeEnd={data.onResizeEnd ?? undefined}
|
||||||
keepAspectRatio={data.keepAspectRatio ?? undefined}
|
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
|
||||||
color="red"
|
color="red"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
||||||
import type { ResizeNode } from './types';
|
import type { ResizeNode } from './types';
|
||||||
|
import { store } from './store.svelte';
|
||||||
|
|
||||||
let { data }: NodeProps<ResizeNode> = $props();
|
let { data }: NodeProps<ResizeNode> = $props();
|
||||||
</script>
|
</script>
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
onResizeStart={data.onResizeStart ?? undefined}
|
onResizeStart={data.onResizeStart ?? undefined}
|
||||||
onResize={data.onResize ?? undefined}
|
onResize={data.onResize ?? undefined}
|
||||||
onResizeEnd={data.onResizeEnd ?? undefined}
|
onResizeEnd={data.onResizeEnd ?? undefined}
|
||||||
keepAspectRatio={data.keepAspectRatio ?? undefined}
|
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
|
||||||
color="red"
|
color="red"
|
||||||
position={Position.Top}
|
position={Position.Top}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
function createStore() {
|
||||||
|
let keepAspectRatio = $state(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
get keepAspectRatio() {
|
||||||
|
return keepAspectRatio;
|
||||||
|
},
|
||||||
|
set keepAspectRatio(value: boolean) {
|
||||||
|
keepAspectRatio = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const store = createStore();
|
||||||
@@ -104,6 +104,18 @@ function nodeToChildExtent(child: NodeBase, parent: NodeBase, nodeOrigin: NodeOr
|
|||||||
export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: XYResizerParams): XYResizerInstance {
|
export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: XYResizerParams): XYResizerInstance {
|
||||||
const selection = select(domNode);
|
const selection = select(domNode);
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
controlDirection: getControlDirection('bottom-right'),
|
||||||
|
boundaries: {
|
||||||
|
minWidth: 0,
|
||||||
|
minHeight: 0,
|
||||||
|
maxWidth: Number.MAX_VALUE,
|
||||||
|
maxHeight: Number.MAX_VALUE,
|
||||||
|
},
|
||||||
|
resizeDirection: undefined as ResizeControlDirection | undefined,
|
||||||
|
keepAspectRatio: false,
|
||||||
|
};
|
||||||
|
|
||||||
function update({
|
function update({
|
||||||
controlPosition,
|
controlPosition,
|
||||||
boundaries,
|
boundaries,
|
||||||
@@ -117,7 +129,12 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
let prevValues = { ...initPrevValues };
|
let prevValues = { ...initPrevValues };
|
||||||
let startValues = { ...initStartValues };
|
let startValues = { ...initStartValues };
|
||||||
|
|
||||||
const controlDirection = getControlDirection(controlPosition);
|
params = {
|
||||||
|
boundaries,
|
||||||
|
resizeDirection,
|
||||||
|
keepAspectRatio,
|
||||||
|
controlDirection: getControlDirection(controlPosition),
|
||||||
|
};
|
||||||
|
|
||||||
let node: InternalNodeBase | undefined = undefined;
|
let node: InternalNodeBase | undefined = undefined;
|
||||||
let containerBounds: DOMRect | null = null;
|
let containerBounds: DOMRect | null = null;
|
||||||
@@ -212,16 +229,17 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
if (!node) {
|
if (!node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues;
|
const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues;
|
||||||
const change: XYResizerChange = {};
|
const change: XYResizerChange = {};
|
||||||
const nodeOrigin = node.origin ?? storeNodeOrigin;
|
const nodeOrigin = node.origin ?? storeNodeOrigin;
|
||||||
|
|
||||||
const { width, height, x, y } = getDimensionsAfterResize(
|
const { width, height, x, y } = getDimensionsAfterResize(
|
||||||
startValues,
|
startValues,
|
||||||
controlDirection,
|
params.controlDirection,
|
||||||
pointerPosition,
|
pointerPosition,
|
||||||
boundaries,
|
params.boundaries,
|
||||||
keepAspectRatio,
|
params.keepAspectRatio,
|
||||||
nodeOrigin,
|
nodeOrigin,
|
||||||
parentExtent,
|
parentExtent,
|
||||||
childExtent
|
childExtent
|
||||||
@@ -264,9 +282,13 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
|
|
||||||
if (isWidthChange || isHeightChange) {
|
if (isWidthChange || isHeightChange) {
|
||||||
change.width =
|
change.width =
|
||||||
isWidthChange && (!resizeDirection || resizeDirection === 'horizontal') ? width : prevValues.width;
|
isWidthChange && (!params.resizeDirection || params.resizeDirection === 'horizontal')
|
||||||
|
? width
|
||||||
|
: prevValues.width;
|
||||||
change.height =
|
change.height =
|
||||||
isHeightChange && (!resizeDirection || resizeDirection === 'vertical') ? height : prevValues.height;
|
isHeightChange && (!params.resizeDirection || params.resizeDirection === 'vertical')
|
||||||
|
? height
|
||||||
|
: prevValues.height;
|
||||||
prevValues.width = change.width;
|
prevValues.width = change.width;
|
||||||
prevValues.height = change.height;
|
prevValues.height = change.height;
|
||||||
}
|
}
|
||||||
@@ -291,8 +313,8 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
prevWidth,
|
prevWidth,
|
||||||
height: prevValues.height,
|
height: prevValues.height,
|
||||||
prevHeight,
|
prevHeight,
|
||||||
affectsX: controlDirection.affectsX,
|
affectsX: params.controlDirection.affectsX,
|
||||||
affectsY: controlDirection.affectsY,
|
affectsY: params.controlDirection.affectsY,
|
||||||
});
|
});
|
||||||
|
|
||||||
const nextValues = { ...prevValues, direction };
|
const nextValues = { ...prevValues, direction };
|
||||||
|
|||||||
Reference in New Issue
Block a user