feat(node-resizer): add maxHeight and maxWidth props

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
braks
2023-03-07 20:43:31 +01:00
committed by Braks
parent f6491d13cf
commit afc29db489
4 changed files with 61 additions and 35 deletions

View File

@@ -7,7 +7,7 @@ defineProps(['label'])
</script>
<template>
<NodeResizer min-width="100" min-height="30" />
<NodeResizer min-width="100" min-height="30" max-height="200" max-width="200" keep-aspect-ratio />
<Handle type="target" :position="Position.Left" />
<div style="padding: 10px">{{ label }}</div>

View File

@@ -40,6 +40,8 @@ export default {
:color="color"
:min-width="minWidth"
:min-height="minHeight"
:max-width="maxWidth"
:max-height="maxHeight"
:should-resize="shouldResize"
@resize-start="emits('resizeStart', $event)"
@resize="emits('resize', $event)"
@@ -56,6 +58,8 @@ export default {
:color="color"
:min-width="minWidth"
:min-height="minHeight"
:max-width="maxWidth"
:max-height="maxHeight"
:should-resize="shouldResize"
:keep-aspect-ratio="keepAspectRatio"
@resize-start="emits('resizeStart', $event)"

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { NodeChange, NodeDimensionChange, NodePositionChange } from '@vue-flow/core'
import { NodeIdInjection, useGetPointerPosition, useVueFlow } from '@vue-flow/core'
import { NodeIdInjection, clamp, useGetPointerPosition, useVueFlow } from '@vue-flow/core'
import { select } from 'd3-selection'
import { drag } from 'd3-drag'
import type { OnResize, OnResizeStart, ResizeControlProps, ResizeDragEvent } from './types'
@@ -11,6 +11,9 @@ const props = withDefaults(defineProps<ResizeControlProps>(), {
variant: 'handle' as ResizeControlVariant,
minWidth: 10,
minHeight: 10,
maxWidth: Number.MAX_VALUE,
maxHeight: Number.MAX_VALUE,
keepAspectRatio: false,
})
const emits = defineEmits<{
@@ -25,33 +28,25 @@ const initStartValues = {
...initPrevValues,
pointerX: 0,
pointerY: 0,
aspectRatio: 1,
}
const { findNode, emits: triggerEmits } = useVueFlow()
const getPointerPosition = useGetPointerPosition()
const contextNodeId = inject(NodeIdInjection, null)
const resizeControlRef = ref<HTMLDivElement>()
const id = computed(() => (typeof props.nodeId === 'string' ? props.nodeId : contextNodeId))
const { findNode, emits: triggerEmits } = useVueFlow()
const startValues = ref<typeof initStartValues>(initStartValues)
const prevValues = ref<typeof initPrevValues>(initPrevValues)
const aspectRatio = computed(() => {
if (props.keepAspectRatio === true && startValues.value.width && startValues.value.height) {
return startValues.value.width / startValues.value.height
}
const id = computed(() => (typeof props.nodeId === 'string' ? props.nodeId : contextNodeId))
if (typeof props.keepAspectRatio == 'number') {
return props.keepAspectRatio
}
return undefined
})
const getPointerPosition = useGetPointerPosition()
const defaultPosition = computed(() => (props.variant === ResizeControlVariant.Line ? 'right' : 'bottom-right'))
const controlPosition = computed(() => props.position ?? defaultPosition.value)
watchEffect((onCleanup) => {
@@ -61,6 +56,11 @@ watchEffect((onCleanup) => {
const selection = select(resizeControlRef.value)
const enableX = controlPosition.value.includes('right') || controlPosition.value.includes('left')
const enableY = controlPosition.value.includes('bottom') || controlPosition.value.includes('top')
const invertX = controlPosition.value.includes('left')
const invertY = controlPosition.value.includes('top')
const dragHandler = drag<HTMLDivElement, unknown>()
.on('start', (event: ResizeDragEvent) => {
const node = findNode(id.value!)
@@ -77,6 +77,7 @@ watchEffect((onCleanup) => {
...prevValues.value,
pointerX: xSnapped,
pointerY: ySnapped,
aspectRatio: prevValues.value.width / prevValues.value.height,
}
emits('resizeStart', { event, params: prevValues.value })
@@ -84,10 +85,6 @@ watchEffect((onCleanup) => {
.on('drag', (event: ResizeDragEvent) => {
const { xSnapped, ySnapped } = getPointerPosition(event)
const node = findNode(id.value!)
const enableX = controlPosition.value.includes('right') || controlPosition.value.includes('left')
const enableY = controlPosition.value.includes('bottom') || controlPosition.value.includes('top')
const invertX = controlPosition.value.includes('left')
const invertY = controlPosition.value.includes('top')
if (node) {
const changes: NodeChange[] = []
@@ -98,6 +95,7 @@ watchEffect((onCleanup) => {
height: startHeight,
x: startNodeX,
y: startNodeY,
aspectRatio: startAspectRatio,
} = startValues.value
const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues.value
@@ -105,20 +103,38 @@ watchEffect((onCleanup) => {
const distX = Math.floor(enableX ? xSnapped - startX : 0)
const distY = Math.floor(enableY ? ySnapped - startY : 0)
let width = Math.max(startWidth + (invertX ? -distX : distX), props.minWidth)
let height = Math.max(startHeight + (invertY ? -distY : distY), props.minHeight)
let width = clamp(startWidth + (invertX ? -distX : distX), props.minWidth, props.maxWidth)
let height = clamp(startHeight + (invertY ? -distY : distY), props.minHeight, props.maxHeight)
if (aspectRatio.value) {
const currentAspectRatio = width / height
if (currentAspectRatio !== aspectRatio.value) {
const newWidth = height * aspectRatio.value
const newHeight = width / aspectRatio.value
if (props.keepAspectRatio) {
const nextAspectRatio = width / height
let aspectRatio = startAspectRatio
if (distX > distY) {
height = Math.max(newHeight, props.minHeight)
} else {
width = Math.max(newWidth, props.minWidth)
}
if (typeof props.keepAspectRatio === 'number' && nextAspectRatio !== props.keepAspectRatio) {
aspectRatio = props.keepAspectRatio
}
const isDiagonal = enableX && enableY
const isHorizontal = enableX && !enableY
const isVertical = enableY && !enableX
width = (nextAspectRatio <= aspectRatio && isDiagonal) || isVertical ? height * aspectRatio : width
height = (nextAspectRatio > aspectRatio && isDiagonal) || isHorizontal ? width / aspectRatio : height
if (width >= props.maxWidth) {
width = props.maxWidth
height = props.maxWidth / aspectRatio
} else if (width <= props.minWidth) {
width = props.minWidth
height = props.minWidth / aspectRatio
}
if (height >= props.maxHeight) {
height = props.maxHeight
width = props.maxHeight * aspectRatio
} else if (height <= props.minHeight) {
height = props.minHeight
width = props.minHeight * aspectRatio
}
}

View File

@@ -41,6 +41,8 @@ export interface NodeResizerProps {
isVisible?: boolean
minWidth?: number
minHeight?: number
maxWidth?: number
maxHeight?: number
shouldResize?: ShouldResize
keepAspectRatio?: boolean | number
}
@@ -65,17 +67,21 @@ export interface ResizeControlProps {
color?: string
minWidth?: number
minHeight?: number
maxWidth?: number
maxHeight?: number
position?: ControlPosition
variant?: ResizeControlVariant
shouldResize?: ShouldResize
keepAspectRatio?: boolean | number
}
export interface ResizeControlLineProps {
export interface ResizeControlLineProps extends ResizeControlProps {
nodeId?: string
color?: string
minWidth?: number
minHeight?: number
maxWidth?: number
maxHeight?: number
variant?: ResizeControlVariant
position?: ControlLinePosition
keepAspectRatio?: boolean | number