JointJS是一款基于HTML5和JavaScript的前端图形化组件库,提供了丰富的图形化组件,包括但不限于流程图、UML图、ER图等。
一、框架介绍
JointJS框架的核心是rappid和jointjs库,rappid为joint提供了一些便捷的工具和编辑器,joint则是提供了核心可视化功能、手动布局和事件交互机制。
这里我们提供一个简单的示例,展示如何用JointJS绘制一个由若干个图形组成的图形场景。代码如下:
const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
width: 600,
height: 200,
model: graph
});
const rect = new joint.shapes.standard.Rectangle();
const rect2 = rect.clone();
const text = new joint.shapes.standard.Text();
rect.position(100, 30);
rect2.position(450, 80);
text.position(290, 40);
graph.addCells([rect, rect2, text]);
在这段代码中,我们首先新建一个joint.dia.Graph实例,定义画布的大小和graph实例,同时定义绘图上下文,然后创建两个矩形和一个文本对象,并定义它们的位置,最后将他们加入到画布的graph实例中,就能在画布上画出这三个对象。
二、基础图形
1. Rectangle 矩形
JointJS提供了矩形这个基础图形,通过矩形基础图形,我们可以自定义网格组件或者自定义节点。
const rect = new joint.shapes.standard.Rectangle();
JointJS的矩形可以自定义位置、尺寸和样式等属性,并且可以通过定位、旋转、套矩等方式构成更复杂的图形。
2. Ellipse 椭圆形
JointJS的椭圆形基础图形可以通过如下代码定义:
const ellipse = new joint.shapes.standard.Ellipse();
同样,椭圆形也可以自定义位置、尺寸、样式等属性,并且可以通过定位、旋转、套矩等方式构成更复杂的图形。
3. Rhombus 菱形
JointJS的菱形基础图形可以通过如下代码定义:
const rhombus = new joint.shapes.standard.Rhombus();
同样,菱形也可以自定义位置、尺寸、样式等属性,并且可以通过定位、旋转、套矩等方式构成更复杂的图形。
三、布局算法
JointJS提供了多种布局算法,包括直线路线布局、有机布局和树形布局,通过布局算法可以快速自动生成复杂的图例。
1. 直线路线布局
直线路线布局是JointJS提供的一种基础布局算法,也是最简单的一种布局算法。通过如下代码即可创建一张带有直线路线布局的画布:
const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
width: 600,
height: 200,
model: graph
});
const rect = new joint.shapes.standard.Rectangle({ position: { x: 100, y: 30 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } } });
const rect2 = rect.clone().translate(300);
const link = new joint.shapes.standard.Link({
source: {
id: rect.id
},
target: {
id: rect2.id
},
attrs: {
'.connection': {
stroke: 'black',
'stroke-width': 1
}
}
});
graph.addCells([rect, rect2,link]);
joint.layout.DirectedGraph.layout(graph, {
dagre: dagre
});
JointJS提供了多种布局算法,包括directional、sugiyama和dendrogram。例如以上代码中,使用了DAGre库来实现有向图的布局。
2. 有机布局
有机布局可以针对特定需求自定义可调节的布局参数,使其符合需求。
const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
width: 800,
height: 800,
model: graph
});
const rect1 = new joint.shapes.basic.Rect({
position: { x: 100, y: 100 },
size: { width: 150, height: 70 },
attrs: { rect: { fill: '#ff5252' }, text: { text: 'My shape', fill: 'white' } }
});
const rect2 = rect1.clone();
const rect3 = rect1.clone();
const rect4 = rect1.clone();
const rect5 = rect1.clone();
const link1 = new joint.dia.Link({
source: { id: rect1.id },
target: { id: rect2.id },
attrs: {
'.connection': {
stroke: '#333',
'stroke-width': 2
}
}
});
const link2 = new joint.dia.Link({
source: { id: rect2.id },
target: { id: rect3.id },
attrs: {
'.connection': {
stroke: '#333',
'stroke-width': 2
}
}
});
const link3 = new joint.dia.Link({
source: { id: rect2.id },
target: { id: rect4.id },
attrs: {
'.connection': {
stroke: '#333',
'stroke-width': 2
}
}
});
const link4 = new joint.dia.Link({
source: { id: rect2.id },
target: { id: rect5.id },
attrs: {
'.connection': {
stroke: '#333',
'stroke-width': 2
}
}
});
graph.addCells([ rect1, rect2, rect3, rect4, rect5, link1, link2, link3, link4 ]);
joint.layout.ForceDirectedLayout.layout(graph, null, {
linkDistance: 200,
nodeRepulsion: 400,
nodeAttraction: 0.01,
friction: 0.6,
gravity: 100,
theta: 0.8
});
3. 树形布局
JointJS的树形布局支持多级节点嵌套布局,并提供了专业的算法优化,使得布局效果自然。
const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
width: 800,
height: 800,
model: graph
});
const rect1 = new joint.shapes.standard.Rectangle({ position: { x: 100, y: 30 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } } });
const rect2 = new joint.shapes.standard.Rectangle({ position: { x: 50, y: 100 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'red' }, text: { text: 'my box', fill: 'white' } } });
const rect3 = new joint.shapes.standard.Rectangle({ position: { x: 200, y: 100 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'green' }, text: { text: 'my box', fill: 'white' } } });
const link1 = new joint.shapes.standard.Link({
source: { id: rect1.id },
target: { id: rect2.id }
});
const link2 = new joint.shapes.standard.Link({
source: { id: rect1.id },
target: { id: rect3.id }
});
graph.addCells([ rect1, rect2, rect3, link1, link2 ]);
joint.layout.TreeLayout.layout(graph, null, {
nodeSep: 100,
levelSep: 100,
siblingSep: 50,
direction: 'TD' // LR, TB, RL, BT
});
四、事件机制
JointJS提供了众多的事件机制,针对不同的交互事件,都有对应的回调函数或事件监听器,例如鼠标悬停,单击,拖拽放置等。
const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
width: 800,
height: 800,
model: graph
});
const rect1 = new joint.shapes.standard.Rectangle({ position: { x: 100, y: 30 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } } });
const rect2 = new joint.shapes.standard.Rectangle({ position: { x: 250, y: 80 }, size: { width: 100, height: 30 }, attrs: { rect: { fill: 'red' }, text: { text: 'my box', fill: 'white' } } });
const link = new joint.shapes.standard.Link({
source: { id: rect1.id },
target: { id: rect2.id }
});
graph.addCells([ rect1, rect2, link ]);
rect1.on('change:position', function(element) {
console.log('Position of rect1 has changed to x: ' + element.changed.position.x + ', y: ' + element.changed.position.y);
});
rect1.on('mouseover', function() {
console.log('Mouseover on rect1');
});
rect2.on('click', function() {
console.log('Click on rect2');
});
link.on('mouseenter', function() {
console.log('Mouseenter on link');
});
以上代码中,我们注册了对应的事件监听器或回调函数,通过这些事件机制可以响应用户的一些行为,例如在图形拖拽时,可以触发change:position事件来处理拖动后的位置信息。
五、小结
JointJS能够帮助我们编写出交互和丰富的应用,同时它也提供了数据绑定和事件系统来使用户与应用交互,帮助我们快速地实现自定义的可视化操作。
