Skip to content

Commit 4e64754

Browse files
committed
improve embedded diagrams performance (route translating), clean outdated css rule
1 parent bf1c2eb commit 4e64754

38 files changed

+790
-264
lines changed

Diff for: dist/geometry.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-11
1+
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-17
22
33
44
This Source Code Form is subject to the terms of the Mozilla Public

Diff for: dist/geometry.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: dist/joint.browserify-bundle.js

+14-14
Large diffs are not rendered by default.

Diff for: dist/joint.core.css

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-11
1+
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-17
22
33
44
This Source Code Form is subject to the terms of the Mozilla Public
@@ -77,17 +77,16 @@ the whole group of elements. Each plugin can provide its own stylesheet.
7777
.element * {
7878
/* The default behavior when scaling an element is not to scale the stroke in order to prevent the ugly effect of stroke with different proportions. */
7979
vector-effect: non-scaling-stroke;
80-
-moz-user-select: none;
8180
user-drag: none;
8281
}
8382

8483

85-
/*
84+
/*
8685
8786
connection-wrap is a <path> element of the joint.dia.Link that follows the .connection <path> of that link.
8887
In other words, the `d` attribute of the .connection-wrap contains the same data as the `d` attribute of the
8988
.connection <path>. The advantage of using .connection-wrap is to be able to catch pointer events
90-
in the neighborhood of the .connection <path>. This is especially handy if the .connection <path> is
89+
in the neighborhood of the .connection <path>. This is especially handy if the .connection <path> is
9190
very thin.
9291
9392
*/
@@ -124,7 +123,7 @@ very thin.
124123
vector-effect: non-scaling-stroke;
125124
}
126125

