jointjs
Version:
JavaScript diagramming library
135 lines (118 loc) • 4.31 kB
JavaScript
;
// JointJS v2.0.0 Performance tips
// Overall goals
// -------------
// 1. reduce number of DOM elements
// 2. avoid asking the browser for element bounding boxes as much as possible
// Number of elements 0 - ?
var COUNT = 500;
// Async rendering true/false
// true: does not block the UI
var ASYNC = false;
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: document.getElementById('canvas'),
width: COUNT / 2 * 110,
height: 500,
model: graph,
async: ASYNC
});
var Shape = joint.dia.Element.define('Shape', {
size: {
width: 100,
height: 50
},
attrs: {
body: {
// Using of special 'ref-like` attributes it's not generally the most
// performer. In this particular case it's different though.
// If the `ref` attribute is not defined all the metrics (width, height, x, y)
// are taken from the model. There is no need to ask the browser for
// an element bounding box.
// All calculation are done just in Javascript === very fast.
refWidth: '100%',
refHeight: '100%',
stroke: 'red',
strokeWidth: 2,
fill: 'lightgray',
rx: 5,
ry: 5
},
label: {
fill: 'black',
// Please see the `ref-width` & `ref-height` comment.
refX: '50%',
refY: '50%',
// Do not use special attribute `x-alignment` when not necessary.
// It calls getBBox() on the SVGText element internally. Measuring text
// in the browser is usually the slowest.
// `text-anchor` attribute does the same job here (works for the text elements only).
textAnchor: 'middle',
// Do not use special attribute `y-alignment` for text vertical positioning. See above.
textVerticalAnchor: 'middle'
}
},
z: 2
}, {
// if markup does not change during the application life time, define it on the prototype (i.e. not in the defaults above)
markup: [{
tagName: 'rect',
selector: 'body'
}, {
tagName: 'text',
selector: 'label'
}]
});
var Link = joint.dia.Link.define('Link', {
z: 1,
attrs: {
line: {
connection: true,
// SVG Markers are pretty fast. Let's take advantage of this.
targetMarker: {
type: 'path',
fill: 'green',
stroke: 'none',
d: 'M 10 -10 0 0 10 10 z'
}
}
}
}, {
markup: [{
tagName: 'path',
selector: 'line',
attributes: {
// Here comes SVG attributes, for which values won't change during the application life time.
// These are specs SVG attributes. Do not add special attributes (e.g. targetMarker, fill: { /* gradient */ })).
// These attributes are set during render, and never touched again during updates.
'stroke': 'green',
'stroke-width': 2,
}
}]
});
var el = new Shape();
var l = new Link();
var cells = [];
Array.from({ length: COUNT / 2 }).forEach(function(_, n) {
var a = el.clone().position(n * 110, 100).attr('label/text', n + 1);
var b = el.clone().position(n * 100, 300).attr('label/text', n + 1 + (COUNT / 2));
var ab = l.clone().prop('source/id', a.id).prop('target/id', b.id);
cells.push(a, b, ab);
});
var startTime = new Date();
function showResult() {
var duration = (new Date() - startTime) / 1000;
document.getElementById('perf').textContent = (COUNT + ' elements and ' + COUNT / 2 + ' links rendered in ' + duration + 's');
}
// Prefer resetCells() over `addCells()` to add elements in bulk.
// SVG as oppose to HTML does not know `z-index` attribute.
// The "z" coordinate is determined by the order of the sibling elements. The JointJS
// paper makes sure the DOM elements are sorted based on the "z" stored on each element model.
graph.resetCells(cells);
if (ASYNC) {
paper.on('render:done', showResult);
} else {
showResult();
}
// There is still room for improvements in JointJS from the performance perspective.
// We're definitely going to address this in the upcoming releases.