butterfly vue3 关系图

该博客展示了如何在Vue3项目中利用butterfly-dag库创建一个关系图组件。通过引用必要的依赖和设置配置,实现可拖动、可放大缩小、可删除连线的关系图,并提供了自定义节点和边的样式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

index.vue

<div className="compact-box-tree-page">

<div className="compact-box-tree-canvas" ref="buildCore"></div>

</div>

<script lang="ts">

import { defineComponent, ref, watch, onMounted } from 'vue';

import { mockData } from './config';

import { TreeCanvas } from 'butterfly-dag';

import 'butterfly-dag/dist/index.css';

export default defineComponent({

name: 'Butterfly',

components: {},

setup() {

const buildCore = ref<HTMLDivElement | null>(null);

let canvas: any = null;

onMounted(() => {

if (buildCore.value != null) {

canvas = new TreeCanvas({

root: buildCore.value,

disLinkable: true, // 可删除连线

linkable: true, // 可连线

draggable: true, // 可拖动

zoomable: true, // 可放大

moveable: true, // 可平移

theme: {

edge: {

shapeType: 'Manhattan',

arrow: true,

},

},

layout: {

type: 'compactBox',

options: {

direction: 'TB',

getHeight(d: any) {

return 60;

},

getWidth(d: any) {

return 120;

},

getHGap(d: any) {

return 20;

},

getVGap(d: any) {

return 80;

},

},

},

});

canvas.draw(mockData, {}, () => {

canvas.focusCenterWithAnimate();

});

}

});

const data = ref(mockData);

watch(

() => data,

() => {

canvas.draw(mockData, {}, () => {

canvas.focusCenterWithAnimate();

});

},

);

return {

buildCore,

};

},

});

</script>

<style lang="less">

@butterfly-theme-color-base: #fff;

@butterfly-normal-font-color-base: #222;

@butterfly-overlay-font-color-base: #fff;

@butterfly-primary-color-base: #f66902;

@butterfly-box-border-color-base: #d9d9d9;

@butterfly-box-shadow-base:0 2px 3px 0 rgba(0,112,204,0.06);

@butterfly-box-radius-base: 100px;

@butterfly-line-color-base: #bfbfbf;

// 主题背景色(画布背景色)

@butterfly-theme-background-color: @butterfly-theme-color-base;

// (各图形框)普通情况背景色

@butterfly-theme-color: fade(@butterfly-theme-color-base, 80%);

// 主题色

@butterfly-primary-color: @butterfly-primary-color-base;

// 普通情况下字体颜色

@butterfly-normal-font-color: @butterfly-normal-font-color-base;

// 主题背景色上的字体颜色及icon颜色

@butterfly-overlay-font-color: @butterfly-overlay-font-color-base;

// 拖动时的背景色

@butterfly-box-move-background-color: fade(@butterfly-primary-color, 20%);

// 边框的样式

@butterfly-box-border: 1px solid @butterfly-box-border-color-base;

@butterfly-box-shadow: @butterfly-box-shadow-base;

@butterfly-box-radius: @butterfly-box-radius-base;

@butterfly-box-node-border-hover: 1px solid @butterfly-primary-color;

// 线条样式

@butterfly-line-color: @butterfly-line-color-base;

.iot-node {

position: absolute;

width: 110px;

height: 64px;

.title {

width: 100%;

height: 100%;

line-height: 64px;

text-align: center;

background: @butterfly-primary-color;

border-radius: 0 0 8.04px 8.04px;

}

/* .content {

height: 32px;

padding: 0 8px;

color: @butterfly-normal-font-color;

font-size: 12px;

line-height: 32px;

text-align: center;

background: @butterfly-theme-color;

border: @butterfly-box-border;

border-radius: 0 0 8.04px 8.04px;

}*/

.expand-btn {

position: absolute;

bottom: -17px;

left: 46px;

width: 20px;

height: 10px;

line-height: 8px;

text-align: center;

background: @butterfly-theme-color;

border: @butterfly-box-border;

border-radius: 4px;

box-shadow: @butterfly-box-shadow;

cursor: pointer;

}

.expand-btn:hover {

border: @butterfly-box-node-border-hover;

border-radius: 5px;

}

}

.compact-box-tree-page {

width: 100%;

height: 100%;

.compact-box-tree-canvas {

width: 100%;

height: 100%;

}

.butterfly-wrapper {

position: relative;

}

.text-box {

position: absolute;

top: -45px;

left: 0;

display: inline-block;

width: 100%;

height: 30px;

padding: 0 10px;

font-size: 12px;

line-height: 30px;

text-align: center;

// background-color: pink;

}

.label {

position: absolute;

display: inline-block;

width: 80px;

height: 28px;

padding: 4px;

color: @butterfly-primary-color;

text-align: center;

//background: @butterfly-theme-color;

}

}

</style>

node.js

import $ from 'jquery';

import { TreeNode } from 'butterfly-dag';

//import dd from './../../../assets/imgs/kai.png';

