JointJS——前端图形化组件库(用JointJS做一个简单的功能控制图)

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

Published by

风君子

独自遨游何稽首 揭天掀地慰生平