vue-flow/helpline

187 阅读1分钟

提供helpline组件,未来可能上传npm吧,躺平了.

支持单个节点拖拽,以及多个同时拖拽对齐

image.png

image.png

<template>
  <div class="w-full h-[1px] border-blue-300 fixed border-dashed border-t-[2px] z-50" :style="{
    left: '0px',
    top: helpLine.y + 'px',
  }"></div>

  <div class="h-full w-[1px] border-blue-300 fixed border-dashed border-l-[2px] z-50" :style="{
    left: helpLine.x + 'px',
    top: '0px',
  }"></div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useVueFlow } from '@vue-flow/core'

const {
  toObject,
  updateNode,
  getViewport,
  getSelectedNodes,
  onNodeDragStart,
  onNodeDrag,
  onNodeDragStop,
  onSelectionDrag,
  onSelectionDragStop,
  onSelectionDragStart
} = useVueFlow()

const helpLine = ref({ x: -5, y: -5})
let horizontalHelpLines = []
let verticalHelpLines = []

const handleOnDragStart = ()=>{
  const { nodes } = toObject()
  const selectedNodes = getSelectedNodes.value
  const set = new Set(selectedNodes.map(item => item.id))
  horizontalHelpLines = []
  verticalHelpLines = []

  nodes.filter(item => !set.has(item.id))
    .map(item => {
      horizontalHelpLines.push({
        x: item.position.x,
        y: item.position.y,
      })
      verticalHelpLines.push({
        x: item.position.x,
        y: item.position.y,
      })
    })
}
onSelectionDragStart(handleOnDragStart)
onNodeDragStart(handleOnDragStart)

const handleOnDragMove = ()=>{
  const selectedNodes = getSelectedNodes.value
  let { x, y } = selectedNodes[0].position
  selectedNodes.forEach(node => {
    x = Math.min(x, node.position.x)
    y = Math.min(y, node.position.y)
  })

  let nx = x, ny = y
  helpLine.value = { x: -5, y: -5 }
  const v = getViewport()
  for (let i = 0; i < horizontalHelpLines.length; i++) {
    const help = horizontalHelpLines[i]
    if (
      y < help.y + 20 * v.zoom && 
      y > help.y - 20 * v.zoom
    ) {
      helpLine.value.y = help.y * v.zoom + v.y
      ny = help.y
      break
    }
  }

  for (let i = 0; i < verticalHelpLines.length; i++) {
    const help = verticalHelpLines[i]
    if (
      x < help.x + 20 * v.zoom && 
      x > help.x - 20 * v.zoom
    ) {
      helpLine.value.x = help.x * v.zoom + v.x
      nx = help.x
      break
    }
  }

  selectedNodes.map(item => {
    updateNode(item.id, {
      position: {
        x: item.position.x + (nx - x),
        y: item.position.y + (ny - y),
      }
    })
  })
}
onSelectionDrag(handleOnDragMove)
onNodeDrag(handleOnDragMove)

const handleOnDragEnd = ()=>{
  helpLine.value = { x: -5, y: -5 }
}

onSelectionDragStop(handleOnDragEnd)
onNodeDragStop(handleOnDragEnd)

</script>

最后在你的fow里面加入这个组件

<template>
  <div class="w-full h-full z-50 relative bg-gray-100 translate-x-0" ref="playground">
    <VueFlow v-model:nodes="nodes" :edges="edges">
       <HelpLine />
    </VueFlow>
  </div>

一些css的细节可能没仔细调整,如果你发现定位不准确,可能是css配置的原因,注意,translate, fixed这几个的配置。祝你好运