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能够帮助我们编写出交互和丰富的应用,同时它也提供了数据绑定和事件系统来使用户与应用交互,帮助我们快速地实现自定义的可视化操作。