class BaseNode extends TreeNode {

draw = opts => {

let container = $('<div class="iot-node"></div>')

.css('top', opts.top + 'px')

.css('left', opts.left + 'px')

.attr('id', opts.id);

let titleDom = $(

// `<div class="title ${opts.options.color}">${opts.options.title}<div>`,

`<div class="title"><img src= "${require(`@/assets/imgs/kai.png`)}" width='32' height='32'/><div>`,

);

// let contentDom = $(`<div class="content">${opts.options.content}<div>`);

container.append(titleDom);

// container.append(contentDom);

this.showExpandBtn(container);

this.createText(container);

return container[0];

};

showExpandBtn(container = this.dom) {

let expandBtn = $(`<div class='expand-btn'>···</div>`);

expandBtn.on('click', e => {

e.stopPropagation();

e.preventDefault();

if (this.collapsed) {

// 可以在这里向后端请求数据,把node穿进去expand里面

this.expand();

} else {

this.collapse();

}

});

expandBtn.appendTo(container);

}

createText(container = this.dom) {

if (this.options.label) {

$('<span class="text-box"></span>').text(this.options.label).appendTo(container);

}

}

}

export default BaseNode;

edge.js

import $ from 'jquery';

import { Edge } from 'butterfly-dag';

class BaseEdge extends Edge {

draw(obj) {

let path = super.draw(obj);

if (this.options.color) {

$(path).addClass(this.options.color);

}

return path;

}

drawArrow(isShow) {

let dom = super.drawArrow(isShow);

if (this.options.color) {

$(dom).addClass(this.options.color);

}

return dom;

}

drawLabel(text) {

let dom = null;

if (text) {

dom = $(`<span class="label">${text}</span>`)[0];

}

return dom;

}

}

export default BaseEdge;

config.ts

import Node from './node.js';

import BaseEdge from './edge';

export const mockData: any = {

nodes: {

// 节点信息

isRoot: true,

id: 'Root',

title: '根节点',

content: 'root',

// iconClass: 'icon-class',

// iconType: 'icon-shujuji',

src: 'kai.png',

Class: Node,

// label: '节点上的描述',

endpoints: [

{

id: '1',

orientation: [0, 1],

pos: [0.5, 0],

},

],

children: [

{

id: 'subNode1',

Class: Node,

title: '子节点 1',

content: 'sub node 1',

// collapsed: true,

//iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

children: [

{

id: 'subNode1-1',

Class: Node,

title: '子节点 1-1',

content: 'sub node 1-1',

//iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

},

{

id: 'subNode1-2',

Class: Node,

title: '子节点 1-2',

content: 'sub node 1-2',

// iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

},

],

},

{

id: 'subNode2',

Class: Node,

title: '子节点 2',

content: 'sub node 2',

// iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

// collapsed: true,

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

children: [

{

id: 'subNode2-1',

Class: Node,

title: '子节点 2-1',

content: 'sub node 2-1',

// iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

},

{

id: 'subNode2-2',

Class: Node,

title: '子节点 2-2',

content: 'sub node 2-2',

// iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

label: '4011',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

},

],

},

{

id: 'subNode3',

Class: Node,

label: '4011',

title: '子节点 3',

content: 'sub node 3',

// iconType: 'icon-guize-kai',

// iconClass: 'icon-class',

endpoints: [

{

id: '1',

orientation: [0, -1],

pos: [0.5, 0],

},

{

id: '2',

orientation: [0, 1],

pos: [0.5, 0],

},

],

},

],

},

edges: [

// 连线信息

{

id: '0',

source: '1',

target: '1',

sourceNode: 'Root',

targetNode: 'subNode1',

type: 'endpoint',

// label: 'line描述',

// labelPosition: 0.9,

//arrowPosition: 0.7, // 箭头的位置

//labelOffset: 20,

Class: BaseEdge,

},

{

id: '1',

source: '1',

target: '1',

sourceNode: 'Root',

targetNode: 'subNode2',

type: 'endpoint',

// label: 'line描述',

// labelPosition: 0.9,

//labelOffset: 20,

Class: BaseEdge,

},

{

id: '2',

source: '1',

target: '1',

sourceNode: 'Root',

targetNode: 'subNode3',

type: 'endpoint',

// label: 'line描述',

//labelPosition: 0.9,

// labelOffset: 20,

Class: BaseEdge,

},

{

id: '3',

source: '2',

target: '1',

sourceNode: 'subNode1',

targetNode: 'subNode1-1',

type: 'endpoint',

// label: 'line描述',

Class: BaseEdge,

},

{

id: '4',

source: '2',

target: '1',

sourceNode: 'subNode1',

targetNode: 'subNode1-2',

type: 'endpoint',

// label: 'line描述',

Class: BaseEdge,

},

{

id: '5',

source: '2',

target: '1',

sourceNode: 'subNode2',

targetNode: 'subNode2-1',

type: 'endpoint',

// label: 'line描述',

Class: BaseEdge,

},

{

id: '6',

source: '2',

target: '1',

sourceNode: 'subNode2',

targetNode: 'subNode2-2',

type: 'endpoint',

// label: 'line描述',

Class: BaseEdge,

},

],

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值