feat(resize-rotate-node): implement onResize & onRotate handlers
This commit is contained in:
@@ -1,70 +1,127 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { MoveableEvents } from 'vue3-moveable'
|
import type { MoveableEvents } from 'vue3-moveable'
|
||||||
import Moveable from 'vue3-moveable'
|
import Moveable from 'vue3-moveable'
|
||||||
|
import type { Position } from '@braks/vue-flow'
|
||||||
|
import { Handle, useVueFlow } from '@braks/vue-flow'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
id: string
|
id: string
|
||||||
label: string
|
label: string
|
||||||
|
targetPosition: Position
|
||||||
|
sourcePosition: Position
|
||||||
|
nodeElement: HTMLDivElement
|
||||||
|
data: any
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { viewport, updateNodeDimensions } = useVueFlow()
|
||||||
|
|
||||||
const el = ref()
|
const el = ref()
|
||||||
const initialDimensions = ref()
|
const visible = ref(false)
|
||||||
const translateX = ref(0)
|
|
||||||
const translateY = ref(0)
|
|
||||||
|
|
||||||
const isRight = (i: number[]) => i[0] === 1
|
const frame = ref({
|
||||||
const isLeft = (i: number[]) => i[0] === -1
|
translate: [0, 0],
|
||||||
const isBottom = (i: number[]) => i[1] === 1
|
rotate: 0,
|
||||||
const isTop = (i: number[]) => i[1] === -1
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
initialDimensions.value = el.value.getBoundingClientRect()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const onResize = ({ direction, width, height, target }: MoveableEvents['resize']) => {
|
const onResizeStart = (e: MoveableEvents['resizeStart']) => {
|
||||||
if (isLeft(direction)) {
|
e.setOrigin(['%', '%'])
|
||||||
translateX.value = initialDimensions.value.width - width
|
e.dragStart && e.dragStart.set(frame.value.translate)
|
||||||
}
|
}
|
||||||
if (isTop(direction)) {
|
|
||||||
translateY.value = initialDimensions.value.height - height
|
const onResize = (e: MoveableEvents['resize']) => {
|
||||||
|
const beforeTranslate = e.drag.beforeTranslate
|
||||||
|
|
||||||
|
frame.value.translate = beforeTranslate
|
||||||
|
e.target.style.width = `${e.width}px`
|
||||||
|
e.target.style.height = `${e.height}px`
|
||||||
|
|
||||||
|
let nextTranslation = String(e.target.style.transform)
|
||||||
|
const translateX = `translateX(${beforeTranslate[0]}px)`
|
||||||
|
const translateY = `translateY(${beforeTranslate[1]}px)`
|
||||||
|
|
||||||
|
const hasTranslateX = nextTranslation.match(/translateX\((-?\d+\.\d+?(?:px))\)/)
|
||||||
|
const hasTranslateY = nextTranslation.match(/translateY\((-?\d+\.\d+?(?:px))\)/)
|
||||||
|
|
||||||
|
if (!nextTranslation) return (e.target.style.transform = `${translateX} ${translateY}`)
|
||||||
|
|
||||||
|
if (hasTranslateX) {
|
||||||
|
nextTranslation = nextTranslation.replace(hasTranslateX[0], translateX)
|
||||||
|
} else {
|
||||||
|
nextTranslation += ` ${translateX}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRight(direction) || isLeft(direction)) target.style.width = `${width}px`
|
if (hasTranslateY) {
|
||||||
if (isBottom(direction) || isTop(direction)) target.style.height = `${height}px`
|
nextTranslation = nextTranslation.replace(hasTranslateY[0], translateY)
|
||||||
|
} else {
|
||||||
|
nextTranslation += ` ${translateY}`
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.style.transform = nextTranslation
|
||||||
|
}
|
||||||
|
|
||||||
|
const onRotateStart = (e: MoveableEvents['rotateStart']) => {
|
||||||
|
e.set(frame.value.rotate)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRotate = (e: MoveableEvents['rotate']) => {
|
const onRotate = (e: MoveableEvents['rotate']) => {
|
||||||
console.log('rotate')
|
frame.value.rotate = e.beforeRotate
|
||||||
|
|
||||||
|
const rotation = ` rotate(${e.beforeRotate}deg)`
|
||||||
|
|
||||||
|
if (!e.target.style.transform) {
|
||||||
|
e.target.style.transform = rotation
|
||||||
|
} else {
|
||||||
|
const hasRotation = e.target.style.transform.match(/rotate\(\d+\.\d+?deg\)/)
|
||||||
|
if (hasRotation) {
|
||||||
|
e.target.style.transform = e.target.style.transform.replace(hasRotation[0], rotation)
|
||||||
|
} else {
|
||||||
|
e.target.style.transform += ` ${rotation}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateNodeDimensions([{ id: props.id, nodeElement: props.nodeElement, forceUpdate: true }])
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickOutside(el, () => {
|
||||||
|
visible.value = false
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :data-moveable-id="props.id" :style="data.style" @click="onClick">
|
||||||
ref="el"
|
<Handle type="target" :position="props.targetPosition" />
|
||||||
:data-moveable-id="props.id"
|
|
||||||
:style="{
|
|
||||||
transform: `translateX(${translateX || 0}px) translateY(${translateY || 0}px)`,
|
|
||||||
background: 'rgb(255, 0, 114) none repeat scroll 0% 0%',
|
|
||||||
padding: '20px',
|
|
||||||
borderRadius: '20px',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<slot>
|
<slot>
|
||||||
{{ label }}
|
{{ props.label }}
|
||||||
</slot>
|
</slot>
|
||||||
|
<Handle type="source" :position="props.sourcePosition" />
|
||||||
</div>
|
</div>
|
||||||
<Moveable
|
<Moveable
|
||||||
|
ref="el"
|
||||||
class-name="nodrag"
|
class-name="nodrag"
|
||||||
:target="[`[data-moveable-id='${id}']`]"
|
:style="visible ? '' : 'display: none !important'"
|
||||||
|
:target="[`[data-moveable-id='${props.id}']`]"
|
||||||
:resizable="true"
|
:resizable="true"
|
||||||
:keep-ratio="true"
|
|
||||||
:rotatable="true"
|
:rotatable="true"
|
||||||
|
:throttle-rotate="0"
|
||||||
|
rotation-position="top"
|
||||||
|
:padding="{ left: 0, top: 0, right: 0, bottom: 0 }"
|
||||||
|
:origin="false"
|
||||||
|
:edge="true"
|
||||||
:throttle-resize="1"
|
:throttle-resize="1"
|
||||||
:render-directions="['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']"
|
:render-directions="['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']"
|
||||||
:zoom="1"
|
:zoom="1"
|
||||||
|
@resize-start="onResizeStart"
|
||||||
@resize="onResize"
|
@resize="onResize"
|
||||||
|
@rotate-start="onRotateStart"
|
||||||
@rotate="onRotate"
|
@rotate="onRotate"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user