JointJS:JavaScript 流程图绘制框架
最近调研了js画流程图的框架,最后选择了Joint。配合上 dagre 可以画出像模像样的流程图。
JointJS 简介
JointJS 是一个开源前端框架,支持绘制各种各样的流程图、工作流图等。Rappid 是 Joint 的商业版,提供了一些更强的插件。JointJS 的特点有下面几条,摘自官网:
能够实时地渲染上百(或者上千)个元素和连接
支持多种形状(矩形、圆、文本、图像、路径等)
高度事件驱动,用户可自定义任何发生在 paper 下的事件响应
元素间连接简单
可定制的连接和关系图
连接平滑(基于贝塞尔插值 bezier interpolation)& 智能路径选择
基于 SVG 的可定制、可编程的图形渲染
NodeJS 支持
通过 JSON 进行序列化和反序列化
总之 JoingJS 是一款很强的流程图制作框架,开源版本已经足够日常使用了。
一些常用地址:
API: https://resources.jointjs.com/docs/jointjs/v1.1/joint.html
Tutorials: https://resources.jointjs.com/tutorial
JointJS Hello world
<!DOCTYPE html> <html> <head> <link type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" /> </head> <body> <!-- content --> <div></div> <!-- dependencies 通过CDN加载依赖--> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script> <!-- code --> <script type="text/javascript"> var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({ el: document.getElementById('myholder'), model: graph, width: 600, height: 100, gridSize: 1 }); var rect = new joint.shapes.standard.Rectangle(); rect.position(100, 30); rect.resize(100, 40); rect.attr({ body: { fill: 'blue' }, label: { text: 'Hello', fill: 'white' } }); rect.addTo(graph); var rect2 = rect.clone(); rect2.translate(300, 0); rect2.attr('label/text', 'World!'); rect2.addTo(graph); var link = new joint.shapes.standard.Link(); link.source(rect); link.target(rect2); link.addTo(graph); </script> </body> </html>
hello world 代码没什么好说的。要注意这里的图形并没有自动排版,而是通过移动第二个 rect 实现的手动排版。
前后端分离架构
既然支持 NodeJs,那就可以把繁重的图形绘制任务交给服务器,再通过 JSON 序列化在 HTTP 上传输对象,这样减轻客户端的压力。
NodeJS 后端
var express = require('express'); var joint = require('jointjs'); var app = express(); function get_graph(){ var graph = new joint.dia.Graph(); var rect = new joint.shapes.standard.Rectangle(); rect.position(100, 30); rect.resize(100, 40); rect.attr({ body: { fill: 'blue' }, label: { text: 'Hello', fill: 'white' } }); rect.addTo(graph); var rect2 = rect.clone(); rect2.translate(300, 0); rect2.attr('label/text', 'World!'); rect2.addTo(graph); var link = new joint.shapes.standard.Link(); link.source(rect); link.target(rect2); link.addTo(graph); return graph.toJSON(); } app.all('*', function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); next(); }); app.get('/graph', function(req, res){ console.log('[+] send graph json to client') res.send(get_graph()); }); app.listen(8071);
HTML 前端
<!DOCTYPE html> <html> <head> <link type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" /> </head> <body> <!-- content --> <div></div> <!-- dependencies 通过CDN加载依赖--> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script> <!-- code --> <script type="text/javascript"> var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({ el: document.getElementById('myholder'), model: graph, width: 600, height: 100, gridSize: 1 }); $.get('http://192.168.237.128:8071/graph', function(data, statue){ graph.fromJSON(data); }); </script> </body> </html>
其他
自动布局 Automatic layout
JointJS 内置了插件进行自动排版,原理是调用 Dagre 库。官方 api 中有样例。
使用方法:
var graphBBox = joint.layout.DirectedGraph.layout(graph, { nodeSep: 50, edgeSep: 80, rankDir: "TB" });