vue+jsplumb实现连线绘图,供大家参考,具体内容如下
jsPlumb是一个比较强大的绘图组件,它提供了一种方法,主要用于连接网页上的元素。在现代浏览器中,它使用SVG或者Canvas技术,而对于IE8以下(含IE8)的浏览器,则使用VML技术。
效果如图
1.安装
npm install jsplumb --save
2.main.js 引入
import jsPlumb from 'jsplumb'
Vue.prototype.$jsPlumb = jsPlumb.jsPlumb
3.封装组件 linkDataJsPlumb.vue
<template>
<div>
<div id="container" class='clear-float'>
<div class="left">
<ul>
<div class='titleContend clear-float'>
<div class='float firstField'>源表字段</div>
<div class='float secondField'>类型</div>
<div class='float thirdField'>描述</div>
</div>
<li v-for="(item,index) in leftList" :key="'left' + index" :id="item.nodeId" name="source">
<div class='titleContend clear-float'>
<div class='float firstField'>{{item.name}}</div>
<div class='float secondField'>{{item.name}}</div>
<div class='float thirdField'>{{item.name}}</div>
</div>
</li>
</ul>
</div>
<div class="right">
<ul>
<div class='titleContend clear-float'>
<div class='float firstField'>识别字段</div>
</div>
<li v-for="(item,index) in rightList" :key="'right' + index" :id="item.nodeId" name="target">
<div class='titleContend clear-float'>
<div class='float firstField'>{{item.name}}</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'linkElementModal',
props: {
// 左侧数据 [{ name: 'xxx_left_1', nodeId: 'left_1' }]
leftList: {
type: Array,
default: () => {
return [];
}
},
// 右侧数据 [{ name: 'xxx_right_1', nodeId: 'right_1' }]
rightList: {
type: Array,
default: () => {
return [];
}
},
// 默认数据 [{left: 'left_1', right: 'right_1'}]
value: {
type: Array,
default: () => {
return [];
}
}
},
data () {
return {
jsPlumb: null // 缓存实例化的jsplumb对象
};
},
mounted () {
this.showPlumb();
},
methods: {
showPlumb () {
this.jsPlumb = this.$jsPlumb.getInstance({
Container: 'container', // 选择器id
EndpointStyle: { radius: 0.11, fill: '#999' }, // 端点样式
PaintStyle: { stroke: '#999', strokeWidth: 2 }, // 绘画样式,默认8px线宽 #456
HoverPaintStyle: { stroke: '#994B0A', strokeWidth: 3 }, // 默认悬停样式 默认为null
ConnectionOverlays: [ // 此处可以设置所有箭头的样式
['Arrow', { // 设置参数可以参考中文文档
location: 1,
width: 10,
length: 6,
paintStyle: {
stroke: '#999',
fill: '#999'
}
}]
],
Connector: ['Straight'], // 要使用的默认连接器的类型:直线,折线,曲线等
DrapOptions: { cursor: 'crosshair', zIndex: 2000 }
});
this.jsPlumb.batch(() => {
for (let i = 0; i < this.leftList.length; i++) {
this.initLeaf(this.leftList[i].nodeId, 'source');
}
for (let j = 0; j < this.rightList.length; j++) {
this.initLeaf(this.rightList[j].nodeId, 'target');
}
});
this.setjsPlumb(true, true);
// 点击连线
this.jsPlumb.bind('click', (conn, originalEvent) => {
this.value.forEach((item, index) => {
if (item.left == conn.sourceId) {
this.value.splice(index, 1);
}
});
this.jsPlumb.deleteConnection(conn);
});
// 连线时触发
this.jsPlumb.bind('connection', (conn, originalEvent) => {
let obg = {
left: conn.sourceId,
right: conn.targetId
};
this.value.push(obg);
});
// 右键触发
this.jsPlumb.bind('contextmenu', (conn, originalEvent) => {
console.log(conn, originalEvent);
});
},
// 初始化规则使其可以连线、拖拽
initLeaf (id, type) {
const ins = this.jsPlumb;
const elem = document.getElementById(id);
if (type === 'source') {
ins.makeSource(elem, {
anchor: [1, 0.5, 0, 0], // 左 上 右 下
allowLoopback: false, // 允许回连
maxConnections: 1 // 最大连接数(-1表示不限制)
});
} else {
ins.makeTarget(elem, {
anchor: [0, 0.5, 0, 0],
allowLoopback: false,
maxConnections: 1
});
}
},
setjsPlumb (sourceFlag, targetFlag) {
const source = document.getElementsByName('source');
const target = document.getElementsByName('target');
this.jsPlumb.setSourceEnabled(source, sourceFlag);
this.jsPlumb.setTargetEnabled(target, targetFlag);
this.jsPlumb.setDraggable(source, false); // 是否支持拖拽
this.jsPlumb.setDraggable(target, false); // 是否支持拖拽
// 是否含有默认数据
if (this.value.length > 0) {
this.initConnect();
}
},
// 默认链接
initConnect () {
const jsplumbConnectOptions = {
isSource: true,
isTarget: true,
// 动态锚点、提供了4个方向 Continuous、AutoDefault
anchor: 'Continuous'
};
this.jsPlumb.deleteEveryConnection();
for (var i = 0; i < this.value.length; i++) {
let line = this.value[i];
this.jsPlumb.connect({
source: line.left,
target: line.right
}, jsplumbConnectOptions);
}
}
}
};
</script>
<style>
#container {
width: 500px;
padding: 20px;
position: relative; /*一定加上这句,否则连线位置发生错乱*/
}
.left {
float: left;
width: auto;
}
.right {
float: right;
width: auto;
}
.left li,
.right li {
list-style: none;
width: auto;
}
</style>
<style lang='scss' scoped>
.titleContend {
width: auto;
height: 30px;
line-height: 30px;
border-bottom: 1px solid #cccccc;
.float {
float: left;
}
.firstField {
width: 100px;
}
.secondField {
width: 100px;
}
.thirdField {
width: 80px;
}
}
</style>
4.使用组件
<linkDataJsPlumb v-model='defaultList' :leftList='leftList' :rightList='rightList'/>
import linkDataJsPlumb from './components/linkDataJsPlumb';
// 左侧数据
leftList: [
{ name: 'xxx_left_1', nodeId: 'left_1' },
{ name: 'xxx_left_2', nodeId: 'left_2' },
{ name: 'xxx_left_3', nodeId: 'left_3' },
{ name: 'xxx_left_4', nodeId: 'left_4' }
],
rightList: [
{ name: 'xxx_right_1', nodeId: 'right_1' },
{ name: 'xxx_right_2', nodeId: 'right_2' },
{ name: 'xxx_right_3', nodeId: 'right_3' },
{ name: 'xxx_right_4', nodeId: 'right_4' }
],
// 默认值
defaultList: [
{left: 'left_1', right: 'right_2'},
{left: 'left_2', right: 'right_3'},
{left: 'left_3', right: 'right_1'}
]
中文mirrors / wangduanduan / jsplumb-chinese-tutorial · GitCode
jsPlumb的初始化
使用jsPlumb进行实例化的同时可以传入相关属性的设置。
this.jsp = jsPlumb.getInstance({
Anchor: ["Right", "Left"],
//锚点位置,如left,top,bottom等;对任何没有声明描点的Endpoint设置锚点,
//用于source或target节点
//设置为数组可以指定锚点的位置
Anchors: ["Right", "Left"], //连线的source和target Anchor
ConnectionsDetachable: false, //连线是否可用鼠标分离
ConnectionOverlays: [ //连线的叠加组件,如箭头、标签
//叠加组件-箭头参数设置
["Arrow", {
location: 1,
visible: true,
width: 11,
length: 11,
id: "ARROW",
events: {
click: function () {
}
}
}],
//叠加组件-标签参数设置
["Label", {
location: 0.1,
cssClass: "aLabel", //hover时label的样式名
events: {
click:info=>{
console.log(info);
}
},
visible: true
}]
],
Connector: "Straight",
//连线的类型,有直线(Sright),有流程图(Flowchart)、贝塞尔曲线(Bezier),State machine(状态机)
Container: "module",
//父级元素id;假如页面元素所在上层不同,最外层父级一定要设置
DoNotThrowErrors: false,
//如果请求不存在的Anchor、Endpoint或Connector,是否抛异常
DragOptions : { },//用于配置拖拽元素的参数
DropOptions : { },//用于配置元素的drop行为的参数
Endpoint: "Dot", //端点(锚点)的样式声明
Endpoints: [null, null],
//用jsPlumb.connect创建连接时,source端点和target端点的样式设置
EndpointOverlays: [], //端点的叠加物
EndpointStyle: {fill: 'transparent', stroke: '#1565C0', radius: 4, strokeWidth: 1}, //端点的默认样式
EndpointStyles: [null, null], //连线的source和target端点的样式
EndpointHoverStyle: {fill: '#1565C0', stroke: '#1565C0', radius: 4, strokeWidth: 1}, //端点hover时的样式
EndpointHoverStyles: [null, null], //连线的source和target端点hover时的样式
HoverPaintStyle: {stroke: '#1565C0', strokeWidth: 3}, //连线hover时的样式
LabelStyle: {color: "black"}, //标签的默认样式,用css写法。
LogEnabled: false, //是否开启jsPlumb内部日志
Overlays: [], //连线和端点的叠加物
MaxConnections: 10, //端点支持的最大连接数
PaintStyle: {stroke: '#1565C0', strokeWidth: 1, joinstyle: 'round'}, //连线样式
ReattachConnections: true, //是否重新连接使用鼠标分离的线?
RenderMode: "svg", //默认渲染模式
Scope: "jsPlumb_DefaultScope", //范围,具有相同scope的点才可
reattach: true,
})
jsPlumb的相关方法
-
添加连线
let params={source: info.sourceId, target: info.targetId};
let setting=为自定义的jsPlumb设置,也可以不传入
this.jsp.connect(params,setting);
-
删除连线
this.jsp.removeAllEndpoints(node)这个方法删除指定的节点和连线,传入的node为节点元素
this.jsp.deleteEveryConnection();这个方法删除所有连线,不需要传入参数
this.jsp.deleteEveryEndpoint();这个方法删除所有节点,不需要传入参数
this.jsp.deleteConnectionsForElement("A-1",{});删除制定的连线,传入节点ID
-
重绘连线
this.jsp.repaintEverything()//重绘连线
this.jsp.setSuspendDrawing(true);
this.jsp.setSuspendDrawing(false,true);
这里第二个参数的true,会使整个jsPlumb立即重绘。
注意:
因为jsPlumb 是通过DOM进行工作的,所以我们需要把jsPlumb初始化 放在mounted声明,
如果是在子组件中完成,需要保证子组件渲染完成才可进行处理,可以放在进行初始化this.$nextTick(()=>{ } )