feat(node-toolbar): add align prop
This commit is contained in:
@@ -4,43 +4,58 @@ import type { GraphNode, Rect, ViewportTransform } from '@vue-flow/core'
|
|||||||
import { NodeIdInjection, Position, getRectOfNodes, useVueFlow } from '@vue-flow/core'
|
import { NodeIdInjection, Position, getRectOfNodes, useVueFlow } from '@vue-flow/core'
|
||||||
|
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties } from 'vue'
|
||||||
import type { NodeToolbarProps } from './types'
|
import type { Align, NodeToolbarProps } from './types'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<NodeToolbarProps>(), {
|
const props = withDefaults(defineProps<NodeToolbarProps>(), {
|
||||||
position: Position.Top,
|
position: Position.Top,
|
||||||
offset: 10,
|
offset: 10,
|
||||||
|
align: 'center',
|
||||||
})
|
})
|
||||||
|
|
||||||
const contextNodeId = inject(NodeIdInjection, null)
|
const contextNodeId = inject(NodeIdInjection, null)
|
||||||
|
|
||||||
const { viewportRef, viewport, getSelectedNodes, findNode } = useVueFlow()
|
const { viewportRef, viewport, getSelectedNodes, findNode } = useVueFlow()
|
||||||
|
|
||||||
function getTransform(nodeRect: Rect, transform: ViewportTransform, position: Position, offset: number): string {
|
function getTransform(nodeRect: Rect, transform: ViewportTransform, position: Position, offset: number, align: Align): string {
|
||||||
let xPos = (nodeRect.x + nodeRect.width / 2) * transform.zoom + transform.x
|
let alignmentOffset = 0.5
|
||||||
let yPos = nodeRect.y * transform.zoom + transform.y - offset
|
|
||||||
let xShift = -50
|
if (align === 'start') {
|
||||||
let yShift = -100
|
alignmentOffset = 0
|
||||||
|
} else if (align === 'end') {
|
||||||
|
alignmentOffset = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// position === Position.Top
|
||||||
|
// we set the x any y position of the toolbar based on the nodes position
|
||||||
|
let pos = [
|
||||||
|
(nodeRect.x + nodeRect.width * alignmentOffset) * transform.zoom + transform.x,
|
||||||
|
nodeRect.y * transform.zoom + transform.y - offset,
|
||||||
|
]
|
||||||
|
// and then shift it based on the alignment. The shift values are in %.
|
||||||
|
let shift = [-100 * alignmentOffset, -100]
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case Position.Right:
|
case Position.Right:
|
||||||
xPos = (nodeRect.x + nodeRect.width) * transform.zoom + transform.x + offset
|
pos = [
|
||||||
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
|
(nodeRect.x + nodeRect.width) * transform.zoom + transform.x + offset,
|
||||||
xShift = 0
|
(nodeRect.y + nodeRect.height * alignmentOffset) * transform.zoom + transform.y,
|
||||||
yShift = -50
|
]
|
||||||
|
shift = [0, -100 * alignmentOffset]
|
||||||
break
|
break
|
||||||
case Position.Bottom:
|
case Position.Bottom:
|
||||||
yPos = (nodeRect.y + nodeRect.height) * transform.zoom + transform.y + offset
|
pos[1] = (nodeRect.y + nodeRect.height) * transform.zoom + transform.y + offset
|
||||||
yShift = 0
|
shift[1] = 0
|
||||||
break
|
break
|
||||||
case Position.Left:
|
case Position.Left:
|
||||||
xPos = nodeRect.x * transform.zoom + transform.x - offset
|
pos = [
|
||||||
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
|
nodeRect.x * transform.zoom + transform.x - offset,
|
||||||
xShift = -100
|
(nodeRect.y + nodeRect.height * alignmentOffset) * transform.zoom + transform.y,
|
||||||
yShift = -50
|
]
|
||||||
|
shift = [-100, -100 * alignmentOffset]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return `translate(${xPos}px, ${yPos}px) translate(${xShift}%, ${yShift}%)`
|
return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = computed(() => {
|
const nodes = computed(() => {
|
||||||
@@ -63,13 +78,13 @@ const isActive = computed(() =>
|
|||||||
: nodes.value.length === 1 && nodes.value[0].selected && getSelectedNodes.value.length === 1,
|
: nodes.value.length === 1 && nodes.value[0].selected && getSelectedNodes.value.length === 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeRect = computed<Rect>(() => getRectOfNodes(nodes.value))
|
const nodeRect = computed(() => getRectOfNodes(nodes.value))
|
||||||
|
|
||||||
const zIndex = computed<number>(() => Math.max(...nodes.value.map((node) => (node.computedPosition.z || 1) + 1)))
|
const zIndex = computed(() => Math.max(...nodes.value.map((node) => (node.computedPosition.z || 1) + 1)))
|
||||||
|
|
||||||
const wrapperStyle = computed<CSSProperties>(() => ({
|
const wrapperStyle = computed<CSSProperties>(() => ({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
transform: getTransform(nodeRect.value, viewport.value, props.position, props.offset),
|
transform: getTransform(nodeRect.value, viewport.value, props.position, props.offset, props.align),
|
||||||
zIndex: zIndex.value,
|
zIndex: zIndex.value,
|
||||||
}))
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,4 +5,7 @@ export interface NodeToolbarProps {
|
|||||||
isVisible?: boolean
|
isVisible?: boolean
|
||||||
position?: Position
|
position?: Position
|
||||||
offset?: number
|
offset?: number
|
||||||
|
align?: 'center' | 'start' | 'end'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Align = 'center' | 'start' | 'end'
|
||||||
|
|||||||
Reference in New Issue
Block a user