refactor(node-resizer): add auto-scale prop & scale resize controls with zoom level (#1872)

* refactor(node-resizer): add auto-scale prop & scale resize controls with zoom

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>

* chore(changeset): add

---------

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Braks
2025-06-12 14:01:30 +02:00
parent e7dec135e1
commit f4e139f1bc
5 changed files with 35 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@vue-flow/node-resizer": minor
---
Add auto-scale prop to node resizer (default `true`) that forces node resizer controls to scale with the viewport zoom level.
+4 -1
View File
@@ -8,6 +8,7 @@ import { ResizeControlVariant } from './types'
const props = withDefaults(defineProps<NodeResizerProps>(), { const props = withDefaults(defineProps<NodeResizerProps>(), {
isVisible: true, isVisible: true,
autoScale: true,
}) })
const emits = defineEmits<NodeResizerEmits>() const emits = defineEmits<NodeResizerEmits>()
@@ -92,13 +93,14 @@ export default {
:node-id="nodeId" :node-id="nodeId"
:position="c" :position="c"
:variant="ResizeControlVariant.Line" :variant="ResizeControlVariant.Line"
:keep-aspect-ratio="keepAspectRatio"
:color="color" :color="color"
:min-width="minWidth" :min-width="minWidth"
:min-height="minHeight" :min-height="minHeight"
:max-width="maxWidth" :max-width="maxWidth"
:max-height="maxHeight" :max-height="maxHeight"
:should-resize="shouldResize" :should-resize="shouldResize"
:keep-aspect-ratio="keepAspectRatio"
:auto-scale="autoScale"
@resize-start="emits('resizeStart', $event)" @resize-start="emits('resizeStart', $event)"
@resize="emits('resize', $event)" @resize="emits('resize', $event)"
@resize-end="emits('resizeEnd', $event)" @resize-end="emits('resizeEnd', $event)"
@@ -118,6 +120,7 @@ export default {
:max-height="maxHeight" :max-height="maxHeight"
:should-resize="shouldResize" :should-resize="shouldResize"
:keep-aspect-ratio="keepAspectRatio" :keep-aspect-ratio="keepAspectRatio"
:auto-scale="autoScale"
@resize-start="emits('resizeStart', $event)" @resize-start="emits('resizeStart', $event)"
@resize="emits('resize', $event)" @resize="emits('resize', $event)"
@resize-end="emits('resizeEnd', $event)" @resize-end="emits('resizeEnd', $event)"
+12 -7
View File
@@ -3,8 +3,9 @@ import type { NodeChange, NodeDimensionChange, NodePositionChange } from '@vue-f
import { clamp, useGetPointerPosition, useVueFlow } from '@vue-flow/core' import { clamp, useGetPointerPosition, useVueFlow } from '@vue-flow/core'
import { select } from 'd3-selection' import { select } from 'd3-selection'
import { drag } from 'd3-drag' import { drag } from 'd3-drag'
import { ref, toRef, watchEffect } from 'vue' import { computed, ref, toRef, watchEffect } from 'vue'
import type { NodeResizerEmits, ResizeControlProps, ResizeControlVariant, ResizeDragEvent } from './types' import type { NodeResizerEmits, ResizeControlProps, ResizeDragEvent } from './types'
import { ResizeControlVariant } from './types'
import { DefaultPositions, StylingProperty, getDirection } from './utils' import { DefaultPositions, StylingProperty, getDirection } from './utils'
const props = withDefaults(defineProps<ResizeControlProps>(), { const props = withDefaults(defineProps<ResizeControlProps>(), {
@@ -14,6 +15,7 @@ const props = withDefaults(defineProps<ResizeControlProps>(), {
maxWidth: Number.MAX_VALUE, maxWidth: Number.MAX_VALUE,
maxHeight: Number.MAX_VALUE, maxHeight: Number.MAX_VALUE,
keepAspectRatio: false, keepAspectRatio: false,
autoScale: true,
}) })
const emits = defineEmits<NodeResizerEmits>() const emits = defineEmits<NodeResizerEmits>()
@@ -27,7 +29,7 @@ const initStartValues = {
aspectRatio: 1, aspectRatio: 1,
} }
const { findNode, emits: triggerEmits } = useVueFlow() const { findNode, emits: triggerEmits, viewport, noDragClassName } = useVueFlow()
const getPointerPosition = useGetPointerPosition() const getPointerPosition = useGetPointerPosition()
@@ -39,7 +41,7 @@ let prevValues: typeof initPrevValues = initPrevValues
const controlPosition = toRef(() => props.position ?? DefaultPositions[props.variant]) const controlPosition = toRef(() => props.position ?? DefaultPositions[props.variant])
const positionClassNames = toRef(() => controlPosition.value.split('-')) const positionClassNames = computed(() => controlPosition.value.split('-'))
const controlStyle = toRef(() => (props.color ? { [StylingProperty[props.variant]]: props.color } : {})) const controlStyle = toRef(() => (props.color ? { [StylingProperty[props.variant]]: props.color } : {}))
@@ -237,9 +239,12 @@ export default {
<template> <template>
<div <div
ref="resizeControlRef" ref="resizeControlRef"
class="vue-flow__resize-control nodrag" class="vue-flow__resize-control"
:class="[...positionClassNames, variant]" :class="[...positionClassNames, variant, noDragClassName]"
:style="controlStyle" :style="{
...controlStyle,
scale: variant === ResizeControlVariant.Handle ? `${Math.max(1 / viewport.zoom, 1)}` : undefined,
}"
> >
<slot /> <slot />
</div> </div>
+2 -2
View File
@@ -24,8 +24,8 @@
/* handle styles */ /* handle styles */
.vue-flow__resize-control.handle { .vue-flow__resize-control.handle {
width: 4px; width: 5px;
height: 4px; height: 5px;
border: 1px solid #fff; border: 1px solid #fff;
border-radius: 1px; border-radius: 1px;
background-color: #3367d9; background-color: #3367d9;
+12 -2
View File
@@ -45,6 +45,11 @@ export interface NodeResizerProps {
maxHeight?: number maxHeight?: number
shouldResize?: ShouldResize shouldResize?: ShouldResize
keepAspectRatio?: boolean | number keepAspectRatio?: boolean | number
/**
* Scale the controls with the zoom level.
* @default true
*/
autoScale?: boolean
} }
export interface NodeResizerEmits { export interface NodeResizerEmits {
@@ -62,8 +67,8 @@ export enum ResizeControlVariant {
Handle = 'handle', Handle = 'handle',
} }
export interface ResizeControlProps { export interface ResizeControlProps extends NodeResizerProps {
nodeId?: string | null nodeId?: string
color?: string color?: string
minWidth?: number minWidth?: number
minHeight?: number minHeight?: number
@@ -73,6 +78,11 @@ export interface ResizeControlProps {
variant?: ResizeControlVariant variant?: ResizeControlVariant
shouldResize?: ShouldResize shouldResize?: ShouldResize
keepAspectRatio?: boolean | number keepAspectRatio?: boolean | number
/**
* Scale the controls with the zoom level.
* @default true
*/
autoScale?: boolean
} }
export interface ResizeControlLineProps extends ResizeControlProps { export interface ResizeControlLineProps extends ResizeControlProps {