效果图
安装
npm install --save jointjs
使用
// 引入jointjs和jointjs样式
import 'jointjs/dist/joint.css'
import * as joint from 'jointjs';
组件中加入
<div
ref="myholder"
id="paper"
@drop="drop"
@dragover="allowDrop"
></div>
script
创建画版
let graph = new joint.dia.Graph;
实例化画布,把画布挂载到dom
this.paper = new joint.dia.Paper({
el: this.$refs.myholder, //绑定节点
model: this.graph, // 定义的画布
width: 3000, // 画布宽度
height: 2000,// 画布高度
gridSize: 10, //栅格点间距,元素拖动会捕捉栅格点
snapLinks: {
radius: 60 // 距离元素连接点60像素时自动连接上
},
interactive: function() {
if (self.form.status == 'PROCESSING' || self.form.status == 'STOP') {
return false;
}
return true;
}, // 元素是否可以拖动
linkPinning: false, // 不想让用户拖动链接并将其放置在空白纸张区域的某个位置,请将其设置为false
// perpendicularLinks: true, //如果为true,链接将倾向于与关联对象垂直
multiLinks: false, // 一个元素与同一源元素和目标元素的链接不得超过一个
restrictTranslate: true, //设定元素不能拖出画布
//默认链接线的样式
defaultLink: new CustomLink({
attrs: {
path: { stroke: 'green' },
'.marker-target': {
d: 'M 10 0 L 0 5 L 10 10 z',
stroke: 'green',
fill: 'green'
}
},
labels: [
{
attrs: {
'.label': {
text: '1..n'
}
},
position: {
distance: 49, // individual absolute positioning
offset: null, // remove default offset
args: {
absoluteOffset: null // disable absolute offset when moving
}
}
}
]
}),
// 决定是允许还是禁止源视图/磁体 ( ) 和目标视图/磁体 ( )之间的连接
validateConnection: function(
sourceView,
sourceMagnet,
targetView,
targetMagnet
) {
if (sourceView.model == targetView.model) {
return false;
}
if (targetView.model.attributes.type == 'TriggerModel') {
return false;
}
let targetlinks = self.graph.getConnectedLinks(targetView.model);
for (let index = 0; index < targetlinks.length; index++) {
const element = targetlinks[index];
if (element.attributes.target.id == targetView.model.id) {
return false;
}
}
return true;
}
});
添加元素
allowDrop(ev) {
ev.preventDefault();
},
drop(evt) {
const position = {
x: evt.layerX - 50,
y: evt.layerY - 50
};
let d0 = new shapesCricle({
event: this.dragValue.event,
title: this.dragValue.title,
position: position,
size: { width: 150, height: 150 },
attrs: {
'.label': {
text: this.dragValue.label
},
'.label1': {
text: this.dragValue.label1
},
'.setting': {
fill: '#fa8c16'
}
}
});
this.graph.addCell(d0);
}
自定义元素
var shapesRect = joint.shapes.basic.Generic.extend({
defaults: joint.util.defaultsDeep(
{
// 提供自定义链接标记
markup: [
'<rect class="rectitem"/>',
'<g>',
'<g>',
'<rect class="rectborder"/>',
'<image class="reimage"/>',
'<image class="setimage"/>',
'<image class="linkimage"/>',
'<text class="label"></text>',
'<text class="label1"></text>',
'<rect class="setting"/>',
"</g>",
"</g>"
].join(""),
// 类型
type: "ActionModel",
// 工作流类型
workflowType:"ActionModel",
// 标记样式,位置,属性
attrs: {
'.reimage': {
width: 0,
height: 0,
x: 108,
y: 70,
event: 'click:remove',
cursor: 'pointer',
"xlink:href":
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABsUlEQVRIS+2WPU/CUBSG33OrEcpvMMFSEhcqicZVHfyYTXSR0cWPxU1YrIu6OaGTGy6aOPsxyGw0QVhMLNXE30DBaO8xIBjbRIUSEwfP2nPf57z3nntPCb8c1I5+TR+OMV7mJdBXzxfAM6H3KGTdlH9a3xbAiSXumaF/FiOCpZZL8bYBFc1YIuJd5vcqgwYRnplpLWIX9+saHw4czcgyeDmosMcdRFa1b1c9ADZNUc2djBJEqBsIQ9bCqdkrMk3pAbREq4PJKF4RDQTpwWP4rvDodeNTquiGCckbgQCCNiNW0fxbAAIkCA/MiPnatAzGADeuRTMCORC0ErGKe46WOGJgrnlwx6pdmq/oxjIkZ7sCCKFMhK1C3nM2zUqrenJcSvfyH/C/Rd4767/JihAzIev2zNES2wysN9t0R7VL6Zo+NO1KedpVFxEhTyQOmOUWM/obAMITkcgwy0VmjHUEqOpGWkreCvIWCUGZsFXc/vYtqsWTk67rngcBKIoyFbovXHwLqH90tESOgYVOIAQcqnYp5V/z5UyuO2GWI61B/xWs8QNA4tpfeSu/raHfiRN/7huWhjEoFaxUoQAAAABJRU5ErkJggg==",
},
'.setimage': {
width: 0,
height: 0,
x: 30,
y: 70,
event: 'click:set',
cursor: 'pointer',
"xlink:href":
"data:image/webp;base64,UklGRuoAAABXRUJQVlA4TN0AAAAvF8AFEJ9gIG2b7vev4RavYLWBqG0buUzGn979L/OvJgCQNs0Gt55+UsIAuBv/5AYH7LSCfMrcgDICmk8eqHNCmgioCgaNJCnqZ8b2b/bu/8BBRP8Vtm3bON3TTnIFAAAAAAAAAEA3xXtTlxsNp3cP/e05pLGoz3G86pLGqqqqa7I2VwpX87+xrKEmy7p8Lpyqml44gVZLSgfT/eOwj+P+o3BHJ/bvt0YtoURP9Z+Dx4fEGCmMHwoHFSif1Bzpyh5qi/1Z7v/CeCUDuSXjm8+H9zgedS7Pn9J8q85LAAA=",
},
'.linkimage': {
width: 0,
height: 0,
x: 128,
y: 70,
magnet: true,
"xlink:href":
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAMCAYAAABBV8wuAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAABqADAAQAAAABAAAADAAAAAAhICUEAAAATklEQVQYGWMQ6P/fwIAFMP1n+F+PTZIJpBibJFgCmyRcAl2SBSSADKDGMqDoQFaAIcHIwNj4oZCxAUUCJgjSCZdAFoRLoAuC7cLma5AEADeGJG76kS/8AAAAAElFTkSuQmCC",
},
'.rectborder': {
width: 100,
height: 100,
stroke: '#C8ECB7',
strokeWidth: 2,
fill: "#EDF9E8",
x: 25,
y: 25,
rx: 16,
ry: 16,
event: 'click:rectbg'
},
'.rectitem': {
width: 150,
height: 150,
fill: "rgba(0,0,0,0)",
},
".label": {
fill: "#333333",
fontSize: 18,
textAnchor: "middle",
x: 75,
y: 65
},
".label1": {
fill: "#333333",
fontSize: 18,
textAnchor: "middle",
x: 75,
y: 90
},
".setting": {
width: 6,
height: 6,
fill: "#52C41C",
x: 73,
y: 105,
rx: 3,
ry: 3
},
text: {
fill: "black"
}
}
},
joint.shapes.basic.Generic.prototype.defaults
)
});
事件交互
例子
// 元素点击事件
this.paper.on('cell:pointerclick', function(e, d) {});