refactor(resize-rotate): set fixed styles on resize rotate node

This commit is contained in:
braks
2022-08-30 22:16:10 +02:00
committed by Braks
parent dd62165443
commit 5f5dd49ed6
5 changed files with 107 additions and 56 deletions
+3 -4
View File
@@ -29,12 +29,11 @@ const onPaneReady = (store: VueFlowStore) => {
</script>
<template>
<div style="height: 100%; color: black">
{{ extent }}
<div style="height: 100%">
<VueFlow
v-model="elements"
class="vue-flow-basic-example"
snap-to-grid
:snap-to-grid="true"
:snap-grid="[10, 10]"
:prevent-scrolling="false"
:zoom-on-scroll="false"
@@ -64,7 +63,7 @@ const onPaneReady = (store: VueFlowStore) => {
html,
body,
#root {
height: 1024px;
height: 100%;
width: 100%;
margin: 0;
font-family: 'JetBrains Mono', monospace;
@@ -11,10 +11,6 @@ export default [
x: 0,
y: 0,
},
dragHandle: `[data-moveable-id='1']`,
style: {
cursor: 'default',
},
data: {
style: {
background: 'rgb(255, 0, 114) none repeat scroll 0% 0%',
@@ -1,8 +1,9 @@
<script lang="ts" setup>
import type { MoveableEvents, MoveableProps } from 'vue3-moveable'
import type { MoveableProps } from 'vue3-moveable'
import Moveable from 'vue3-moveable'
import type { Position } from '@braks/vue-flow'
import { Handle, useVueFlow } from '@braks/vue-flow'
import { useMoveable } from './utils'
const props = defineProps<{
id: string
@@ -15,43 +16,13 @@ const props = defineProps<{
const emits = defineEmits(['updateNodeInternals'])
const {
viewport,
updateNodeDimensions,
onPaneClick,
onPaneScroll,
onPaneContextMenu,
getNode,
onNodeClick,
onNodeDragStart,
snapGrid,
snapToGrid,
} = useVueFlow()
const { findNode, onPaneClick, onNodeClick, onNodeDragStart, snapGrid, snapToGrid } = useVueFlow()
const el = ref()
const visible = ref(false)
const frame = {
rotate: 0,
}
const onResize = (e: MoveableEvents['resize']) => {
e.target.style.width = `${e.width}px`
e.target.style.height = `${e.height}px`
e.target.style.left = `${e.drag.left}px`
e.target.style.top = `${e.drag.top}px`
}
const onRotateStart = (e: MoveableEvents['rotateStart']) => {
e.set(frame.rotate)
}
const onRotate = (e: MoveableEvents['rotate']) => {
frame.rotate = e.beforeRotate
e.target.style.transform = `rotate(${e.beforeRotate}deg)`
emits('updateNodeInternals')
}
const { onRotateStart, onRotate, onResizeStart, onResize } = useMoveable(props.id, emits)
const toggleVisibility = (val?: boolean) => {
visible.value = val ?? !visible.value
@@ -66,6 +37,21 @@ onNodeDragStart(({ node }) => {
})
onPaneClick(() => toggleVisibility(false))
onBeforeMount(() => {
const node = findNode(props.id)!
node.dragHandle = `[data-moveable-id='${props.id}']`
const previousStyle = node.style
node.style = () => {
return {
...previousStyle,
pointerEvents: 'none',
cursor: 'default',
}
}
})
</script>
<script lang="ts">
@@ -75,15 +61,7 @@ export default {
</script>
<template>
<div
ref="el"
:data-moveable-id="props.id"
:style="{
cursor: 'grab',
...data.style,
}"
style="position: relative"
>
<div ref="el" style="cursor: grab; pointer-events: all" :data-moveable-id="props.id" :style="data.style">
<Handle type="target" :position="props.targetPosition" />
<slot>
@@ -94,13 +72,12 @@ export default {
</div>
<Moveable
v-if="visible"
v-bind="props.moveableProps"
class-name="nodrag"
:target="[`[data-moveable-id='${props.id}']`]"
style="pointer-events: all"
:target="visible ? el : undefined"
:resizable="true"
:rotatable="true"
:draggable="true"
:snappable="snapToGrid"
:snap-element="snapToGrid"
:snap-gap="snapToGrid"
@@ -108,17 +85,17 @@ export default {
:snap-digit="snapGrid[0]"
:snap-treshold="snapGrid[0]"
:snap-grid-width="snapGrid[0]"
:snap-grid-height="snapGrid[0]"
rotation-position="top"
:snap-grid-height="snapGrid[1]"
:padding="{ left: 0, top: 0, right: 0, bottom: 0 }"
:origin="false"
:edge="true"
:start-drag-rotate="0"
:throttle-drag-rotate="0"
:throttle-resize="1"
:render-directions="['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']"
:zoom="1"
@resize-start="onResizeStart"
@resize="onResize"
@rotate-start="onRotateStart"
@rotate="onRotate"
/>
</template>
@@ -0,0 +1,75 @@
import type { Able, MoveableEvents, MoveableManagerInterface } from 'vue3-moveable'
export function useMoveable(id: string, emits: (event: 'updateNodeInternals') => void) {
const frame = reactive({
translate: [0, 0],
rotate: 0,
})
const onResizeStart = (e: MoveableEvents['resizeStart']) => {
e.setOrigin(['%', '%'])
if (e.dragStart) {
e.dragStart.set(frame.translate)
}
}
const onResize = (e: MoveableEvents['resize']) => {
frame.translate = e.drag.beforeTranslate
e.target.style.width = `${e.width}px`
e.target.style.height = `${e.height}px`
e.target.style.transform = `translate(${frame.translate[0]}px, ${frame.translate[1]}px)` + ` rotate(${frame.rotate}deg)`
}
const onRotateStart = (e: MoveableEvents['rotateStart']) => {
e.set(frame.rotate)
}
const onRotate = (e: MoveableEvents['rotate']) => {
frame.rotate = e.beforeRotate
e.target.style.transform = `translate(${frame.translate[0]}px, ${frame.translate[1]}px)` + ` rotate(${frame.rotate}deg)`
emits('updateNodeInternals')
}
return {
onResizeStart,
onResize,
onRotateStart,
onRotate,
}
}
export const DimensionViewable = {
name: 'dimensionViewable',
props: {},
events: {},
render(moveable: MoveableManagerInterface<any, any>, renderer) {
const rect = moveable.getRect()
// Add key (required)
// Add class prefix moveable-(required)
return renderer.createElement(
'div',
{
key: 'dimension-viewer',
class: 'moveable-dimension',
style: {
position: 'absolute',
left: `${rect.width / 2}px`,
top: `${rect.height + 20}px`,
background: '#4af',
borderRadius: '2px',
padding: '2px 4px',
color: 'white',
fontSize: '13px',
whiteSpace: 'nowrap',
fontWeight: 'bold',
willChange: 'transform',
transform: 'translate(-50%, 0px)',
},
},
`${Math.round(rect.offsetWidth)} x ${Math.round(rect.offsetHeight)}`,
)
},
} as Able<{}, {}>
@@ -154,16 +154,20 @@ export default {
<slot :name="`node-${nodeName}`" />
</template>
</template>
<template #edges>
<template v-for="edgeName of Object.keys(getEdgeTypes)">
<slot :name="`edge-${edgeName}`" />
</template>
</template>
<template #connection-name>
<slot name="connection-line" />
</template>
<slot name="zoom-pane" />
</Viewport>
<slot />
</div>
</template>