Skip to content

francecil/vue-flowchart

Repository files navigation

vue-flowchart

基于Vue.js的流程图框架

目前进度:

  • 数据显示
  • 节点拖拽
  • 连线拖拽
  • 多选,划框选择
  • 多元素拖拽
  • 节点创建:点击新增&预置节点拖拽新增
  • 节点、连线编辑和删除
  • 画板自适应
  • 复制粘贴节点
  • 快捷键处理
  • 画板缩放
  • 撤销重做
  • 节点svg化
  • 悬浮节点提示

构建

# install dependencies
npm install

# serve with hot reload at localhost:8080
npm run dev

# build for production with minification
npm run build

# build for production and view the bundle analyzer report
npm run build --report

# run unit tests
npm run unit

# run e2e tests
npm run e2e

# run all tests
npm test

使用文档

...

定义

画板 Canvas

分为两种组件,一种是主界面,一种是放置模板节点的这里叫模板界面,可以有多个模板界面。

对于模板界面,没有连线,且仅支持节点拖拽和鼠标悬浮事件

canvas画板由一个 model 对象控制数据,其中包含两种元素,即节点和连线

{
  nodes: [Node],
  edges: [Edge]
}

元素的操作,除了在各种组件上的处理外,事件还会派发到canvas上,由canvas决定是否推入历史栈

一些功能按钮,在外部通过slot插槽传入canvas组件,样式让用户自定义

节点 Node

主要元素之一

{
  id: Number | String, //唯一标识符
  name: String,//节点名称
  x: Number, // 节点相对canvas的x坐标
  y: Number, // 节点相对canvas的y坐标
  connectors: [Connector],// 连接点
  readonly: Boolean=false,// 是否只读,只读模式下仅支持鼠标悬浮事件
  addition:Object// 支持拓展
}

连接点 Connector

一个node最多仅有两个connector(左右两侧两种类型)

用于连线时使用

{
  // 连接点类型,取值范围:leftConnector/rightConnector
  [type: String]: {
    id: Number | String, //唯一标识符
  }
}

组件配置:

连线 Edge

主要元素之一

由某节点的rightConnector连接点和另一节点的leftConnector连接点相连,带箭头

{
  source: Connector.id,
  destination: Connector.id,
  active: Boolean=false,// 应用连线流动动画
  label:String//连线的标签
}

标签

处于连线中心

其他坐标

event.clientX: 基于网页左上角的x坐标

getBoundingClientRect: 相对视口的坐标(相对),而不是网页左上角(绝对),比如有滚动条且向下滚动,获得的top值偏小

拖拽

连线随节点变动而变动

如何做到高效实时拖拽?

1. 监听待拖放节点的drag事件,跟随clientX/Y移动

    handleDragstart () {
      console.log('node Dragstart:', event)
      let elementBox = this.$el.getBoundingClientRect()
      this.eventPointOffset.x = event.clientX - elementBox.left
      this.eventPointOffset.y = event.clientY - elementBox.top
      // this.nodedraggingservice.dragstart(event)
      let dataTransfer = event.dataTransfer
      dataTransfer.dropEffect = 'move'
      dataTransfer.setData('Text', event.target.id)
      dataTransfer.setDragImage(this.$el, this.eventPointOffset.x, this.eventPointOffset.y)
      this.$emit('node-dragstart', this.node)
      this.updateConnectorPosition()
    },
    handleDragging (event) {
      console.log('handleDragging')
      if (!(event.clientX && event.clientY)) {
        return
      }
      let newNode = Object.assign(this.node, {
        x: event.clientX - this.canvas.left - this.eventPointOffset.x,
        y: event.clientY - this.canvas.top - this.eventPointOffset.y
      })
      this.updateNode({
        node: this.node,
        newNode
      })
      this.updateConnectorPosition()
    },
    handleDragend () {
      console.log('node Dragend:', event)
      let newNode = Object.assign(this.node, {
        x: event.clientX - this.canvas.left - this.eventPointOffset.x,
        y: event.clientY - this.canvas.top - this.eventPointOffset.y
      })
      this.updateNode({
        node: this.node,
        newNode,
        isPushState: true
      })
      this.$emit('node-dragend', event)
      // this.updateConnectorPosition()
    }

firefox 下 drag,dragend拿到的event.clientX/Y 为0,只能从容器的 dragover 和drop事件的event中获取

firefox 必须使用dataTransfer.setData('text', xxx) ie11上会报错且getData拿不到数据?

dragover时拿不到dataTransfer.getData

2. 触发容器的dragover事件

这样做的好处在于,被拖动元素将不可拖动至任意地方,仅在容器中重绘

chrome 中 dragover 不能拿到event.dataTransfer.getData('Text')

采用mouse代替drag

从测试上来看,mouse兼容性好,且性能更好一点

批量拖拽

鼠标悬浮mouseOver

类似 mouseover,它们两者之间的差别是 mouseenter 不会冒泡(bubble)

About

基于vue的流程图框架

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published