使用JointJS做一个简单的功能控制图

继上一篇介绍了GoJS之后,继续研究JS的绘图工具,毕竟GoJS有些小贵。这次选择了JointJS,完全开源,它还有一个商业版本叫Raddit,功能更强大。不过就我的需求场景,开源的Joint就足够了。接下来,我们看看它是怎么使用的。

JointJS是基于Backbone开发的,所以使用Joint之前,要先引入Backbone的相关依赖,所以我们的HTML文件是这样的:

这里我都用CDN,也可以将相应的库载到本地,但需要注意的是JS的加载顺序不能改。接下来,我们写一个官方的HelloWorld:

从上例里,我们可以看出,使用JointJS开发主要的步骤就是创建画板、创建画布、创建图形,然后将图形置于画板中。上面的例子执行后会得到下面的图像。
HelloWorld!

JointJS中的图形主要有两类,一是”元素”(Element),由构造函数创建。上例中的矩形就是JointJS库提供的标准元素,其构造函数为”joint.shapes.standard.Rectangle”。元素创建后,可以设置各种参数,比如位置,大小,风格等。JointJS提供了丰富的内置元素如矩形,圆形,椭圆等,可以参考API文档。同时,我们可以通过扩展”joint.dia.Element”类来自定义元素。

另一类图形是”连接”(Link),用来将两个”元素”连起来,一般显示为一条连线。上例中的连线是通过JointJS库提供的标准构造函数”joint.shapes.standard.Link”来创建的,创建后设置其”头”(Source)和”尾”(Target),即可将两个”元素”连起来。我们也可以设置”连接”的各种参数,如颜色,箭头,标签文字等。

HelloWorld之后我们来做一个简单的自动化功能控制图吧,HTML部分不变,我们来写JS部分。

  1. 首先定义画板和画布
  2. 上面的属性有些多,但大部分都好理解,主要是验证函数”validateConnection”,其返回”true”或”false”,用来决定连线是否被允许。传入的参数”viewSource”和”viewTarget”分别是画线过程中鼠标按钮释放时,当前连线头和尾的元素;而参数”magnetSource”和”magnetTarget”分别是当前连线头和尾的”连接点”(port)。”连接点”的概念下面会讲到。

  1. 定义基本图例元素
  2. 这里,我们创建了与、或、非,三个基本元素,因为是图例元素,所以不允许连入连出。我们使用标准库提供的”joint.shapes.devs.Model”元素,因为它很方便设置”连接点”(port)。

    上面代码写得挺粗燥的,高手见笑。其实可以更好的抽象,只是懒得弄了。上面关键的概念就是”连接点”(port),JointJS库中”joint.shapes.devs.Model”元素默认支持”入”(in)和”出”(out)两种连接点,分别显示在元素图形的左边和右边,多个连接点会自动排列。通过前一段代码中”paper”的”linkPinning”属性设置,可以要求”连线”只允许接在”连接点”上。上面我们定义了”连接点”风格为一个长10px宽3px的水平线。上例中,因为我重写了”连接点”的标记”portMarkup”,去掉了允许连线的属性,所以这些连接点目前都无法被连线。

  1. 接下来定义绘图元素
  2. 上面的代码还是很好理解的,我将图例元素中的”portMarkup”改了,其实就是增加了css类”port-body”,这是JointJS库中预定义的。该类中设置了”元素”的”magnet”属性,设为”true”时可入可出;”passive”时只入不出;”false”时不能连线。这样,我们的绘图元素就可以接上连线了。另外,这里将自定义属性”.label/type”改为”instance”主要是后面的事件判断用。

  1. 最后,我们定义鼠标事件,来支持将图例元素拖入绘图区域
  2. JointJS的事件都定义在画布paper上,可以参考这里的说明。事件的种类很多,可以在”元素”、”连线”或”空白处”上监听,可以是各种鼠标事件,这里不赘述了。大部分事件都接受4个参数:

    • “cellView”(或叫”elementView”) — 事件监听的主体,可以通过elementView.model来获得元素对象,并对其做各种设置
    • “evt” — 保存信息用于在事件间传数据
    • “x”和”y” — 记录事件发生时鼠标的位置

    上例中的事件函数,定义了将图例元素拖入绘图区域,并创建一个新的绘图元素的过程。

保存上面的代码并在浏览器里打开,大家应该可以看到如下内容。
JoinJS Sample

JointJS源码托管在Github中。更详细的开发API文档可以在官方API文档中找到。
本文中的示例代码,可以在这里下载

发表评论

电子邮件地址不会被公开。 必填项已用*标注