127-
/*
126+
/*
128127
129128
Vertex markers are `<circle>` elements that appear at connection vertex positions.
130129
@@ -238,4 +237,4 @@ Do not allow adding new vertices: .connection-wrap { pointer-events: none; }
238237
vertical-align: middle;
239238
display: table-cell;
240239
padding: 0px 5px 0px 5px;
241-
}
240+
}

Diff for: dist/joint.core.js

+153-51
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-11
1+
/*! JointJS v0.9.5 - JavaScript diagramming library 2015-12-17
22
33
44
This Source Code Form is subject to the terms of the Mozilla Public
@@ -3969,7 +3969,7 @@ joint.dia.Graph = Backbone.Model.extend({
39693969

39703970
var cellsAncestors = _.map(arguments, function(cell) {
39713971

3972-
var ancestors = [cell.id];
3972+
var ancestors = [];
39733973
var parentId = cell.get('parent');
39743974

39753975
while (parentId) {
@@ -5086,7 +5086,7 @@ joint.dia.CellView = joint.mvc.View.extend({
50865086
return this.render();
50875087
}
50885088

5089-
return this.update();
5089+
return this.update(cell, attrs, opt);
50905090
},
50915091

50925092
// Override the Backbone `_ensureElement()` method in order to create a `<g>` node that wraps
@@ -6530,11 +6530,11 @@ joint.dia.Link = joint.dia.Cell.extend({
65306530
var vertices = this.get('vertices');
65316531

65326532
if (!source.id) {
6533-
attrs.source = { x: source.x + tx, y: source.y + ty };
6533+
attrs.source = { x: (source.x || 0) + tx, y: (source.y || 0) + ty };
65346534
}
65356535

65366536
if (!target.id) {
6537-
attrs.target = { x: target.x + tx, y: target.y + ty };
6537+
attrs.target = { x: (target.x || 0) + tx, y: (target.y || 0) + ty };
65386538
}
65396539

65406540
if (vertices && vertices.length) {
@@ -6543,6 +6543,12 @@ joint.dia.Link = joint.dia.Cell.extend({
65436543
});
65446544
}
65456545

6546+
// enrich the option object
6547+
opt = opt || {};
6548+
opt.translateBy = opt.translateBy || this.id;
6549+
opt.tx = tx;
6550+
opt.ty = ty;
6551+
65466552
return this.set(attrs, opt);
65476553
},
65486554

@@ -6560,7 +6566,7 @@ joint.dia.Link = joint.dia.Cell.extend({
65606566
newParent = this.graph.getCommonAncestor(source, target);
65616567
}
65626568

6563-
if (prevParent && (!newParent || newParent.id != prevParent.id)) {
6569+
if (prevParent && (!newParent || newParent.id !== prevParent.id)) {
65646570
// Unembed the link if source and target has no common ancestor
65656571
// or common ancestor changed
65666572
prevParent.unembed(this, opt);
@@ -6619,6 +6625,35 @@ joint.dia.Link = joint.dia.Cell.extend({
66196625
var target = this.get('target');
66206626

66216627
return (target && target.id && this.graph && this.graph.getCell(target.id)) || null;
6628+
},
6629+
6630+
// Returns the common ancestor for the source element,
6631+
// target element and the link itself.
6632+
getRelationshipAncestor: function() {
6633+
6634+
var connectionAncestor;
6635+
6636+
if (this.graph) {
6637+
6638+
var cells = _.compact([
6639+
this,
6640+
this.getSourceElement(), // null if source is a point
6641+
this.getTargetElement() // null if target is a point
6642+
]);
6643+
6644+
connectionAncestor = this.graph.getCommonAncestor.apply(this.graph, cells);
6645+
}
6646+
6647+
return connectionAncestor || null;
6648+
},
6649+
6650+
// Is source, target and the link itself embedded in a given element?
6651+
isRelationshipEmbeddedIn: function(element) {
6652+
6653+
var elementId = _.isString(element) ? element : element.id;
6654+
var ancestor = this.getRelationshipAncestor();
6655+
6656+
return !!ancestor && (ancestor.id === elementId || ancestor.isEmbeddedIn(elementId));
66226657
}
66236658
});
66246659

@@ -6680,14 +6715,30 @@ joint.dia.LinkView = joint.dia.CellView.extend({
66806715
this.listenTo(model, 'change:target', this.onTargetChange);
66816716
},
66826717

6683-
onSourceChange: function(cell, source) {
6718+
onSourceChange: function(cell, source, opt) {
66846719

6685-
this.watchSource(cell, source).update();
6720+
// Start watching the new source model.
6721+
this.watchSource(cell, source);
6722+
// This handler is called when the source attribute is changed.
6723+
// This can happen either when someone reconnects the link (or moves arrowhead),
6724+
// or when an embedded link is translated by its ancestor.
6725+
// 1. Always do update.
6726+
// 2. Do update only if the opposite end ('target') is also a point.
6727+
if (!opt.translateBy || !this.model.get('target').id) {
6728+
opt.updateConnectionOnly = true;
6729+
this.update(this.model, null, opt);
6730+
}
66866731
},
66876732

6688-
onTargetChange: function(cell, target) {
6733+
onTargetChange: function(cell, target, opt) {
66896734

6690-
this.watchTarget(cell, target).update();
6735+
// Start watching the new target model.
6736+
this.watchTarget(cell, target);
6737+
// See `onSourceChange` method.
6738+
if (!opt.translateBy) {
6739+
opt.updateConnectionOnly = true;
6740+
this.update(this.model, null, opt);
6741+
}
66916742
},
66926743

66936744
onVerticesChange: function(cell, changed, opt) {
@@ -6698,10 +6749,11 @@ joint.dia.LinkView = joint.dia.CellView.extend({
66986749
// the only link that was translated. If the link was translated via another element which the link
66996750
// is embedded in, this element will be translated as well and that triggers an update.
67006751
// Note that all embeds in a model are sorted - first comes links, then elements.
6701-
if (!opt.translateBy || opt.translateBy === this.model.id || this.model.hasLoop()) {
6702-
// Vertices were changed (not as a reaction on translate) or link.translate() was called or
6703-
// we're dealing with a loop link that is embedded.
6704-
this.update();
6752+
if (!opt.translateBy || opt.translateBy === this.model.id) {
6753+
// Vertices were changed (not as a reaction on translate)
6754+
// or link.translate() was called or
6755+
opt.updateConnectionOnly = true;
6756+
this.update(cell, null, opt);
67056757
}
67066758
},
67076759

@@ -6727,7 +6779,8 @@ joint.dia.LinkView = joint.dia.CellView.extend({
67276779
// `.connection`, `.connection-wrap`, `.marker-source` and `.marker-target` selectors
67286780
// of elements with special meaning though. Therefore, those classes should be preserved in any
67296781
// special markup passed in `properties.markup`.
6730-
var children = V(this.model.get('markup') || this.model.markup);
6782+
var model = this.model;
6783+
var children = V(model.get('markup') || model.markup);
67316784

67326785
// custom markup may contain only one children
67336786
if (!_.isArray(children)) children = [children];
@@ -6754,8 +6807,8 @@ joint.dia.LinkView = joint.dia.CellView.extend({
67546807
this.renderLabels();
67556808

67566809
// start watching the ends of the link for changes
6757-
this.watchSource(this.model, this.model.get('source'))
6758-
.watchTarget(this.model, this.model.get('target'))
6810+
this.watchSource(model, model.get('source'))
6811+
.watchTarget(model, model.get('target'))
67596812
.update();
67606813

67616814
return this;
@@ -6914,7 +6967,70 @@ joint.dia.LinkView = joint.dia.CellView.extend({
69146967
//---------
69156968

69166969
// Default is to process the `attrs` object and set attributes on subelements based on the selectors.
6917-
update: function() {
6970+
update: function(model, attributes, opt) {
6971+
6972+
opt = opt || {};
6973+
6974+
if (!opt.updateConnectionOnly) {
6975+
// update SVG attributes defined by 'attrs/'.
6976+
this.updateAttributes();
6977+
}
6978+
6979+
// update the link path, label position etc.
6980+
this.updateConnection(opt);
6981+
this.updateLabelPositions();
6982+
this.updateToolsPosition();
6983+
this.updateArrowheadMarkers();
6984+
6985+
// Local perpendicular flag (as opposed to one defined on paper).
6986+
// Could be enabled inside a connector/router. It's valid only
6987+
// during the update execution.
6988+
this.options.perpendicular = null;
6989+
// Mark that postponed update has been already executed.
6990+
this.updatePostponed = false;
6991+
6992+
return this;
6993+
},
6994+
6995+
updateConnection: function(opt) {
6996+
6997+
opt = opt || {};
6998+
6999+
var model = this.model;
7000+
var route;
7001+
7002+
if (opt.translateBy && model.isRelationshipEmbeddedIn(opt.translateBy)) {
7003+
// The link is being translated by an ancestor that will
7004+
// shift source point, target point and all vertices
7005+
// by an equal distance.
7006+
var tx = opt.tx || 0;
7007+
var ty = opt.ty || 0;
7008+
7009+
route = this.route = _.map(this.route, function(point) {
7010+
// translate point by point by delta translation
7011+
return g.point(point).offset(tx, ty);
7012+
});
7013+
7014+
// translate source and target connection and marker points.
7015+
this._translateConnectionPoints(tx, ty);
7016+
7017+
} else {
7018+
// Necessary path finding
7019+
route = this.route = this.findRoute(model.get('vertices') || [], opt);
7020+
// finds all the connection points taking new vertices into account
7021+
this._findConnectionPoints(route);
7022+
}
7023+
7024+
var pathData = this.getPathData(route);
7025+
7026+
// The markup needs to contain a `.connection`
7027+
this._V.connection.attr('d', pathData);
7028+
this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData);
7029+
7030+
this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget);
7031+
},
7032+
7033+
updateAttributes: function() {
69187034

69197035
// Update attributes.
69207036
_.each(this.model.get('attrs'), function(attrs, selector) {
@@ -6953,31 +7069,6 @@ joint.dia.LinkView = joint.dia.CellView.extend({
69537069
this.findBySelector(selector).attr(attrs);
69547070

69557071
}, this);
6956-
6957-
// Path finding
6958-
var vertices = this.route = this.findRoute(this.model.get('vertices') || []);
6959-
6960-
// finds all the connection points taking new vertices into account
6961-
this._findConnectionPoints(vertices);
6962-
6963-
var pathData = this.getPathData(vertices);
6964-
6965-
// The markup needs to contain a `.connection`
6966-
this._V.connection.attr('d', pathData);
6967-
this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData);
6968-
6969-
this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget);
6970-
6971-
//partials updates
6972-
this.updateLabelPositions();
6973-
this.updateToolsPosition();
6974-
this.updateArrowheadMarkers();
6975-
6976-
this.options.perpendicular = null;
6977-
// Mark that postponed update has been already executed.
6978-
this.updatePostponed = false;
6979-
6980-
return this;
69817072
},
69827073

69837074
_findConnectionPoints: function(vertices) {
@@ -7033,6 +7124,16 @@ joint.dia.LinkView = joint.dia.CellView.extend({
70337124
this.targetPoint = targetPoint;
70347125
},
70357126

7127+
_translateConnectionPoints: function(tx, ty) {
7128+
7129+
var cache = this._markerCache;
7130+
7131+
cache.sourcePoint.offset(tx, ty);
7132+
cache.targetPoint.offset(tx, ty);
7133+
this.sourcePoint.offset(tx, ty);
7134+
this.targetPoint.offset(tx, ty);
7135+
},
7136+
70367137
updateLabelPositions: function() {
70377138

70387139
if (!this._V.labels) return this;
@@ -7213,13 +7314,14 @@ joint.dia.LinkView = joint.dia.CellView.extend({
72137314
onEndModelChange: function(endType, endModel, opt) {
72147315

72157316
var doUpdate = !opt.cacheOnly;
7216-
var end = this.model.get(endType) || {};
7317+
var model = this.model;
7318+
var end = model.get(endType) || {};
72177319

72187320
if (endModel) {
72197321

72207322
var selector = this.constructor.makeSelector(end);
72217323
var oppositeEndType = endType == 'source' ? 'target' : 'source';
7222-
var oppositeEnd = this.model.get(oppositeEndType) || {};
7324+
var oppositeEnd = model.get(oppositeEndType) || {};
72237325
var oppositeSelector = oppositeEnd.id && this.constructor.makeSelector(oppositeEnd);
72247326

72257327
// Caching end models bounding boxes.
@@ -7258,8 +7360,8 @@ joint.dia.LinkView = joint.dia.CellView.extend({
72587360
}
72597361

72607362
if (opt.handleBy === this.cid && opt.translateBy &&
7261-
this.model.isEmbeddedIn(endModel) &&
7262-
!_.isEmpty(this.model.get('vertices'))) {
7363+
model.isEmbeddedIn(endModel) &&
7364+
!_.isEmpty(model.get('vertices'))) {
72637365
// Loop link whose element was translated and that has vertices (that need to be translated with
72647366
// the parent in which my element is embedded).
72657367
// If the link is embedded, has a loop and vertices and the end model
@@ -7306,10 +7408,10 @@ joint.dia.LinkView = joint.dia.CellView.extend({
73067408
this[endType + 'View'] = this[endType + 'Magnet'] = null;
73077409
}
73087410

7309-
// keep track which end had been changed very last
7310-
this.lastEndChange = endType;
7311-
7312-
doUpdate && this.update();
7411+
if (doUpdate) {
7412+
opt.updateConnectionOnly = true;
7413+
this.update(model, null, opt);
7414+
}
73137415
},
73147416

73157417
_translateAndAutoOrientArrows: function(sourceArrow, targetArrow) {

Diff for: dist/joint.core.min.css

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)