refactor(background): move background into separate package

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
braks
2022-12-13 14:53:44 +01:00
committed by Braks
parent af801c74ce
commit c7b51025d0
10 changed files with 395 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
<script lang="ts" setup>
import { useVueFlow } from '@vue-flow/core'
import { BackgroundVariant } from './types'
import type { BackgroundProps } from './types'
const {
variant = 'dots' as BackgroundVariant,
gap = 10,
size = 0.4,
height = 100,
width = 100,
x = 0,
y = 0,
bgColor,
patternColor: initialPatternColor,
} = defineProps<BackgroundProps>()
const defaultColors: Record<BackgroundVariant, string> = {
[BackgroundVariant.Dots]: '#81818a',
[BackgroundVariant.Lines]: '#eee',
}
const { id, viewport } = useVueFlow()
const background = $computed(() => {
const scaledGap = gap && gap * viewport.value.zoom
const xOffset = scaledGap && viewport.value.x % scaledGap
const yOffset = scaledGap && viewport.value.y % scaledGap
const bgSize = size * viewport.value.zoom
return {
scaledGap,
xOffset,
yOffset,
size: bgSize,
}
})
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
const patternId = `pattern-${id}`
const patternColor = computed(() => initialPatternColor || defaultColors[variant || BackgroundVariant.Dots])
const d = computed(
() => `M${background.scaledGap / 2} 0 V${background.scaledGap} M0 ${background.scaledGap / 2} H${background.scaledGap}`,
)
</script>
<script lang="ts">
export default {
name: 'Background',
}
</script>
<template>
<svg
class="vue-flow__background"
:style="{
height: `${height > 100 ? 100 : height}%`,
width: `${width > 100 ? 100 : width}%`,
}"
>
<slot :id="patternId" name="pattern-container">
<pattern
:id="patternId"
:x="background.xOffset"
:y="background.yOffset"
:width="background.scaledGap"
:height="background.scaledGap"
patternUnits="userSpaceOnUse"
>
<slot name="pattern">
<template v-if="variant === BackgroundVariant.Lines">
<path :stroke="patternColor" :stroke-width="size" :d="d" />
</template>
<template v-else-if="variant === BackgroundVariant.Dots">
<circle :cx="background.size" :cy="background.size" :r="background.size" :fill="patternColor" />
</template>
<svg v-if="bgColor" height="100" width="100">
<rect width="100%" height="100%" :fill="bgColor" />
</svg>
</slot>
</pattern>
</slot>
<rect :x="x" :y="y" width="100%" height="100%" :fill="`url(#${patternId})`" />
<slot :id="patternId" />
</svg>
</template>
+91
View File
@@ -0,0 +1,91 @@
<script lang="ts" setup>
import { computed, inject } from 'vue'
import type { GraphNode, Rect, ViewpaneTransform } from '@vue-flow/core'
import { NodeIdInjection, Position, getRectOfNodes, useVueFlow } from '@vue-flow/core'
import type { CSSProperties } from 'vue'
import type { NodeToolbarProps } from './types'
const props = withDefaults(defineProps<NodeToolbarProps>(), {
position: Position.Top,
offset: 10,
})
const contextNodeId = inject(NodeIdInjection, null)
const { viewportRef, viewport, getSelectedNodes, findNode } = useVueFlow()
function getTransform(nodeRect: Rect, transform: ViewpaneTransform, position: Position, offset: number): string {
// position === Position.Top
let xPos = (nodeRect.x + nodeRect.width / 2) * transform.zoom + transform.x
let yPos = nodeRect.y * transform.zoom + transform.y - offset
let xShift = -50
let yShift = -100
switch (position) {
case Position.Right:
xPos = (nodeRect.x + nodeRect.width) * transform.zoom + transform.x + offset
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
xShift = 0
yShift = -50
break
case Position.Bottom:
yPos = (nodeRect.y + nodeRect.height) * transform.zoom + transform.y + offset
yShift = 0
break
case Position.Left:
xPos = nodeRect.x * transform.zoom + transform.x - offset
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
xShift = -100
yShift = -50
break
}
return `translate(${xPos}px, ${yPos}px) translate(${xShift}%, ${yShift}%)`
}
const nodes = computed(() => {
const nodeIds = Array.isArray(props.nodeId) ? props.nodeId : [props.nodeId || contextNodeId || '']
return nodeIds.reduce<GraphNode[]>((acc, id) => {
const node = findNode(id)
if (node) {
acc.push(node)
}
return acc
}, [] as GraphNode[])
})
const isActive = computed(() =>
typeof props.isVisible === 'boolean'
? props.isVisible
: nodes.value.length === 1 && nodes.value[0].selected && getSelectedNodes.value.length === 1,
)
const nodeRect = computed<Rect>(() => getRectOfNodes(nodes.value))
const zIndex = computed<number>(() => Math.max(...nodes.value.map((node) => (node.computedPosition.z || 1) + 1)))
const wrapperStyle = computed<CSSProperties>(() => ({
position: 'absolute',
transform: getTransform(nodeRect.value, viewport.value, props.position, props.offset),
zIndex: zIndex.value,
}))
</script>
<script lang="ts">
export default {
name: 'NodeToolbar',
inheritAttrs: false,
}
</script>
<template>
<Teleport :to="viewportRef">
<div v-if="isActive && nodes.length" v-bind="$attrs" :style="wrapperStyle" class="vue-flow__node-toolbar">
<slot />
</div>
</Teleport>
</template>
+2
View File
@@ -0,0 +1,2 @@
export { default as Background } from './Background.vue'
export * from './types'
+25
View File
@@ -0,0 +1,25 @@
export enum BackgroundVariant {
Lines = 'lines',
Dots = 'dots',
}
export interface BackgroundProps {
/** The background pattern variant, {@link BackgroundVariant} */
variant?: BackgroundVariant
/** Background pattern gap */
gap?: number
/** Background pattern size */
size?: number
/** Background pattern color */
patternColor?: string
/** Background color */
bgColor?: string
/** Background height */
height?: number
/** Background width */
width?: number
/** Background x-coordinate (offset x) */
x?: number
/** Background y-coordinate (offset y) */
y?: number
}