JointJS图库允许用户为所有当前的浏览器创建完全交互的绘图工具。JointJS不仅是一个图库,其MVC(更多的是MV)架构将图、元件(element)和连接(link)模型与绘制分离。这使得JointJS很容易嵌入到后端应用程序。此外,JointJS用Backbone MVC库构建,所以如果用户知道Backbone,会觉得很熟悉JointJS。JointJS是基于jQuery,Underscore,Backbone 和 SVG。
图包含元件,并用链接连接起来。在JointJS中,图由一个模型joint.dia.Graph代表。这个模型然后收集单元(cell,表示元件和链接)。因此,一个单元可以是一个元件(joint.dia.Element或其继承者)或链接(joint.dia.Link)。
JointJS提供了既提供了基本的图形元件,也包含了一些注明的图表(ERD, Org chart, FSA, UML, PN, DEVS, ...)。
Rappid基于JointJS,扩展了40个UI组件和其它元件,能极大的加速应用的开发。形如:
但Rappid需要购买。虽然如此,但是Rappid的Demo很详细,值得学习研究,为我们实现类似的功能提供了很好的参考。下一章将基于Rappid Demo进一步讨论。
Rappid提供了详细的Demo,一下只介绍了几个实用的,其它请参考在线文档。
下图的左方为组件框,包含了可使用的元件,用户可以方便的拖放到右方的画图区域。另外,用户也可以对元件分组,也能实现自定义用户搜索。
joint.ui.Stencil实现了JointJS元件的组件栏,简易代码如下:
vargraph
=new
joint.dia.Graph;
var
paper
=new
joint.dia.Paper({
el
:$
('#paper'),
width
:500,
height
:300,
model
:graph
});
var
stencil
=new
joint.ui.Stencil({
paper
:paper
,
width
:200,
height
:300
});
$
('#stencil-holder').append(stencil
.render().el
);//显示模版框
varr
=new
joint.shapes.basic.Rect({
position
:{
x
:10,
y
:10
},
size
:{
width
:50,
height
:30
}
});
var
c
=new
joint.shapes.basic.Circle({
position
:{
x
:70,
y
:10
},
size
:{
width
:50,
height
:30
}
});
stencil
.load([r
,c
]);//加载可使用的元件
joint.ui.Halo在每个元件上创建了一个控制面板。
简易代码:
paper
.on('cell:pointerup',function(
cellView
){
// We don't want a Halo for links.
if
(
cellView
.model
instanceofjoint.dia.Link)
return;
var
halo
=new
joint.ui.Halo({
cellView
:cellView
});
halo
.render();
});
joint.ui.Inspector创建一个单元模型属性的编辑器和查看器。
简易代码:
varinspector
;
functioncreateInspector(
cellView
){
// No need to re-render inspector if the cellView didn't change.
if
(!
inspector
||inspector
.options
.cellView
!==cellView
){
if
(
inspector
){
// Set unsaved changes to the model and clean up the old inspector if there was one.
inspector
.updateCell();
inspector
.remove();
}
inspector
=new
joint.ui.Inspector({
inputs
:{
myproperty
:{
type
:'range',
min
:0,
max
:30,
defaultValue
:1,
group
:'mydata',
index
:1
},
attrs
:{
text
:{
text
:{
type
:'textarea',
group
:'text',
index
:1
},
'font-size':
{
type
:'number',
group
:'text',
index
:2
}
}
}
},
groups
:{
mydata
:{
label
:'My Data',
index
:1
},
text
:{
label
:'Text',
index
:2
}
},
cellView
:cellView
});
$
('.inspector-container').html(inspector
.render().el
);
}
}
paper
.on('cell:pointerup',function(
cellView
){
createInspector(
cellView
);
});
joint.ui.PaperScroller对paper上的元件进行了包装,实现了滚动、平移、居中和自动调整大小。
简易代码:
varpaper
=new
joint.dia.Paper({
width
:2000,
height
:2000,
model
:graph
});
varpaperScroller
=new
joint.ui.PaperScroller({
paper
:paper
});
$
('#paper-container').append(paperScroller
.render().el
);
paperScroller
.centerContent();
joint.ui.Snaplines是引导元件对齐的实用工具。当用户拖动一个元件垂直或者水平靠近另一个元件时,将会出现水平线或者垂直线。
简易代码:
varsnaplines
=new
joint.ui.Snaplines({
paper
:paper
});
snaplines
.startListening();
JointJS内置了基本的图形元件。这些图形都在joint.shapes.basic命名空间,包括joint.shapes.basic.Rect、joint.shapes.basic.Circle、joint.shapes.basic.Text和joint.shapes.basic.Image。此外,JointJS的插件中也包含了常见图标所需的图形和链接元件。
另外,创建自定义元件也很简单,但需要SVG元素的一些基本知识。最重要的是SVG元件的rect
, text
, circle
, ellipse
, image
和 path
。它们的详细描述和例子可以在MDN. 中找到。
自定义元素通过链接SVG标签创建。通常,我们将一个元件放置到相对于另一个元件的某个位置。比如,我们希望有一个矩形元件和一个文本元件,并且文本元件应该始终在矩形的中心。但SVG没有提供的这样的方法。因此,JointJS引入了特殊的属性来放置元件的相对位置。例如joint.shapes.basic.Rect元件的定义:
joint
.shapes
.basic
.Rect
=joint
.shapes
.basic
.Generic
.extend({
markup
:'
',
defaults
:joint
.util
.deepSupplement({
type
:'basic.Rect',
attrs
:{
'rect':
{
fill
:'white',
stroke
:'black',
'follow-scale':
true,
width
:80,
height
:40
},
'text':
{
'font-size':
14,
'ref-x':
.5,
'ref-y':
.5,
ref
:'rect',
'y-alignment':
'middle',
'x-alignment':
'middle'
}
}
},
joint
.shapes
.basic
.Generic
.prototype
.defaults
)
});
如上所示,SVG标签保存在markup属性。这个属性包含了一个joint.shapes.basic.Rect元件的SVG模版。其中包含了两个SVG组:第一个是"rotatable", 当joint.dia.Element.rotate()被调用时,所有在这个组中的元件都会旋转;另外一个是"scalable",当 joint.dia.Element.resize()被调用时,所有在这个组中的元件都将一起缩放。
4.1
关系数据
每个元件都包含一个ID,对于Link型的元件,还包含了起始元件和目标元件的id。这样依照图中的数据关系就很清楚了。JointJS提供了相关API存储元件及其关系,比如:
1) graph
.getElements
获取图上所有的元件,除了链接(Link)
2) graph
.getLinks()
获取图中所有的链接(Link),除了元件(Element)。
3) graph
.getConnectedLinks(element
, opt
)
获取所有的已链接的链接(Link)。
4) graph
.toJSON()
返回所画图的JSON序列。注意:这个方法不会返回一个JSON字符串而是一个对象;但通过JSON.stringify()转化之后就能得到。
5) graph
.fromJSON(json
,[options
])
加载JSON对象(不是字符串)。
图片的存储也借鉴Rappid的扩展方法:
1) FORMAT.SVG (SVG EXPORT),此插件为joint.dia.Paper对象增加了两个新方法:
a) toSVG(callback) – 将paper中的内容转化为SVG字符串
b) openAsSVG() – 打开一个新窗口显示SVG paper内容
2) FORMAT.RASTER (PNG AND JPEGEXPORT),此插件为joint.dia.Paper对象增加了新方法,用于客户端输出PNG和JPEG格式的图片。
a) toPNG(callback
[, options
]) – 执行回调函数,表示paper内容的PNG数据URI作为其第一个参数
b) toJPEG(callback
[, options
]) -执行回调函数,表示paper内容的JPEG数据URI作为其第一个参数
c) toDataURL(callback
[, options
]) – 这个是之前两个方法的通用版本。执行回调函数,表示paper内容的特定MIME类型数据URI作为其第一个参数
参考文档:
1) http://www.jointjs.com/tutorial
2) http://www.jointjs.com/api
3) http://jointjs.com/rappid/docs