@joint/core 4.2.0-alpha.0 → 4.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/geometry.js +2 -2
- package/dist/geometry.min.js +3 -2
- package/dist/joint.d.ts +280 -149
- package/dist/joint.js +1427 -475
- package/dist/joint.min.js +4 -3
- package/dist/joint.nowrap.js +1427 -475
- package/dist/joint.nowrap.min.js +4 -3
- package/dist/vectorizer.js +21 -8
- package/dist/vectorizer.min.js +4 -3
- package/dist/version.mjs +1 -1
- package/package.json +7 -7
- package/src/V/index.mjs +20 -5
- package/src/alg/Deque.mjs +126 -0
- package/src/cellTools/Boundary.mjs +15 -13
- package/src/cellTools/Button.mjs +7 -5
- package/src/cellTools/Control.mjs +37 -14
- package/src/cellTools/HoverConnect.mjs +5 -1
- package/src/cellTools/helpers.mjs +44 -3
- package/src/config/index.mjs +8 -0
- package/src/dia/Cell.mjs +26 -10
- package/src/dia/CellView.mjs +7 -0
- package/src/dia/Element.mjs +4 -2
- package/src/dia/ElementView.mjs +2 -1
- package/src/dia/HighlighterView.mjs +22 -0
- package/src/dia/LinkView.mjs +118 -98
- package/src/dia/Paper.mjs +697 -209
- package/src/dia/ToolView.mjs +4 -0
- package/src/dia/ToolsView.mjs +12 -3
- package/src/dia/attributes/text.mjs +4 -2
- package/src/dia/ports.mjs +202 -82
- package/src/elementTools/HoverConnect.mjs +14 -8
- package/src/env/index.mjs +6 -3
- package/src/layout/ports/port.mjs +30 -15
- package/src/layout/ports/portLabel.mjs +1 -1
- package/src/mvc/View.mjs +4 -0
- package/src/mvc/ViewBase.mjs +1 -1
- package/types/geometry.d.ts +64 -60
- package/types/joint.d.ts +205 -88
- package/types/vectorizer.d.ts +11 -1
package/dist/joint.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/*! JointJS v4.2.0-alpha.
|
|
2
|
-
|
|
1
|
+
/*! JointJS v4.2.0-alpha.1 (2025-09-25) - JavaScript diagramming library
|
|
3
2
|
|
|
4
3
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
4
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
5
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
6
|
*/
|
|
7
|
+
|
|
8
8
|
(function (global, factory) {
|
|
9
9
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
10
10
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
@@ -9862,8 +9862,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
9862
9862
|
});
|
|
9863
9863
|
|
|
9864
9864
|
/**
|
|
9865
|
-
*
|
|
9866
|
-
* @
|
|
9865
|
+
* Calculates the transformation matrix from this element to the target element.
|
|
9866
|
+
* @param {SVGElement|V} target - The target element.
|
|
9867
|
+
* @param {Object} [opt] - Options object for transformation calculation.
|
|
9868
|
+
* @param {boolean} [opt.safe] - Use a safe traversal method to compute the matrix.
|
|
9869
|
+
* @returns {DOMMatrix} The transformation matrix from this element to the target element.
|
|
9867
9870
|
*/
|
|
9868
9871
|
VPrototype.getTransformToElement = function (target, opt) {
|
|
9869
9872
|
const node = this.node;
|
|
@@ -10196,11 +10199,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
10196
10199
|
}
|
|
10197
10200
|
VPrototype.text = function (content, opt) {
|
|
10198
10201
|
if (content && typeof content !== 'string') throw new Error('Vectorizer: text() expects the first argument to be a string.');
|
|
10199
|
-
|
|
10200
|
-
// Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
|
|
10201
|
-
// IE would otherwise collapse all spaces into one.
|
|
10202
|
-
content = V.sanitizeText(content);
|
|
10203
10202
|
opt || (opt = {});
|
|
10203
|
+
|
|
10204
|
+
// Backwards-compatibility: if no content was provided, treat it as an
|
|
10205
|
+
// empty string so that subsequent string operations (e.g. split) do
|
|
10206
|
+
// not throw and behaviour matches the previous implementation that
|
|
10207
|
+
// always sanitised the input.
|
|
10208
|
+
if (content == null) content = '';
|
|
10209
|
+
if (opt.useNoBreakSpace) {
|
|
10210
|
+
// Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
|
|
10211
|
+
// IE would otherwise collapse all spaces into one.
|
|
10212
|
+
content = V.sanitizeText(content);
|
|
10213
|
+
}
|
|
10204
10214
|
// Should we allow the text to be selected?
|
|
10205
10215
|
var displayEmpty = opt.displayEmpty;
|
|
10206
10216
|
// End of Line character
|
|
@@ -10943,6 +10953,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
10943
10953
|
// also exposed so that the programmer can use it in case he needs to. This is useful e.g. in tests
|
|
10944
10954
|
// when you want to compare the actual DOM text content without having to add the unicode character in
|
|
10945
10955
|
// the place of all spaces.
|
|
10956
|
+
/**
|
|
10957
|
+
* @deprecated Use regular spaces and rely on xml:space="preserve" instead.
|
|
10958
|
+
*/
|
|
10946
10959
|
V.sanitizeText = function (text) {
|
|
10947
10960
|
return (text || '').replace(/ /g, '\u00A0');
|
|
10948
10961
|
};
|
|
@@ -12490,6 +12503,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
12490
12503
|
});
|
|
12491
12504
|
|
|
12492
12505
|
const config$3 = {
|
|
12506
|
+
// How the cell attributes are merged when `cell.prop()` is called.
|
|
12507
|
+
// DEFAULT: the arrays are merged into the source array.
|
|
12508
|
+
cellMergeStrategy: null,
|
|
12509
|
+
// How the cell default attributes are merged with the attributes provided
|
|
12510
|
+
// in the cell constructor.
|
|
12511
|
+
// DEFAULT: the arrays are merged by replacing the source array
|
|
12512
|
+
// with the destination array.
|
|
12513
|
+
cellDefaultsMergeStrategy: null,
|
|
12493
12514
|
// When set to `true` the cell selectors could be defined as CSS selectors.
|
|
12494
12515
|
// If not, only JSON Markup selectors are taken into account.
|
|
12495
12516
|
useCSSSelectors: false,
|
|
@@ -15034,9 +15055,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
15034
15055
|
const eol = attrs.eol;
|
|
15035
15056
|
const x = attrs.x;
|
|
15036
15057
|
let textPath = attrs['text-path'];
|
|
15058
|
+
const useNoBreakSpace = attrs['use-no-break-space'] === true;
|
|
15037
15059
|
// Update the text only if there was a change in the string
|
|
15038
15060
|
// or any of its attributes.
|
|
15039
|
-
const textHash = JSON.stringify([text, lineHeight, annotations, textVerticalAnchor, eol, displayEmpty, textPath, x, fontSize]);
|
|
15061
|
+
const textHash = JSON.stringify([text, lineHeight, annotations, textVerticalAnchor, eol, displayEmpty, textPath, x, fontSize, useNoBreakSpace]);
|
|
15040
15062
|
if (cache === undefined || cache !== textHash) {
|
|
15041
15063
|
// Chrome bug:
|
|
15042
15064
|
// <tspan> positions defined as `em` are not updated
|
|
@@ -15061,7 +15083,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
15061
15083
|
x,
|
|
15062
15084
|
textVerticalAnchor,
|
|
15063
15085
|
eol,
|
|
15064
|
-
displayEmpty
|
|
15086
|
+
displayEmpty,
|
|
15087
|
+
useNoBreakSpace
|
|
15065
15088
|
});
|
|
15066
15089
|
$.data.set(node, cacheName, textHash);
|
|
15067
15090
|
}
|
|
@@ -15577,12 +15600,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
15577
15600
|
if (defaults = result(this, 'defaults')) {
|
|
15578
15601
|
//<custom code>
|
|
15579
15602
|
// Replaced the call to _.defaults with util.merge.
|
|
15580
|
-
const customizer = options && options.mergeArrays === true ? false : attributesMerger;
|
|
15603
|
+
const customizer = options && options.mergeArrays === true ? false : config$3.cellDefaultsMergeStrategy || attributesMerger;
|
|
15581
15604
|
attrs = merge({}, defaults, attrs, customizer);
|
|
15582
15605
|
//</custom code>
|
|
15583
15606
|
}
|
|
15584
15607
|
this.set(attrs, options);
|
|
15585
15608
|
this.changed = {};
|
|
15609
|
+
if (options && options.portLayoutNamespace) {
|
|
15610
|
+
this.portLayoutNamespace = options.portLayoutNamespace;
|
|
15611
|
+
}
|
|
15612
|
+
if (options && options.portLabelLayoutNamespace) {
|
|
15613
|
+
this.portLabelLayoutNamespace = options.portLabelLayoutNamespace;
|
|
15614
|
+
}
|
|
15586
15615
|
this.initialize.apply(this, arguments);
|
|
15587
15616
|
},
|
|
15588
15617
|
translate: function (dx, dy, opt) {
|
|
@@ -15976,7 +16005,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
15976
16005
|
if (!opt.deep) {
|
|
15977
16006
|
// Shallow cloning.
|
|
15978
16007
|
|
|
15979
|
-
|
|
16008
|
+
// Preserve the original's `portLayoutNamespace` and `portLabelLayoutNamespace`.
|
|
16009
|
+
const clone = new this.constructor(this.attributes, {
|
|
16010
|
+
portLayoutNamespace: this.portLayoutNamespace,
|
|
16011
|
+
portLabelLayoutNamespace: this.portLabelLayoutNamespace
|
|
16012
|
+
});
|
|
15980
16013
|
// We don't want the clone to have the same ID as the original.
|
|
15981
16014
|
clone.set(this.getIdAttribute(), this.generateId());
|
|
15982
16015
|
// A shallow cloned element does not carry over the original embeds.
|
|
@@ -15988,7 +16021,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
15988
16021
|
} else {
|
|
15989
16022
|
// Deep cloning.
|
|
15990
16023
|
|
|
15991
|
-
// For a deep clone, simply call `
|
|
16024
|
+
// For a deep clone, simply call `util.cloneCells()` with the cell and all its embedded cells.
|
|
15992
16025
|
return toArray$1(cloneCells([this].concat(this.getEmbeddedCells({
|
|
15993
16026
|
deep: true
|
|
15994
16027
|
}))));
|
|
@@ -16053,7 +16086,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16053
16086
|
options.rewrite && unsetByPath(baseAttributes, path, '/');
|
|
16054
16087
|
|
|
16055
16088
|
// Merge update with the model attributes.
|
|
16056
|
-
var attributes = merge(baseAttributes, update);
|
|
16089
|
+
var attributes = merge(baseAttributes, update, config$3.cellMergeStrategy);
|
|
16057
16090
|
// Finally, set the property to the updated attributes.
|
|
16058
16091
|
return this.set(property, attributes[property], options);
|
|
16059
16092
|
} else {
|
|
@@ -16075,11 +16108,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16075
16108
|
// Merging the values of changed attributes with the current ones.
|
|
16076
16109
|
const {
|
|
16077
16110
|
changedValue
|
|
16078
|
-
} = merge({}, {
|
|
16111
|
+
} = merge(merge({}, {
|
|
16079
16112
|
changedValue: this.attributes[key]
|
|
16080
|
-
}, {
|
|
16113
|
+
}), {
|
|
16081
16114
|
changedValue: props[key]
|
|
16082
|
-
});
|
|
16115
|
+
}, config$3.cellMergeStrategy);
|
|
16083
16116
|
changedAttributes[key] = changedValue;
|
|
16084
16117
|
}
|
|
16085
16118
|
return this.set(changedAttributes, options);
|
|
@@ -16313,9 +16346,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16313
16346
|
}
|
|
16314
16347
|
}, {
|
|
16315
16348
|
getAttributeDefinition: function (attrName) {
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16349
|
+
const defNS = this.attributes;
|
|
16350
|
+
const globalDefNS = attributes;
|
|
16351
|
+
const definition = defNS && defNS[attrName] || globalDefNS[attrName];
|
|
16352
|
+
return definition !== undefined ? definition : null;
|
|
16319
16353
|
},
|
|
16320
16354
|
define: function (type, defaults, protoProps, staticProps) {
|
|
16321
16355
|
protoProps = assign({
|
|
@@ -16621,6 +16655,22 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16621
16655
|
wrappers: wrappers
|
|
16622
16656
|
};
|
|
16623
16657
|
|
|
16658
|
+
function parseCoordinate(coordinate, dimension, bbox, value) {
|
|
16659
|
+
if (isPercentage(value)) {
|
|
16660
|
+
return parseFloat(value) / 100 * bbox[dimension];
|
|
16661
|
+
}
|
|
16662
|
+
if (isCalcExpression(value)) {
|
|
16663
|
+
return Number(evalCalcExpression(value, bbox));
|
|
16664
|
+
}
|
|
16665
|
+
if (typeof value === 'string') {
|
|
16666
|
+
const num = Number(value);
|
|
16667
|
+
if (isNaN(num)) {
|
|
16668
|
+
throw new TypeError(`Cannot convert port coordinate ${coordinate}: "${value}" to a number`);
|
|
16669
|
+
}
|
|
16670
|
+
return num;
|
|
16671
|
+
}
|
|
16672
|
+
return value;
|
|
16673
|
+
}
|
|
16624
16674
|
function portTransformAttrs(point, angle, opt) {
|
|
16625
16675
|
var trans = point.toJSON();
|
|
16626
16676
|
trans.angle = angle || 0;
|
|
@@ -16664,19 +16714,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16664
16714
|
y,
|
|
16665
16715
|
angle
|
|
16666
16716
|
} = args;
|
|
16667
|
-
if (isPercentage(x)) {
|
|
16668
|
-
x = parseFloat(x) / 100 * bbox.width;
|
|
16669
|
-
} else if (isCalcExpression(x)) {
|
|
16670
|
-
x = Number(evalCalcExpression(x, bbox));
|
|
16671
|
-
}
|
|
16672
|
-
if (isPercentage(y)) {
|
|
16673
|
-
y = parseFloat(y) / 100 * bbox.height;
|
|
16674
|
-
} else if (isCalcExpression(y)) {
|
|
16675
|
-
y = Number(evalCalcExpression(y, bbox));
|
|
16676
|
-
}
|
|
16677
16717
|
return {
|
|
16678
|
-
x,
|
|
16679
|
-
y,
|
|
16718
|
+
x: parseCoordinate('x', 'width', bbox, x),
|
|
16719
|
+
y: parseCoordinate('y', 'height', bbox, y),
|
|
16680
16720
|
angle
|
|
16681
16721
|
};
|
|
16682
16722
|
}
|
|
@@ -16696,7 +16736,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16696
16736
|
* @param {Object=} opt opt Group options
|
|
16697
16737
|
* @returns {Array<g.Point>}
|
|
16698
16738
|
*/
|
|
16699
|
-
const absolute = function (ports, elBBox) {
|
|
16739
|
+
const absolute = function (ports, elBBox, opt) {
|
|
16700
16740
|
return ports.map(port => {
|
|
16701
16741
|
const transformation = argPoint(elBBox, port).round().toJSON();
|
|
16702
16742
|
transformation.angle = port.angle || 0;
|
|
@@ -16705,6 +16745,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16705
16745
|
};
|
|
16706
16746
|
|
|
16707
16747
|
/**
|
|
16748
|
+
* @deprecated
|
|
16708
16749
|
* @param {Array<Object>} ports
|
|
16709
16750
|
* @param {g.Rect} elBBox
|
|
16710
16751
|
* @param {Object=} opt opt Group options
|
|
@@ -16969,7 +17010,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
16969
17010
|
}
|
|
16970
17011
|
});
|
|
16971
17012
|
}
|
|
16972
|
-
const manual = function (
|
|
17013
|
+
const manual = function (portPosition, elBBox, opt) {
|
|
16973
17014
|
return labelAttributes(opt);
|
|
16974
17015
|
};
|
|
16975
17016
|
const left$1 = function (portPosition, elBBox, opt) {
|
|
@@ -17050,13 +17091,20 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17050
17091
|
top: top$1
|
|
17051
17092
|
};
|
|
17052
17093
|
|
|
17053
|
-
|
|
17054
|
-
|
|
17094
|
+
const DEFAULT_PORT_POSITION_NAME = 'left';
|
|
17095
|
+
const DEFAULT_ABSOLUTE_PORT_POSITION_NAME = 'absolute';
|
|
17096
|
+
const DEFAULT_PORT_LABEL_POSITION_NAME = 'left';
|
|
17097
|
+
const PortData = function (model) {
|
|
17098
|
+
const {
|
|
17099
|
+
portLayoutNamespace = Port,
|
|
17100
|
+
portLabelLayoutNamespace = PortLabel
|
|
17101
|
+
} = model;
|
|
17102
|
+
const clonedData = cloneDeep(model.get('ports')) || {};
|
|
17055
17103
|
this.ports = [];
|
|
17056
17104
|
this.portsMap = {};
|
|
17057
17105
|
this.groups = {};
|
|
17058
|
-
this.portLayoutNamespace =
|
|
17059
|
-
this.portLabelLayoutNamespace =
|
|
17106
|
+
this.portLayoutNamespace = portLayoutNamespace;
|
|
17107
|
+
this.portLabelLayoutNamespace = portLabelLayoutNamespace;
|
|
17060
17108
|
this.metrics = {};
|
|
17061
17109
|
this.metricsKey = null;
|
|
17062
17110
|
this._init(clonedData);
|
|
@@ -17081,6 +17129,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17081
17129
|
return port.group === groupName;
|
|
17082
17130
|
});
|
|
17083
17131
|
},
|
|
17132
|
+
// Calculate SVG transformations based on evaluated group + port data
|
|
17133
|
+
// NOTE: This function is also called for ports without a group (groupName = undefined)
|
|
17084
17134
|
getGroupPortsMetrics: function (groupName, rect) {
|
|
17085
17135
|
const {
|
|
17086
17136
|
x = 0,
|
|
@@ -17099,29 +17149,36 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17099
17149
|
// Return cached metrics
|
|
17100
17150
|
return groupPortsMetrics;
|
|
17101
17151
|
}
|
|
17152
|
+
|
|
17102
17153
|
// Calculate the metrics
|
|
17103
17154
|
groupPortsMetrics = this.resolveGroupPortsMetrics(groupName, new Rect(x, y, width, height));
|
|
17104
17155
|
this.metrics[groupName] = groupPortsMetrics;
|
|
17105
17156
|
return groupPortsMetrics;
|
|
17106
17157
|
},
|
|
17107
17158
|
resolveGroupPortsMetrics: function (groupName, elBBox) {
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
if (!namespace[groupPositionName]) {
|
|
17114
|
-
groupPositionName = 'left';
|
|
17115
|
-
}
|
|
17116
|
-
var groupArgs = groupPosition.args || {};
|
|
17117
|
-
var portsArgs = ports.map(function (port) {
|
|
17159
|
+
// `groupName` of `undefined` (= not a string) means "the group of ports which do not have the `group` property".
|
|
17160
|
+
const isNoGroup = groupName === undefined;
|
|
17161
|
+
const group = this.getGroup(groupName);
|
|
17162
|
+
const ports = this.getPortsByGroup(groupName);
|
|
17163
|
+
const portsArgs = ports.map(function (port) {
|
|
17118
17164
|
return port && port.position && port.position.args;
|
|
17119
17165
|
});
|
|
17120
|
-
|
|
17121
|
-
|
|
17166
|
+
|
|
17167
|
+
// Get an array of transformations of individual ports according to the group's port layout function:
|
|
17168
|
+
let groupPortTransformations;
|
|
17169
|
+
if (isNoGroup) {
|
|
17170
|
+
// Apply default port layout function to the set of ports without `group` property.
|
|
17171
|
+
const noGroup = this._evaluateGroup({});
|
|
17172
|
+
groupPortTransformations = this._getGroupPortTransformations(noGroup, portsArgs, elBBox);
|
|
17173
|
+
} else {
|
|
17174
|
+
groupPortTransformations = this._getGroupPortTransformations(group, portsArgs, elBBox);
|
|
17175
|
+
}
|
|
17176
|
+
let accumulator = {
|
|
17122
17177
|
ports: ports,
|
|
17123
17178
|
result: {}
|
|
17124
17179
|
};
|
|
17180
|
+
|
|
17181
|
+
// For each individual port transformation, find the information necessary to calculate SVG transformations:
|
|
17125
17182
|
toArray$1(groupPortTransformations).reduce((res, portTransformation, index) => {
|
|
17126
17183
|
const port = res.ports[index];
|
|
17127
17184
|
const portId = port.id;
|
|
@@ -17129,7 +17186,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17129
17186
|
index,
|
|
17130
17187
|
portId,
|
|
17131
17188
|
portTransformation: portTransformation,
|
|
17132
|
-
labelTransformation: this.
|
|
17189
|
+
labelTransformation: this._getPortLabelTransformation(port, Point(portTransformation), elBBox),
|
|
17133
17190
|
portAttrs: port.attrs,
|
|
17134
17191
|
portSize: port.size,
|
|
17135
17192
|
labelSize: port.label.size
|
|
@@ -17138,16 +17195,24 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17138
17195
|
}, accumulator);
|
|
17139
17196
|
return accumulator.result;
|
|
17140
17197
|
},
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17198
|
+
_getGroupPortTransformations: function (group, portsArgs, elBBox) {
|
|
17199
|
+
const groupPosition = group.position || {};
|
|
17200
|
+
const groupPositionArgs = groupPosition.args || {};
|
|
17201
|
+
const groupPositionLayoutCallback = groupPosition.layoutCallback;
|
|
17202
|
+
return groupPositionLayoutCallback(portsArgs, elBBox, groupPositionArgs);
|
|
17203
|
+
},
|
|
17204
|
+
_getPortLabelTransformation: function (port, portPosition, elBBox) {
|
|
17205
|
+
const portLabelPosition = port.label.position || {};
|
|
17206
|
+
const portLabelPositionArgs = portLabelPosition.args || {};
|
|
17207
|
+
const portLabelPositionLayoutCallback = portLabelPosition.layoutCallback;
|
|
17208
|
+
if (portLabelPositionLayoutCallback) {
|
|
17209
|
+
return portLabelPositionLayoutCallback(portPosition, elBBox, portLabelPositionArgs);
|
|
17146
17210
|
}
|
|
17147
17211
|
return null;
|
|
17148
17212
|
},
|
|
17149
17213
|
_init: function (data) {
|
|
17150
|
-
//
|
|
17214
|
+
// Prepare groups:
|
|
17215
|
+
// NOTE: This overwrites passed group properties with evaluated group properties.
|
|
17151
17216
|
if (isObject(data.groups)) {
|
|
17152
17217
|
var groups = Object.keys(data.groups);
|
|
17153
17218
|
for (var i = 0, n = groups.length; i < n; i++) {
|
|
@@ -17156,7 +17221,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17156
17221
|
}
|
|
17157
17222
|
}
|
|
17158
17223
|
|
|
17159
|
-
//
|
|
17224
|
+
// Prepare ports:
|
|
17225
|
+
// NOTE: This overwrites passed port properties with evaluated port properties, plus mixed-in evaluated group properties (see above).
|
|
17160
17226
|
var ports = toArray$1(data.items);
|
|
17161
17227
|
for (var j = 0, m = ports.length; j < m; j++) {
|
|
17162
17228
|
const resolvedPort = this._evaluatePort(ports[j]);
|
|
@@ -17165,23 +17231,155 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17165
17231
|
}
|
|
17166
17232
|
},
|
|
17167
17233
|
_evaluateGroup: function (group) {
|
|
17168
|
-
return merge(group, {
|
|
17169
|
-
position: this.
|
|
17170
|
-
label: this.
|
|
17234
|
+
return merge({}, group, {
|
|
17235
|
+
position: this._evaluateGroupPositionProperty(group),
|
|
17236
|
+
label: this._evaluateGroupLabelProperty(group)
|
|
17237
|
+
});
|
|
17238
|
+
},
|
|
17239
|
+
_evaluateGroupPositionProperty: function (group) {
|
|
17240
|
+
const namespace = this.portLayoutNamespace;
|
|
17241
|
+
const groupPosition = group.position;
|
|
17242
|
+
if (groupPosition === undefined) {
|
|
17243
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_POSITION_NAME, 'Default port group');
|
|
17244
|
+
return {
|
|
17245
|
+
layoutCallback
|
|
17246
|
+
};
|
|
17247
|
+
} else if (isFunction(groupPosition)) {
|
|
17248
|
+
return {
|
|
17249
|
+
layoutCallback: groupPosition
|
|
17250
|
+
};
|
|
17251
|
+
} else if (isObject(groupPosition)) {
|
|
17252
|
+
if (groupPosition.name) {
|
|
17253
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupPosition.name, 'Provided port group');
|
|
17254
|
+
return {
|
|
17255
|
+
layoutCallback,
|
|
17256
|
+
args: groupPosition.args
|
|
17257
|
+
};
|
|
17258
|
+
} else {
|
|
17259
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_POSITION_NAME, 'Default port group');
|
|
17260
|
+
return {
|
|
17261
|
+
layoutCallback,
|
|
17262
|
+
args: groupPosition.args
|
|
17263
|
+
};
|
|
17264
|
+
}
|
|
17265
|
+
} else if (isString(groupPosition)) {
|
|
17266
|
+
// TODO: Remove legacy signature (see `this._evaluateGroupLabelPositionProperty()`).
|
|
17267
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupPosition, 'Provided port group');
|
|
17268
|
+
return {
|
|
17269
|
+
layoutCallback
|
|
17270
|
+
};
|
|
17271
|
+
} else if (Array.isArray(groupPosition)) {
|
|
17272
|
+
// TODO: Remove legacy signature (see `this._evaluateGroupLabelPositionProperty()`).
|
|
17273
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_ABSOLUTE_PORT_POSITION_NAME, 'Default absolute port group');
|
|
17274
|
+
return {
|
|
17275
|
+
layoutCallback,
|
|
17276
|
+
args: {
|
|
17277
|
+
x: groupPosition[0],
|
|
17278
|
+
y: groupPosition[1]
|
|
17279
|
+
}
|
|
17280
|
+
};
|
|
17281
|
+
} else {
|
|
17282
|
+
throw new Error('dia.Element: Provided port group position value has an invalid type.');
|
|
17283
|
+
}
|
|
17284
|
+
},
|
|
17285
|
+
_evaluateGroupLabelProperty: function (group) {
|
|
17286
|
+
const groupLabel = group.label;
|
|
17287
|
+
if (!groupLabel) {
|
|
17288
|
+
return {
|
|
17289
|
+
position: this._evaluateGroupLabelPositionProperty({})
|
|
17290
|
+
};
|
|
17291
|
+
}
|
|
17292
|
+
return merge({}, groupLabel, {
|
|
17293
|
+
position: this._evaluateGroupLabelPositionProperty(groupLabel)
|
|
17171
17294
|
});
|
|
17172
17295
|
},
|
|
17296
|
+
_evaluateGroupLabelPositionProperty: function (groupLabel) {
|
|
17297
|
+
const namespace = this.portLabelLayoutNamespace;
|
|
17298
|
+
const groupLabelPosition = groupLabel.position;
|
|
17299
|
+
if (groupLabelPosition === undefined) {
|
|
17300
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_LABEL_POSITION_NAME, 'Default port group label');
|
|
17301
|
+
return {
|
|
17302
|
+
layoutCallback
|
|
17303
|
+
};
|
|
17304
|
+
} else if (isFunction(groupLabelPosition)) {
|
|
17305
|
+
return {
|
|
17306
|
+
layoutCallback: groupLabelPosition
|
|
17307
|
+
};
|
|
17308
|
+
} else if (isObject(groupLabelPosition)) {
|
|
17309
|
+
if (groupLabelPosition.name) {
|
|
17310
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupLabelPosition.name, 'Provided port group label');
|
|
17311
|
+
return {
|
|
17312
|
+
layoutCallback,
|
|
17313
|
+
args: groupLabelPosition.args
|
|
17314
|
+
};
|
|
17315
|
+
} else {
|
|
17316
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_LABEL_POSITION_NAME, 'Default port group label');
|
|
17317
|
+
return {
|
|
17318
|
+
layoutCallback,
|
|
17319
|
+
args: groupLabelPosition.args
|
|
17320
|
+
};
|
|
17321
|
+
}
|
|
17322
|
+
} else {
|
|
17323
|
+
throw new Error('dia.Element: Provided port group label position value has an invalid type.');
|
|
17324
|
+
}
|
|
17325
|
+
},
|
|
17173
17326
|
_evaluatePort: function (port) {
|
|
17174
|
-
|
|
17175
|
-
|
|
17327
|
+
const group = this.getGroup(port.group);
|
|
17328
|
+
const evaluated = assign({}, port);
|
|
17176
17329
|
evaluated.markup = evaluated.markup || group.markup;
|
|
17177
17330
|
evaluated.attrs = merge({}, group.attrs, evaluated.attrs);
|
|
17178
|
-
evaluated.position = this.
|
|
17179
|
-
evaluated.label =
|
|
17180
|
-
evaluated.z = this.
|
|
17331
|
+
evaluated.position = this._evaluatePortPositionProperty(group, evaluated);
|
|
17332
|
+
evaluated.label = this._evaluatePortLabelProperty(group, evaluated);
|
|
17333
|
+
evaluated.z = this._evaluatePortZProperty(group, evaluated);
|
|
17181
17334
|
evaluated.size = assign({}, group.size, evaluated.size);
|
|
17182
17335
|
return evaluated;
|
|
17183
17336
|
},
|
|
17184
|
-
|
|
17337
|
+
_evaluatePortPositionProperty: function (group, port) {
|
|
17338
|
+
return {
|
|
17339
|
+
args: merge({},
|
|
17340
|
+
// NOTE: `x != null` is equivalent to `x !== null && x !== undefined`.
|
|
17341
|
+
group.position != null ? group.position.args : {},
|
|
17342
|
+
// Port can overwrite `group.position.args` via `port.position.args` or `port.args`.
|
|
17343
|
+
// TODO: Remove `port.args` backwards compatibility.
|
|
17344
|
+
port.position != null && port.position.args != null ? port.position.args : port.args)
|
|
17345
|
+
};
|
|
17346
|
+
},
|
|
17347
|
+
_evaluatePortLabelProperty: function (group, port) {
|
|
17348
|
+
const groupLabel = group.label;
|
|
17349
|
+
const portLabel = port.label;
|
|
17350
|
+
if (!portLabel) {
|
|
17351
|
+
return assign({}, groupLabel);
|
|
17352
|
+
}
|
|
17353
|
+
return merge({}, groupLabel, merge({}, portLabel, {
|
|
17354
|
+
position: this._evaluatePortLabelPositionProperty(portLabel)
|
|
17355
|
+
}));
|
|
17356
|
+
},
|
|
17357
|
+
_evaluatePortLabelPositionProperty: function (portLabel) {
|
|
17358
|
+
const namespace = this.portLabelLayoutNamespace;
|
|
17359
|
+
const portLabelPosition = portLabel.position;
|
|
17360
|
+
if (portLabelPosition === undefined) {
|
|
17361
|
+
return {};
|
|
17362
|
+
} else if (isFunction(portLabelPosition)) {
|
|
17363
|
+
return {
|
|
17364
|
+
layoutCallback: portLabelPosition
|
|
17365
|
+
};
|
|
17366
|
+
} else if (isObject(portLabelPosition)) {
|
|
17367
|
+
if (portLabelPosition.name) {
|
|
17368
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, portLabelPosition.name, 'Provided port label');
|
|
17369
|
+
return {
|
|
17370
|
+
layoutCallback,
|
|
17371
|
+
args: portLabelPosition.args
|
|
17372
|
+
};
|
|
17373
|
+
} else {
|
|
17374
|
+
return {
|
|
17375
|
+
args: portLabelPosition.args
|
|
17376
|
+
};
|
|
17377
|
+
}
|
|
17378
|
+
} else {
|
|
17379
|
+
throw new Error('dia.Element: Provided port label position value has an invalid type.');
|
|
17380
|
+
}
|
|
17381
|
+
},
|
|
17382
|
+
_evaluatePortZProperty: function (group, port) {
|
|
17185
17383
|
if (isNumber(port.z)) {
|
|
17186
17384
|
return port.z;
|
|
17187
17385
|
}
|
|
@@ -17190,47 +17388,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17190
17388
|
}
|
|
17191
17389
|
return 'auto';
|
|
17192
17390
|
},
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
}, group.position, {
|
|
17198
|
-
// TODO: remove `port.args` backwards compatibility
|
|
17199
|
-
// NOTE: `x != null` is equivalent to `x !== null && x !== undefined`
|
|
17200
|
-
args: port.position != null && port.position.args != null ? port.position.args : port.args
|
|
17201
|
-
});
|
|
17202
|
-
},
|
|
17203
|
-
_getPosition: function (position, setDefault) {
|
|
17204
|
-
var args = {};
|
|
17205
|
-
var positionName;
|
|
17206
|
-
if (isFunction(position)) {
|
|
17207
|
-
positionName = 'fn';
|
|
17208
|
-
args.fn = position;
|
|
17209
|
-
} else if (isString(position)) {
|
|
17210
|
-
positionName = position;
|
|
17211
|
-
} else if (position === undefined) {
|
|
17212
|
-
positionName = setDefault ? 'left' : null;
|
|
17213
|
-
} else if (Array.isArray(position)) {
|
|
17214
|
-
positionName = 'absolute';
|
|
17215
|
-
args.x = position[0];
|
|
17216
|
-
args.y = position[1];
|
|
17217
|
-
} else if (isObject(position)) {
|
|
17218
|
-
positionName = position.name;
|
|
17219
|
-
assign(args, position.args);
|
|
17220
|
-
}
|
|
17221
|
-
var result = {
|
|
17222
|
-
args: args
|
|
17223
|
-
};
|
|
17224
|
-
if (positionName) {
|
|
17225
|
-
result.name = positionName;
|
|
17391
|
+
_resolveLayoutCallbackOrThrow: function (namespace, name, errorSubstring) {
|
|
17392
|
+
const layoutCallback = namespace[name];
|
|
17393
|
+
if (!layoutCallback) {
|
|
17394
|
+
throw new Error(`dia.Element: ${errorSubstring} layout name is not recognized.`);
|
|
17226
17395
|
}
|
|
17227
|
-
return
|
|
17228
|
-
},
|
|
17229
|
-
_getLabel: function (item, setDefaults) {
|
|
17230
|
-
var label = item.label || {};
|
|
17231
|
-
var ret = label;
|
|
17232
|
-
ret.position = this._getPosition(label.position, setDefaults);
|
|
17233
|
-
return ret;
|
|
17396
|
+
return layoutCallback;
|
|
17234
17397
|
}
|
|
17235
17398
|
};
|
|
17236
17399
|
const elementPortPrototype = {
|
|
@@ -17570,7 +17733,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
17570
17733
|
if (this._portSettingsData) {
|
|
17571
17734
|
prevPortData = this._portSettingsData.getPorts();
|
|
17572
17735
|
}
|
|
17573
|
-
this._portSettingsData = new PortData(this
|
|
17736
|
+
this._portSettingsData = new PortData(this);
|
|
17574
17737
|
var curPortData = this._portSettingsData.getPorts();
|
|
17575
17738
|
if (prevPortData) {
|
|
17576
17739
|
var added = curPortData.filter(function (item) {
|
|
@@ -18278,8 +18441,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
18278
18441
|
_fitToElements: function (opt = {}) {
|
|
18279
18442
|
let minBBox = null;
|
|
18280
18443
|
if (opt.minRect) {
|
|
18281
|
-
// Coerce `opt.minRect` to g.Rect
|
|
18282
|
-
|
|
18444
|
+
// Coerce `opt.minRect` to g.Rect
|
|
18445
|
+
// (missing properties are taken from this element's current bbox).
|
|
18446
|
+
const minRect = assign(this.getBBox(), opt.minRect);
|
|
18447
|
+
minBBox = new Rect(minRect);
|
|
18283
18448
|
}
|
|
18284
18449
|
const elementsBBox = this.graph.getCellsBBox(opt.elements);
|
|
18285
18450
|
// If no `opt.elements` were provided, do nothing (but if `opt.minRect` was provided, set that as this element's bbox instead).
|
|
@@ -18949,9 +19114,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
18949
19114
|
svgforeignobject: function () {
|
|
18950
19115
|
return !!document.createElementNS && /SVGForeignObject/.test({}.toString.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
|
|
18951
19116
|
},
|
|
18952
|
-
// works for iOS
|
|
18953
|
-
|
|
18954
|
-
|
|
19117
|
+
// works for: (1) macOS Safari, (2) any WKWebView, (3) any iOS browser (including Safari, CriOS, EdgiOS, OPR, FxiOS)
|
|
19118
|
+
isAppleWebKit: function () {
|
|
19119
|
+
const userAgent = navigator.userAgent;
|
|
19120
|
+
const isAppleWebKit = /applewebkit/i.test(userAgent);
|
|
19121
|
+
const isChromium = /chrome/i.test(userAgent); // e.g. Chrome, Edge, Opera, SamsungBrowser
|
|
19122
|
+
return isAppleWebKit && !isChromium;
|
|
18955
19123
|
}
|
|
18956
19124
|
},
|
|
18957
19125
|
addTest: function (name, fn) {
|
|
@@ -20825,7 +20993,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
20825
20993
|
// Creating a ViewBase creates its initial element outside of the DOM,
|
|
20826
20994
|
// if an existing element is not provided...
|
|
20827
20995
|
var ViewBase = function (options) {
|
|
20828
|
-
this.cid = uniqueId('view');
|
|
20996
|
+
this.cid = options && options.cid || uniqueId('view');
|
|
20829
20997
|
this.preinitialize.apply(this, arguments);
|
|
20830
20998
|
assign(this, pick(options, viewOptions));
|
|
20831
20999
|
this._ensureElement();
|
|
@@ -20981,8 +21149,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
20981
21149
|
childNodes: null,
|
|
20982
21150
|
DETACHABLE: true,
|
|
20983
21151
|
UPDATE_PRIORITY: 2,
|
|
21152
|
+
/** @deprecated is no longer used (moved to Paper) */
|
|
20984
21153
|
FLAG_INSERT: 1 << 30,
|
|
21154
|
+
/** @deprecated is no longer used */
|
|
20985
21155
|
FLAG_REMOVE: 1 << 29,
|
|
21156
|
+
/** @deprecated is no longer used */
|
|
20986
21157
|
FLAG_INIT: 1 << 28,
|
|
20987
21158
|
constructor: function (options) {
|
|
20988
21159
|
this.requireSetThemeOverride = options && !!options.theme;
|
|
@@ -22094,6 +22265,31 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
22094
22265
|
return null;
|
|
22095
22266
|
}
|
|
22096
22267
|
},
|
|
22268
|
+
// Check if the cellView has a highlighter with the given `id`.
|
|
22269
|
+
// If no `id` is provided, it checks if the cellView has any highlighter.
|
|
22270
|
+
has(cellView, id = null) {
|
|
22271
|
+
const {
|
|
22272
|
+
cid
|
|
22273
|
+
} = cellView;
|
|
22274
|
+
const {
|
|
22275
|
+
_views
|
|
22276
|
+
} = this;
|
|
22277
|
+
const refs = _views[cid];
|
|
22278
|
+
if (!refs) return false;
|
|
22279
|
+
if (id === null) {
|
|
22280
|
+
// any highlighter
|
|
22281
|
+
for (let hid in refs) {
|
|
22282
|
+
if (refs[hid] instanceof this) return true;
|
|
22283
|
+
}
|
|
22284
|
+
return false;
|
|
22285
|
+
} else {
|
|
22286
|
+
// single highlighter
|
|
22287
|
+
if (id in refs) {
|
|
22288
|
+
if (refs[id] instanceof this) return true;
|
|
22289
|
+
}
|
|
22290
|
+
return false;
|
|
22291
|
+
}
|
|
22292
|
+
},
|
|
22097
22293
|
add(cellView, nodeSelector, id, opt = {}) {
|
|
22098
22294
|
if (!id) throw new Error('dia.HighlighterView: An ID required.');
|
|
22099
22295
|
// Search the existing view amongst all the highlighters
|
|
@@ -28837,6 +29033,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
28837
29033
|
}
|
|
28838
29034
|
});
|
|
28839
29035
|
|
|
29036
|
+
// Internal tag to identify this object as a cell view instance.
|
|
29037
|
+
// Used instead of `instanceof` for performance and cross-frame safety.
|
|
29038
|
+
|
|
29039
|
+
const CELL_VIEW_MARKER = Symbol('joint.cellViewMarker');
|
|
29040
|
+
Object.defineProperty(CellView.prototype, CELL_VIEW_MARKER, {
|
|
29041
|
+
value: true
|
|
29042
|
+
});
|
|
29043
|
+
|
|
28840
29044
|
const Flags$1 = {
|
|
28841
29045
|
TOOLS: CellView.Flags.TOOLS,
|
|
28842
29046
|
UPDATE: 'UPDATE',
|
|
@@ -29190,7 +29394,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
29190
29394
|
});
|
|
29191
29395
|
data.initialParentId = parentId;
|
|
29192
29396
|
} else {
|
|
29193
|
-
data.initialParentId
|
|
29397
|
+
// `data.initialParentId` can be explicitly set to a dummy value to enable validation of unembedding.
|
|
29398
|
+
data.initialParentId = data.initialParentId || null;
|
|
29194
29399
|
}
|
|
29195
29400
|
},
|
|
29196
29401
|
processEmbedding: function (data = {}, evt, x, y) {
|
|
@@ -29669,6 +29874,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
29669
29874
|
_labelCache: null,
|
|
29670
29875
|
_labelSelectors: null,
|
|
29671
29876
|
_V: null,
|
|
29877
|
+
_sourceMagnet: null,
|
|
29878
|
+
_targetMagnet: null,
|
|
29672
29879
|
_dragData: null,
|
|
29673
29880
|
// deprecated
|
|
29674
29881
|
|
|
@@ -29705,23 +29912,34 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
29705
29912
|
initFlag: [Flags.RENDER, Flags.SOURCE, Flags.TARGET, Flags.TOOLS],
|
|
29706
29913
|
UPDATE_PRIORITY: 1,
|
|
29707
29914
|
EPSILON: 1e-6,
|
|
29708
|
-
confirmUpdate: function (flags, opt) {
|
|
29709
|
-
|
|
29915
|
+
confirmUpdate: function (flags, opt = {}) {
|
|
29916
|
+
const {
|
|
29917
|
+
paper,
|
|
29918
|
+
model
|
|
29919
|
+
} = this;
|
|
29920
|
+
const {
|
|
29921
|
+
attributes
|
|
29922
|
+
} = model;
|
|
29923
|
+
const {
|
|
29924
|
+
source: {
|
|
29925
|
+
id: sourceId
|
|
29926
|
+
},
|
|
29927
|
+
target: {
|
|
29928
|
+
id: targetId
|
|
29929
|
+
}
|
|
29930
|
+
} = attributes;
|
|
29710
29931
|
if (this.hasFlag(flags, Flags.SOURCE)) {
|
|
29711
|
-
|
|
29932
|
+
this._sourceMagnet = null; // reset cached source magnet
|
|
29933
|
+
this.checkEndModel('source', sourceId);
|
|
29712
29934
|
flags = this.removeFlag(flags, Flags.SOURCE);
|
|
29713
29935
|
}
|
|
29714
29936
|
if (this.hasFlag(flags, Flags.TARGET)) {
|
|
29715
|
-
|
|
29937
|
+
this._targetMagnet = null; // reset cached target magnet
|
|
29938
|
+
this.checkEndModel('target', targetId);
|
|
29716
29939
|
flags = this.removeFlag(flags, Flags.TARGET);
|
|
29717
29940
|
}
|
|
29718
|
-
|
|
29719
|
-
|
|
29720
|
-
sourceView,
|
|
29721
|
-
targetView
|
|
29722
|
-
} = this;
|
|
29723
|
-
if (paper && (sourceView && !paper.isViewMounted(sourceView) || targetView && !paper.isViewMounted(targetView))) {
|
|
29724
|
-
// Wait for the sourceView and targetView to be rendered
|
|
29941
|
+
if (paper && (sourceId && !paper.isCellVisible(sourceId) || targetId && !paper.isCellVisible(targetId))) {
|
|
29942
|
+
// Wait for the source and target views to be rendered
|
|
29725
29943
|
return flags;
|
|
29726
29944
|
}
|
|
29727
29945
|
if (this.hasFlag(flags, Flags.RENDER)) {
|
|
@@ -29729,18 +29947,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
29729
29947
|
this.updateHighlighters(true);
|
|
29730
29948
|
this.updateTools(opt);
|
|
29731
29949
|
flags = this.removeFlag(flags, [Flags.RENDER, Flags.UPDATE, Flags.LABELS, Flags.TOOLS, Flags.CONNECTOR]);
|
|
29732
|
-
if (env.test('
|
|
29733
|
-
this.
|
|
29950
|
+
if (env.test('isAppleWebKit')) {
|
|
29951
|
+
this.__fixWebKitBug268376();
|
|
29734
29952
|
}
|
|
29735
29953
|
return flags;
|
|
29736
29954
|
}
|
|
29737
29955
|
let updateHighlighters = false;
|
|
29738
|
-
const {
|
|
29739
|
-
model
|
|
29740
|
-
} = this;
|
|
29741
|
-
const {
|
|
29742
|
-
attributes
|
|
29743
|
-
} = model;
|
|
29744
29956
|
let updateLabels = this.hasFlag(flags, Flags.LABELS);
|
|
29745
29957
|
if (updateLabels) {
|
|
29746
29958
|
this.onLabelsChange(model, attributes.labels, opt);
|
|
@@ -29779,8 +29991,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
29779
29991
|
}
|
|
29780
29992
|
return flags;
|
|
29781
29993
|
},
|
|
29782
|
-
|
|
29783
|
-
//
|
|
29994
|
+
__fixWebKitBug268376: function () {
|
|
29995
|
+
// WebKit has a bug where any change after the first render is not reflected in the DOM.
|
|
29784
29996
|
// https://bugs.webkit.org/show_bug.cgi?id=268376
|
|
29785
29997
|
const {
|
|
29786
29998
|
el
|
|
@@ -30449,40 +30661,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
30449
30661
|
if (id && id in metrics) delete metrics[id].magnetMatrix;
|
|
30450
30662
|
}
|
|
30451
30663
|
},
|
|
30452
|
-
|
|
30453
|
-
|
|
30454
|
-
|
|
30455
|
-
|
|
30456
|
-
|
|
30457
|
-
const endViewProperty = `${endType}View`;
|
|
30458
|
-
const endDef = model.get(endType);
|
|
30459
|
-
const endId = endDef && endDef.id;
|
|
30460
|
-
if (!endId) {
|
|
30461
|
-
// the link end is a point ~ rect 0x0
|
|
30462
|
-
this[endViewProperty] = null;
|
|
30463
|
-
this.updateEndMagnet(endType);
|
|
30464
|
-
return true;
|
|
30465
|
-
}
|
|
30466
|
-
const endModel = paper.getModelById(endId);
|
|
30467
|
-
if (!endModel) throw new Error('LinkView: invalid ' + endType + ' cell.');
|
|
30468
|
-
const endView = endModel.findView(paper);
|
|
30469
|
-
if (!endView) {
|
|
30470
|
-
// A view for a model should always exist
|
|
30471
|
-
return false;
|
|
30472
|
-
}
|
|
30473
|
-
this[endViewProperty] = endView;
|
|
30474
|
-
this.updateEndMagnet(endType);
|
|
30475
|
-
return true;
|
|
30476
|
-
},
|
|
30477
|
-
updateEndMagnet: function (endType) {
|
|
30478
|
-
const endMagnetProperty = `${endType}Magnet`;
|
|
30479
|
-
const endView = this.getEndView(endType);
|
|
30480
|
-
if (endView) {
|
|
30481
|
-
let connectedMagnet = endView.getMagnetFromLinkEnd(this.model.get(endType));
|
|
30482
|
-
if (connectedMagnet === endView.el) connectedMagnet = null;
|
|
30483
|
-
this[endMagnetProperty] = connectedMagnet;
|
|
30484
|
-
} else {
|
|
30485
|
-
this[endMagnetProperty] = null;
|
|
30664
|
+
checkEndModel: function (endType, endId) {
|
|
30665
|
+
if (!endId) return;
|
|
30666
|
+
const endModel = this.paper.getModelById(endId);
|
|
30667
|
+
if (!endModel) {
|
|
30668
|
+
throw new Error(`LinkView: invalid ${endType} cell.`);
|
|
30486
30669
|
}
|
|
30487
30670
|
},
|
|
30488
30671
|
_getLabelPositionProperty: function (idx) {
|
|
@@ -31247,52 +31430,30 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
31247
31430
|
let isSnapped = false;
|
|
31248
31431
|
// checking view in close area of the pointer
|
|
31249
31432
|
|
|
31250
|
-
|
|
31251
|
-
|
|
31252
|
-
|
|
31253
|
-
|
|
31254
|
-
|
|
31255
|
-
height: 2 * r
|
|
31256
|
-
}, snapLinks.findInAreaOptions);
|
|
31257
|
-
var prevClosestView = data.closestView || null;
|
|
31258
|
-
var prevClosestMagnet = data.closestMagnet || null;
|
|
31259
|
-
var prevMagnetProxy = data.magnetProxy || null;
|
|
31433
|
+
const radius = snapLinks.radius || 50;
|
|
31434
|
+
const findInAreaOptions = snapLinks.findInAreaOptions;
|
|
31435
|
+
const prevClosestView = data.closestView || null;
|
|
31436
|
+
const prevClosestMagnet = data.closestMagnet || null;
|
|
31437
|
+
const prevMagnetProxy = data.magnetProxy || null;
|
|
31260
31438
|
data.closestView = data.closestMagnet = data.magnetProxy = null;
|
|
31261
|
-
|
|
31262
|
-
|
|
31263
|
-
|
|
31264
|
-
|
|
31265
|
-
// skip connecting to the element in case '.': { magnet: false } attribute present
|
|
31266
|
-
if (view.el.getAttribute('magnet') !== 'false') {
|
|
31267
|
-
candidates.push({
|
|
31268
|
-
bbox: view.model.getBBox(),
|
|
31269
|
-
magnet: view.el
|
|
31270
|
-
});
|
|
31439
|
+
const isValidCandidate = (view, magnet) => {
|
|
31440
|
+
// Do not snap to the current view
|
|
31441
|
+
if (view === this) {
|
|
31442
|
+
return false;
|
|
31271
31443
|
}
|
|
31272
|
-
|
|
31273
|
-
|
|
31274
|
-
|
|
31275
|
-
|
|
31276
|
-
|
|
31277
|
-
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31282
|
-
|
|
31283
|
-
|
|
31284
|
-
|
|
31285
|
-
// the connection is looked up in a circle area by `distance < r`
|
|
31286
|
-
if (distance < minDistance) {
|
|
31287
|
-
const isAlreadyValidated = prevClosestMagnet === magnet;
|
|
31288
|
-
if (isAlreadyValidated || paper.options.validateConnection.apply(paper, data.validateConnectionArgs(view, view.el === magnet ? null : magnet))) {
|
|
31289
|
-
minDistance = distance;
|
|
31290
|
-
data.closestView = view;
|
|
31291
|
-
data.closestMagnet = magnet;
|
|
31292
|
-
}
|
|
31293
|
-
}
|
|
31294
|
-
});
|
|
31295
|
-
}, this);
|
|
31444
|
+
const isAlreadyValidated = prevClosestMagnet === magnet;
|
|
31445
|
+
return isAlreadyValidated || paper.options.validateConnection.apply(paper, data.validateConnectionArgs(view, view.el === magnet ? null : magnet));
|
|
31446
|
+
};
|
|
31447
|
+
const closest = paper.findClosestMagnetToPoint({
|
|
31448
|
+
x,
|
|
31449
|
+
y
|
|
31450
|
+
}, {
|
|
31451
|
+
radius,
|
|
31452
|
+
findInAreaOptions,
|
|
31453
|
+
filter: isValidCandidate
|
|
31454
|
+
});
|
|
31455
|
+
data.closestView = closest ? closest.view : null;
|
|
31456
|
+
data.closestMagnet = closest ? closest.magnet : null;
|
|
31296
31457
|
var end;
|
|
31297
31458
|
var magnetProxy = null;
|
|
31298
31459
|
var closestView = data.closestView;
|
|
@@ -31586,6 +31747,72 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
31586
31747
|
}, {
|
|
31587
31748
|
Flags: Flags
|
|
31588
31749
|
});
|
|
31750
|
+
Object.defineProperty(LinkView.prototype, 'sourceView', {
|
|
31751
|
+
enumerable: true,
|
|
31752
|
+
get: function () {
|
|
31753
|
+
const source = this.model.attributes.source;
|
|
31754
|
+
if (source.id && this.paper) {
|
|
31755
|
+
return this.paper.findViewByModel(source.id);
|
|
31756
|
+
}
|
|
31757
|
+
return null;
|
|
31758
|
+
}
|
|
31759
|
+
});
|
|
31760
|
+
Object.defineProperty(LinkView.prototype, 'targetView', {
|
|
31761
|
+
enumerable: true,
|
|
31762
|
+
get: function () {
|
|
31763
|
+
const target = this.model.attributes.target;
|
|
31764
|
+
if (target.id && this.paper) {
|
|
31765
|
+
return this.paper.findViewByModel(target.id);
|
|
31766
|
+
}
|
|
31767
|
+
return null;
|
|
31768
|
+
}
|
|
31769
|
+
});
|
|
31770
|
+
Object.defineProperty(LinkView.prototype, 'sourceMagnet', {
|
|
31771
|
+
enumerable: true,
|
|
31772
|
+
get: function () {
|
|
31773
|
+
const sourceView = this.sourceView;
|
|
31774
|
+
if (!sourceView) return null;
|
|
31775
|
+
let sourceMagnet = null;
|
|
31776
|
+
// Check if the magnet is already found and cached.
|
|
31777
|
+
// We need to check if the cached magnet is still part of the source view.
|
|
31778
|
+
// The source view might have been disposed and recreated, or the magnet might have been changed.
|
|
31779
|
+
const cachedSourceMagnet = this._sourceMagnet;
|
|
31780
|
+
if (cachedSourceMagnet && sourceView.el.contains(cachedSourceMagnet)) {
|
|
31781
|
+
sourceMagnet = cachedSourceMagnet;
|
|
31782
|
+
} else {
|
|
31783
|
+
// If the cached magnet is not valid, we need to find the magnet.
|
|
31784
|
+
sourceMagnet = sourceView.getMagnetFromLinkEnd(this.model.attributes.source);
|
|
31785
|
+
}
|
|
31786
|
+
this._sourceMagnet = sourceMagnet;
|
|
31787
|
+
if (sourceMagnet === sourceView.el) {
|
|
31788
|
+
// If the source magnet is the element itself, we treat it as no magnet.
|
|
31789
|
+
return null;
|
|
31790
|
+
}
|
|
31791
|
+
return sourceMagnet;
|
|
31792
|
+
}
|
|
31793
|
+
});
|
|
31794
|
+
Object.defineProperty(LinkView.prototype, 'targetMagnet', {
|
|
31795
|
+
enumerable: true,
|
|
31796
|
+
get: function () {
|
|
31797
|
+
const targetView = this.targetView;
|
|
31798
|
+
if (!targetView) return null;
|
|
31799
|
+
let targetMagnet = null;
|
|
31800
|
+
// Check if the magnet is already found and cached (See `sourceMagnet` for explanation).
|
|
31801
|
+
const cachedTargetMagnet = this._targetMagnet;
|
|
31802
|
+
if (cachedTargetMagnet && targetView.el.contains(cachedTargetMagnet)) {
|
|
31803
|
+
targetMagnet = cachedTargetMagnet;
|
|
31804
|
+
} else {
|
|
31805
|
+
// If the cached magnet is not valid, we need to find the magnet.
|
|
31806
|
+
targetMagnet = targetView.getMagnetFromLinkEnd(this.model.attributes.target);
|
|
31807
|
+
}
|
|
31808
|
+
this._targetMagnet = targetMagnet;
|
|
31809
|
+
if (targetMagnet === targetView.el) {
|
|
31810
|
+
// If the target magnet is the element itself, we treat it as no magnet.
|
|
31811
|
+
return null;
|
|
31812
|
+
}
|
|
31813
|
+
return targetMagnet;
|
|
31814
|
+
}
|
|
31815
|
+
});
|
|
31589
31816
|
Object.defineProperty(LinkView.prototype, 'sourceBBox', {
|
|
31590
31817
|
enumerable: true,
|
|
31591
31818
|
get: function () {
|
|
@@ -31617,6 +31844,128 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
31617
31844
|
}
|
|
31618
31845
|
});
|
|
31619
31846
|
|
|
31847
|
+
/**
|
|
31848
|
+
* Deque implementation for managing a double-ended queue.
|
|
31849
|
+
* This implementation uses a doubly linked list for efficient operations.
|
|
31850
|
+
* It supports operations like push, pop, move to head, and delete.
|
|
31851
|
+
* The deque maintains a map for O(1) access to nodes by key.
|
|
31852
|
+
*/
|
|
31853
|
+
class Deque {
|
|
31854
|
+
constructor() {
|
|
31855
|
+
this.head = null;
|
|
31856
|
+
this.tail = null;
|
|
31857
|
+
this.map = new Map(); // key -> node
|
|
31858
|
+
}
|
|
31859
|
+
|
|
31860
|
+
// Return an array of keys in the deque
|
|
31861
|
+
keys() {
|
|
31862
|
+
let current = this.head;
|
|
31863
|
+
const keys = [];
|
|
31864
|
+
while (current) {
|
|
31865
|
+
keys.push(current.key);
|
|
31866
|
+
current = current.next;
|
|
31867
|
+
}
|
|
31868
|
+
return keys;
|
|
31869
|
+
}
|
|
31870
|
+
|
|
31871
|
+
// Return the first node and remove it from the deque
|
|
31872
|
+
popHead() {
|
|
31873
|
+
if (!this.head) return null;
|
|
31874
|
+
const node = this.head;
|
|
31875
|
+
this.map.delete(node.key);
|
|
31876
|
+
this.head = node.next;
|
|
31877
|
+
if (this.head) {
|
|
31878
|
+
this.head.prev = null;
|
|
31879
|
+
} else {
|
|
31880
|
+
this.tail = null;
|
|
31881
|
+
}
|
|
31882
|
+
return node;
|
|
31883
|
+
}
|
|
31884
|
+
|
|
31885
|
+
// Add a new node to the back of the deque
|
|
31886
|
+
pushTail(key, value) {
|
|
31887
|
+
if (this.map.has(key)) {
|
|
31888
|
+
throw new Error(`Key "${key}" already exists in the deque.`);
|
|
31889
|
+
}
|
|
31890
|
+
const node = {
|
|
31891
|
+
key,
|
|
31892
|
+
value,
|
|
31893
|
+
prev: null,
|
|
31894
|
+
next: null
|
|
31895
|
+
};
|
|
31896
|
+
this.map.set(key, node);
|
|
31897
|
+
if (!this.tail) {
|
|
31898
|
+
this.head = this.tail = node;
|
|
31899
|
+
} else {
|
|
31900
|
+
this.tail.next = node;
|
|
31901
|
+
node.prev = this.tail;
|
|
31902
|
+
this.tail = node;
|
|
31903
|
+
}
|
|
31904
|
+
}
|
|
31905
|
+
|
|
31906
|
+
// Move a node from the deque to the head
|
|
31907
|
+
moveToHead(key) {
|
|
31908
|
+
const node = this.map.get(key);
|
|
31909
|
+
if (!node) return;
|
|
31910
|
+
if (node === this.head) return; // already at head
|
|
31911
|
+
// Remove node from its current position
|
|
31912
|
+
if (node.prev) node.prev.next = node.next;
|
|
31913
|
+
if (node.next) node.next.prev = node.prev;
|
|
31914
|
+
if (node === this.tail) this.tail = node.prev; // if it's the tail
|
|
31915
|
+
if (node === this.head) this.head = node.next; // if it's the head
|
|
31916
|
+
// Move node to head
|
|
31917
|
+
node.prev = null;
|
|
31918
|
+
node.next = this.head;
|
|
31919
|
+
if (this.head) {
|
|
31920
|
+
this.head.prev = node; // link old head back to new head
|
|
31921
|
+
}
|
|
31922
|
+
this.head = node; // update head to be the moved node
|
|
31923
|
+
if (!this.tail) {
|
|
31924
|
+
this.tail = node; // if it was the only node, set tail as well
|
|
31925
|
+
}
|
|
31926
|
+
}
|
|
31927
|
+
|
|
31928
|
+
// Return the first node without removing it
|
|
31929
|
+
peekHead() {
|
|
31930
|
+
return this.head || null;
|
|
31931
|
+
}
|
|
31932
|
+
|
|
31933
|
+
// Move the head node to the back of the deque
|
|
31934
|
+
rotate() {
|
|
31935
|
+
if (!this.head || !this.head.next) return;
|
|
31936
|
+
this.tail.next = this.head; // link tail to head
|
|
31937
|
+
this.head.prev = this.tail; // link head back to tail
|
|
31938
|
+
this.tail = this.head; // update tail to be the old head
|
|
31939
|
+
this.head = this.head.next; // move head to the next node
|
|
31940
|
+
this.tail.next = null; // set new tail's next to null
|
|
31941
|
+
this.head.prev = null; // set new head's prev to null
|
|
31942
|
+
}
|
|
31943
|
+
|
|
31944
|
+
// Remove a node from the deque
|
|
31945
|
+
delete(key) {
|
|
31946
|
+
const node = this.map.get(key);
|
|
31947
|
+
if (!node) return;
|
|
31948
|
+
if (node.prev) node.prev.next = node.next;else this.head = node.next;
|
|
31949
|
+
if (node.next) node.next.prev = node.prev;else this.tail = node.prev;
|
|
31950
|
+
this.map.delete(key);
|
|
31951
|
+
}
|
|
31952
|
+
|
|
31953
|
+
// Does the deque contain a node with the given key?
|
|
31954
|
+
has(key) {
|
|
31955
|
+
return this.map.has(key);
|
|
31956
|
+
}
|
|
31957
|
+
|
|
31958
|
+
// Get the node with the given key
|
|
31959
|
+
get(key) {
|
|
31960
|
+
return this.map.get(key) || null;
|
|
31961
|
+
}
|
|
31962
|
+
|
|
31963
|
+
// Number of nodes in the deque
|
|
31964
|
+
get length() {
|
|
31965
|
+
return this.map.size;
|
|
31966
|
+
}
|
|
31967
|
+
}
|
|
31968
|
+
|
|
31620
31969
|
const GridLayer = PaperLayer.extend({
|
|
31621
31970
|
style: {
|
|
31622
31971
|
'pointer-events': 'none'
|
|
@@ -31858,6 +32207,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
31858
32207
|
}, {
|
|
31859
32208
|
name: LayersNames.TOOLS
|
|
31860
32209
|
}];
|
|
32210
|
+
const CELL_VIEW_PLACEHOLDER_MARKER = Symbol('joint.cellViewPlaceholderMarker');
|
|
31861
32211
|
const Paper = View.extend({
|
|
31862
32212
|
className: 'paper',
|
|
31863
32213
|
options: {
|
|
@@ -32008,6 +32358,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32008
32358
|
sorting: sortingTypes.APPROX,
|
|
32009
32359
|
frozen: false,
|
|
32010
32360
|
autoFreeze: false,
|
|
32361
|
+
viewManagement: false,
|
|
32011
32362
|
// no docs yet
|
|
32012
32363
|
onViewUpdate: function (view, flag, priority, opt, paper) {
|
|
32013
32364
|
// Do not update connected links when:
|
|
@@ -32015,7 +32366,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32015
32366
|
// 2. the view was just mounted (added back to the paper by viewport function)
|
|
32016
32367
|
// 3. the change was marked as `isolate`.
|
|
32017
32368
|
// 4. the view model was just removed from the graph
|
|
32018
|
-
if (flag & (
|
|
32369
|
+
if (flag & (paper.FLAG_INSERT | paper.FLAG_REMOVE) || opt.mounting || opt.isolate) return;
|
|
32019
32370
|
paper.requestConnectedLinksUpdate(view, priority, opt);
|
|
32020
32371
|
},
|
|
32021
32372
|
// no docs yet
|
|
@@ -32114,6 +32465,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32114
32465
|
DEFAULT_FIND_BUFFER: 200,
|
|
32115
32466
|
// Default layer to insert the cell views into.
|
|
32116
32467
|
DEFAULT_CELL_LAYER: LayersNames.CELLS,
|
|
32468
|
+
// Update flags
|
|
32469
|
+
FLAG_INSERT: 1 << 30,
|
|
32470
|
+
FLAG_REMOVE: 1 << 29,
|
|
32471
|
+
FLAG_INIT: 1 << 28,
|
|
32117
32472
|
init: function () {
|
|
32118
32473
|
const {
|
|
32119
32474
|
options
|
|
@@ -32125,6 +32480,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32125
32480
|
}
|
|
32126
32481
|
const model = this.model = options.model || new Graph();
|
|
32127
32482
|
|
|
32483
|
+
// This property tells us if we need to keep the compatibility
|
|
32484
|
+
// with the v4 API and behavior.
|
|
32485
|
+
this.legacyMode = !options.viewManagement;
|
|
32486
|
+
|
|
32128
32487
|
// Layers (SVGGroups)
|
|
32129
32488
|
this._layers = {
|
|
32130
32489
|
viewsMap: {},
|
|
@@ -32138,6 +32497,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32138
32497
|
|
|
32139
32498
|
// Hash of all cell views.
|
|
32140
32499
|
this._views = {};
|
|
32500
|
+
this._viewPlaceholders = {};
|
|
32501
|
+
this._idToCid = {};
|
|
32141
32502
|
|
|
32142
32503
|
// Mouse wheel events buffer
|
|
32143
32504
|
this._mw_evt_buffer = {
|
|
@@ -32147,24 +32508,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32147
32508
|
|
|
32148
32509
|
// Render existing cells in the graph
|
|
32149
32510
|
this.resetViews(model.attributes.cells.models);
|
|
32150
|
-
// Start the Rendering Loop
|
|
32151
|
-
if (!this.isFrozen() && this.isAsync()) this.updateViewsAsync();
|
|
32152
32511
|
},
|
|
32153
32512
|
_resetUpdates: function () {
|
|
32154
32513
|
if (this._updates && this._updates.id) cancelFrame(this._updates.id);
|
|
32155
32514
|
return this._updates = {
|
|
32156
32515
|
id: null,
|
|
32157
32516
|
priorities: [{}, {}, {}],
|
|
32158
|
-
|
|
32159
|
-
|
|
32160
|
-
unmounted: {},
|
|
32161
|
-
mounted: {},
|
|
32517
|
+
unmountedList: new Deque(),
|
|
32518
|
+
mountedList: new Deque(),
|
|
32162
32519
|
count: 0,
|
|
32163
32520
|
keyFrozen: false,
|
|
32164
32521
|
freezeKey: null,
|
|
32165
32522
|
sort: false,
|
|
32166
32523
|
disabled: false,
|
|
32167
|
-
idle: false
|
|
32524
|
+
idle: false,
|
|
32525
|
+
freshAfterReset: true
|
|
32168
32526
|
};
|
|
32169
32527
|
},
|
|
32170
32528
|
startListening: function () {
|
|
@@ -32187,14 +32545,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32187
32545
|
}
|
|
32188
32546
|
},
|
|
32189
32547
|
onCellRemoved: function (cell, _, opt) {
|
|
32190
|
-
const
|
|
32191
|
-
if (
|
|
32548
|
+
const viewLike = this._getCellViewLike(cell);
|
|
32549
|
+
if (!viewLike) return;
|
|
32550
|
+
if (viewLike[CELL_VIEW_PLACEHOLDER_MARKER]) {
|
|
32551
|
+
this._unregisterCellViewPlaceholder(viewLike);
|
|
32552
|
+
} else {
|
|
32553
|
+
this.requestViewUpdate(viewLike, this.FLAG_REMOVE, viewLike.UPDATE_PRIORITY, opt);
|
|
32554
|
+
}
|
|
32192
32555
|
},
|
|
32193
32556
|
onCellChange: function (cell, opt) {
|
|
32194
32557
|
if (cell === this.model.attributes.cells) return;
|
|
32195
32558
|
if (cell.hasChanged('layer') || cell.hasChanged('z') && this.options.sorting === sortingTypes.APPROX) {
|
|
32196
|
-
const
|
|
32197
|
-
if (
|
|
32559
|
+
const viewLike = this._getCellViewLike(cell);
|
|
32560
|
+
if (viewLike) {
|
|
32561
|
+
this.requestViewUpdate(viewLike, this.FLAG_INSERT, viewLike.UPDATE_PRIORITY, opt);
|
|
32562
|
+
}
|
|
32198
32563
|
}
|
|
32199
32564
|
},
|
|
32200
32565
|
onGraphReset: function (collection, opt) {
|
|
@@ -32206,7 +32571,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32206
32571
|
this.sortViews();
|
|
32207
32572
|
},
|
|
32208
32573
|
onGraphBatchStop: function (data) {
|
|
32209
|
-
if (this.isFrozen()) return;
|
|
32574
|
+
if (this.isFrozen() || this.isIdle()) return;
|
|
32210
32575
|
var name = data && data.batchName;
|
|
32211
32576
|
var graph = this.model;
|
|
32212
32577
|
if (!this.isAsync()) {
|
|
@@ -32266,6 +32631,16 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32266
32631
|
// Return the default highlighting options into the user specified options.
|
|
32267
32632
|
options.highlighting = defaultsDeep({}, highlighting, defaultHighlighting);
|
|
32268
32633
|
}
|
|
32634
|
+
// Copy and set defaults for the view management options.
|
|
32635
|
+
options.viewManagement = defaults({}, options.viewManagement, {
|
|
32636
|
+
// Whether to lazy initialize the cell views.
|
|
32637
|
+
lazyInitialize: !!options.viewManagement,
|
|
32638
|
+
// default `true` if options.viewManagement provided
|
|
32639
|
+
// Whether to add initialized cell views into the unmounted queue.
|
|
32640
|
+
initializeUnmounted: false,
|
|
32641
|
+
// Whether to dispose the cell views that are not visible.
|
|
32642
|
+
disposeHidden: false
|
|
32643
|
+
});
|
|
32269
32644
|
},
|
|
32270
32645
|
children: function () {
|
|
32271
32646
|
var ns = V.namespace;
|
|
@@ -32644,47 +33019,46 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32644
33019
|
var links = this.model.getConnectedLinks(model);
|
|
32645
33020
|
for (var j = 0, n = links.length; j < n; j++) {
|
|
32646
33021
|
var link = links[j];
|
|
32647
|
-
var linkView = this.
|
|
33022
|
+
var linkView = this._getCellViewLike(link);
|
|
32648
33023
|
if (!linkView) continue;
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
if (
|
|
33024
|
+
// We do not have to update placeholder views.
|
|
33025
|
+
// They will be updated on initial render.
|
|
33026
|
+
if (linkView[CELL_VIEW_PLACEHOLDER_MARKER]) continue;
|
|
32652
33027
|
var nextPriority = Math.max(priority + 1, linkView.UPDATE_PRIORITY);
|
|
32653
|
-
this.scheduleViewUpdate(linkView, linkView.getFlag(
|
|
33028
|
+
this.scheduleViewUpdate(linkView, linkView.getFlag(LinkView.Flags.UPDATE), nextPriority, opt);
|
|
32654
33029
|
}
|
|
32655
33030
|
}
|
|
32656
33031
|
},
|
|
32657
33032
|
forcePostponedViewUpdate: function (view, flag) {
|
|
32658
33033
|
if (!view || !(view instanceof CellView)) return false;
|
|
32659
|
-
|
|
33034
|
+
const model = view.model;
|
|
32660
33035
|
if (model.isElement()) return false;
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
32667
|
-
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
|
|
32671
|
-
|
|
32672
|
-
|
|
32673
|
-
|
|
32674
|
-
|
|
32675
|
-
|
|
32676
|
-
|
|
32677
|
-
|
|
32678
|
-
|
|
32679
|
-
|
|
32680
|
-
|
|
32681
|
-
return !this.dumpView(view, dumpOptions);
|
|
32682
|
-
}
|
|
33036
|
+
const dumpOptions = {
|
|
33037
|
+
silent: true
|
|
33038
|
+
};
|
|
33039
|
+
// LinkView is waiting for the target or the source cellView to be rendered
|
|
33040
|
+
// This can happen when the cells are not in the viewport.
|
|
33041
|
+
let sourceFlag = 0;
|
|
33042
|
+
const sourceCell = model.getSourceCell();
|
|
33043
|
+
if (sourceCell && !this.isCellVisible(sourceCell)) {
|
|
33044
|
+
const sourceView = this.findViewByModel(sourceCell);
|
|
33045
|
+
sourceFlag = this.dumpView(sourceView, dumpOptions);
|
|
33046
|
+
}
|
|
33047
|
+
let targetFlag = 0;
|
|
33048
|
+
const targetCell = model.getTargetCell();
|
|
33049
|
+
if (targetCell && !this.isCellVisible(targetCell)) {
|
|
33050
|
+
const targetView = this.findViewByModel(targetCell);
|
|
33051
|
+
targetFlag = this.dumpView(targetView, dumpOptions);
|
|
33052
|
+
}
|
|
33053
|
+
if (sourceFlag === 0 && targetFlag === 0) {
|
|
33054
|
+
// If leftover flag is 0, all view updates were done.
|
|
33055
|
+
return !this.dumpView(view, dumpOptions);
|
|
32683
33056
|
}
|
|
32684
33057
|
return false;
|
|
32685
33058
|
},
|
|
32686
33059
|
requestViewUpdate: function (view, flag, priority, opt) {
|
|
32687
33060
|
opt || (opt = {});
|
|
33061
|
+
// Note: `scheduleViewUpdate` wakes up the paper if it is idle.
|
|
32688
33062
|
this.scheduleViewUpdate(view, flag, priority, opt);
|
|
32689
33063
|
var isAsync = this.isAsync();
|
|
32690
33064
|
if (this.isFrozen() || isAsync && opt.async !== false) return;
|
|
@@ -32697,15 +33071,15 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32697
33071
|
_updates: updates,
|
|
32698
33072
|
options
|
|
32699
33073
|
} = this;
|
|
32700
|
-
if (updates.idle) {
|
|
32701
|
-
|
|
32702
|
-
|
|
32703
|
-
this.unfreeze();
|
|
32704
|
-
}
|
|
33074
|
+
if (updates.idle && options.autoFreeze) {
|
|
33075
|
+
this.legacyMode ? this.unfreeze() // Restart rendering loop without original options
|
|
33076
|
+
: this.wakeUp();
|
|
32705
33077
|
}
|
|
32706
33078
|
const {
|
|
32707
33079
|
FLAG_REMOVE,
|
|
32708
|
-
FLAG_INSERT
|
|
33080
|
+
FLAG_INSERT
|
|
33081
|
+
} = this;
|
|
33082
|
+
const {
|
|
32709
33083
|
UPDATE_PRIORITY,
|
|
32710
33084
|
cid
|
|
32711
33085
|
} = view;
|
|
@@ -32752,16 +33126,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32752
33126
|
dumpView: function (view, opt = {}) {
|
|
32753
33127
|
const flag = this.dumpViewUpdate(view);
|
|
32754
33128
|
if (!flag) return 0;
|
|
32755
|
-
|
|
32756
|
-
if (shouldNotify) this.notifyBeforeRender(opt);
|
|
33129
|
+
this.notifyBeforeRender(opt);
|
|
32757
33130
|
const leftover = this.updateView(view, flag, opt);
|
|
32758
|
-
|
|
32759
|
-
|
|
32760
|
-
|
|
32761
|
-
|
|
32762
|
-
|
|
32763
|
-
this.notifyAfterRender(stats, opt);
|
|
32764
|
-
}
|
|
33131
|
+
const stats = {
|
|
33132
|
+
updated: 1,
|
|
33133
|
+
priority: view.UPDATE_PRIORITY
|
|
33134
|
+
};
|
|
33135
|
+
this.notifyAfterRender(stats, opt);
|
|
32765
33136
|
return leftover;
|
|
32766
33137
|
},
|
|
32767
33138
|
updateView: function (view, flag, opt) {
|
|
@@ -32769,10 +33140,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32769
33140
|
const {
|
|
32770
33141
|
FLAG_REMOVE,
|
|
32771
33142
|
FLAG_INSERT,
|
|
32772
|
-
FLAG_INIT
|
|
33143
|
+
FLAG_INIT
|
|
33144
|
+
} = this;
|
|
33145
|
+
const {
|
|
32773
33146
|
model
|
|
32774
33147
|
} = view;
|
|
32775
|
-
if (view
|
|
33148
|
+
if (view[CELL_VIEW_MARKER]) {
|
|
32776
33149
|
if (flag & FLAG_REMOVE) {
|
|
32777
33150
|
this.removeView(model);
|
|
32778
33151
|
return 0;
|
|
@@ -32798,58 +33171,70 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32798
33171
|
registerUnmountedView: function (view) {
|
|
32799
33172
|
var cid = view.cid;
|
|
32800
33173
|
var updates = this._updates;
|
|
32801
|
-
if (
|
|
32802
|
-
|
|
32803
|
-
updates.
|
|
32804
|
-
|
|
33174
|
+
if (updates.unmountedList.has(cid)) return 0;
|
|
33175
|
+
const flag = this.FLAG_INSERT;
|
|
33176
|
+
updates.unmountedList.pushTail(cid, flag);
|
|
33177
|
+
updates.mountedList.delete(cid);
|
|
32805
33178
|
return flag;
|
|
32806
33179
|
},
|
|
32807
33180
|
registerMountedView: function (view) {
|
|
32808
33181
|
var cid = view.cid;
|
|
32809
33182
|
var updates = this._updates;
|
|
32810
|
-
if (
|
|
32811
|
-
updates.
|
|
32812
|
-
|
|
32813
|
-
|
|
32814
|
-
|
|
33183
|
+
if (updates.mountedList.has(cid)) return 0;
|
|
33184
|
+
const unmountedItem = updates.unmountedList.get(cid);
|
|
33185
|
+
const flag = unmountedItem ? unmountedItem.value : 0;
|
|
33186
|
+
updates.unmountedList.delete(cid);
|
|
33187
|
+
updates.mountedList.pushTail(cid);
|
|
32815
33188
|
return flag;
|
|
32816
33189
|
},
|
|
32817
|
-
|
|
32818
|
-
|
|
32819
|
-
|
|
32820
|
-
|
|
32821
|
-
|
|
33190
|
+
isCellVisible: function (cellOrId) {
|
|
33191
|
+
const cid = cellOrId && this._idToCid[cellOrId.id || cellOrId];
|
|
33192
|
+
if (!cid) return false; // The view is not registered.
|
|
33193
|
+
return this.isViewMounted(cid);
|
|
33194
|
+
},
|
|
33195
|
+
isViewMounted: function (viewOrCid) {
|
|
33196
|
+
if (!viewOrCid) return false;
|
|
33197
|
+
let cid;
|
|
33198
|
+
if (viewOrCid[CELL_VIEW_MARKER] || viewOrCid[CELL_VIEW_PLACEHOLDER_MARKER]) {
|
|
33199
|
+
cid = viewOrCid.cid;
|
|
33200
|
+
} else {
|
|
33201
|
+
cid = viewOrCid;
|
|
33202
|
+
}
|
|
33203
|
+
return this._updates.mountedList.has(cid);
|
|
32822
33204
|
},
|
|
33205
|
+
/**
|
|
33206
|
+
* @deprecated use `updateCellsVisibility` instead.
|
|
33207
|
+
* `paper.updateCellsVisibility({ cellVisibility: () => true });`
|
|
33208
|
+
*/
|
|
32823
33209
|
dumpViews: function (opt) {
|
|
32824
|
-
|
|
33210
|
+
// Update cell visibility without `cellVisibility` callback i.e. make the cells visible
|
|
33211
|
+
const passingOpt = defaults({}, opt, {
|
|
33212
|
+
cellVisibility: null,
|
|
32825
33213
|
viewport: null
|
|
32826
33214
|
});
|
|
32827
|
-
this.
|
|
32828
|
-
this.updateViews(passingOpt);
|
|
33215
|
+
this.updateCellsVisibility(passingOpt);
|
|
32829
33216
|
},
|
|
32830
|
-
|
|
32831
|
-
|
|
33217
|
+
/**
|
|
33218
|
+
* Process all scheduled updates synchronously.
|
|
33219
|
+
*/
|
|
33220
|
+
updateViews: function (opt = {}) {
|
|
32832
33221
|
this.notifyBeforeRender(opt);
|
|
32833
|
-
|
|
32834
|
-
|
|
32835
|
-
|
|
32836
|
-
|
|
32837
|
-
do {
|
|
32838
|
-
batchCount++;
|
|
32839
|
-
batchStats = this.updateViewsBatch(opt);
|
|
32840
|
-
updateCount += batchStats.updated;
|
|
32841
|
-
priority = Math.min(batchStats.priority, priority);
|
|
32842
|
-
} while (!batchStats.empty);
|
|
33222
|
+
const batchStats = this.updateViewsBatch({
|
|
33223
|
+
...opt,
|
|
33224
|
+
batchSize: Infinity
|
|
33225
|
+
});
|
|
32843
33226
|
const stats = {
|
|
32844
|
-
updated:
|
|
32845
|
-
|
|
32846
|
-
|
|
33227
|
+
updated: batchStats.updated,
|
|
33228
|
+
priority: batchStats.priority,
|
|
33229
|
+
// For backward compatibility. Will be removed in the future.
|
|
33230
|
+
batches: Number.isFinite(opt.batchSize) ? Math.ceil(batchStats.updated / opt.batchSize) : 1
|
|
32847
33231
|
};
|
|
32848
33232
|
this.notifyAfterRender(stats, opt);
|
|
32849
33233
|
return stats;
|
|
32850
33234
|
},
|
|
32851
33235
|
hasScheduledUpdates: function () {
|
|
32852
|
-
const
|
|
33236
|
+
const updates = this._updates;
|
|
33237
|
+
const priorities = updates.priorities;
|
|
32853
33238
|
const priorityIndexes = Object.keys(priorities); // convert priorities to a dense array
|
|
32854
33239
|
let i = priorityIndexes.length;
|
|
32855
33240
|
while (i > 0 && i--) {
|
|
@@ -32862,15 +33247,43 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32862
33247
|
opt || (opt = {});
|
|
32863
33248
|
data || (data = {
|
|
32864
33249
|
processed: 0,
|
|
32865
|
-
priority: MIN_PRIORITY
|
|
33250
|
+
priority: MIN_PRIORITY,
|
|
33251
|
+
checkedUnmounted: 0,
|
|
33252
|
+
checkedMounted: 0
|
|
32866
33253
|
});
|
|
32867
33254
|
const {
|
|
32868
33255
|
_updates: updates,
|
|
32869
33256
|
options
|
|
32870
33257
|
} = this;
|
|
32871
|
-
const
|
|
32872
|
-
|
|
33258
|
+
const {
|
|
33259
|
+
id,
|
|
33260
|
+
mountedList,
|
|
33261
|
+
unmountedList,
|
|
33262
|
+
freshAfterReset
|
|
33263
|
+
} = updates;
|
|
33264
|
+
|
|
33265
|
+
// Should we run the next batch update this frame?
|
|
33266
|
+
let runBatchUpdate = true;
|
|
33267
|
+
if (!id) {
|
|
33268
|
+
// If there's no scheduled frame, no batch update is needed.
|
|
33269
|
+
runBatchUpdate = false;
|
|
33270
|
+
} else {
|
|
33271
|
+
// Cancel any scheduled frame.
|
|
32873
33272
|
cancelFrame(id);
|
|
33273
|
+
if (freshAfterReset) {
|
|
33274
|
+
// First update after a reset.
|
|
33275
|
+
updates.freshAfterReset = false;
|
|
33276
|
+
// When `initializeUnmounted` is enabled, there are no scheduled updates.
|
|
33277
|
+
// We check whether the `mountedList` and `unmountedList` are empty.
|
|
33278
|
+
if (!this.legacyMode && mountedList.length === 0 && unmountedList.length === 0) {
|
|
33279
|
+
// No updates to process; We trigger before/after render events via `updateViews`.
|
|
33280
|
+
// Note: If `autoFreeze` is enabled, 'idle' event triggers next frame.
|
|
33281
|
+
this.updateViews();
|
|
33282
|
+
runBatchUpdate = false;
|
|
33283
|
+
}
|
|
33284
|
+
}
|
|
33285
|
+
}
|
|
33286
|
+
if (runBatchUpdate) {
|
|
32874
33287
|
if (data.processed === 0 && this.hasScheduledUpdates()) {
|
|
32875
33288
|
this.notifyBeforeRender(opt);
|
|
32876
33289
|
}
|
|
@@ -32879,7 +33292,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32879
33292
|
mountBatchSize: MOUNT_BATCH_SIZE - stats.mounted,
|
|
32880
33293
|
unmountBatchSize: MOUNT_BATCH_SIZE - stats.unmounted
|
|
32881
33294
|
});
|
|
32882
|
-
const checkStats = this.
|
|
33295
|
+
const checkStats = this.scheduleCellsVisibilityUpdate(passingOpt);
|
|
32883
33296
|
const unmountCount = checkStats.unmounted;
|
|
32884
33297
|
const mountCount = checkStats.mounted;
|
|
32885
33298
|
let processed = data.processed;
|
|
@@ -32900,11 +33313,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32900
33313
|
} else {
|
|
32901
33314
|
data.processed = processed;
|
|
32902
33315
|
}
|
|
33316
|
+
data.checkedUnmounted = 0;
|
|
33317
|
+
data.checkedMounted = 0;
|
|
32903
33318
|
} else {
|
|
32904
|
-
|
|
32905
|
-
|
|
33319
|
+
data.checkedUnmounted += Math.max(passingOpt.mountBatchSize, 0);
|
|
33320
|
+
data.checkedMounted += Math.max(passingOpt.unmountBatchSize, 0);
|
|
33321
|
+
// The `scheduleCellsVisibilityUpdate` could have scheduled some insertions
|
|
33322
|
+
// (note that removals are currently done synchronously).
|
|
33323
|
+
if (options.autoFreeze && !this.hasScheduledUpdates()) {
|
|
33324
|
+
// If there are no updates scheduled and we checked all unmounted views,
|
|
33325
|
+
if (data.checkedUnmounted >= unmountedList.length && data.checkedMounted >= mountedList.length) {
|
|
33326
|
+
// We freeze the paper and notify the idle state.
|
|
32906
33327
|
this.freeze();
|
|
32907
|
-
updates.idle =
|
|
33328
|
+
updates.idle = {
|
|
33329
|
+
wakeUpOptions: opt
|
|
33330
|
+
};
|
|
32908
33331
|
this.trigger('render:idle', opt);
|
|
32909
33332
|
}
|
|
32910
33333
|
}
|
|
@@ -32923,6 +33346,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32923
33346
|
updates.id = nextFrame(this.updateViewsAsync, this, opt, data);
|
|
32924
33347
|
},
|
|
32925
33348
|
notifyBeforeRender: function (opt = {}) {
|
|
33349
|
+
if (opt.silent) return;
|
|
32926
33350
|
let beforeFn = opt.beforeRender;
|
|
32927
33351
|
if (typeof beforeFn !== 'function') {
|
|
32928
33352
|
beforeFn = this.options.beforeRender;
|
|
@@ -32931,6 +33355,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32931
33355
|
beforeFn.call(this, opt, this);
|
|
32932
33356
|
},
|
|
32933
33357
|
notifyAfterRender: function (stats, opt = {}) {
|
|
33358
|
+
if (opt.silent) return;
|
|
32934
33359
|
let afterFn = opt.afterRender;
|
|
32935
33360
|
if (typeof afterFn !== 'function') {
|
|
32936
33361
|
afterFn = this.options.afterRender;
|
|
@@ -32940,6 +33365,58 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32940
33365
|
}
|
|
32941
33366
|
this.trigger('render:done', stats, opt);
|
|
32942
33367
|
},
|
|
33368
|
+
prioritizeCellViewMount: function (cellOrId) {
|
|
33369
|
+
if (!cellOrId) return false;
|
|
33370
|
+
const cid = this._idToCid[cellOrId.id || cellOrId];
|
|
33371
|
+
if (!cid) return false;
|
|
33372
|
+
const {
|
|
33373
|
+
unmountedList
|
|
33374
|
+
} = this._updates;
|
|
33375
|
+
if (!unmountedList.has(cid)) return false;
|
|
33376
|
+
// Move the view to the head of the mounted list
|
|
33377
|
+
unmountedList.moveToHead(cid);
|
|
33378
|
+
return true;
|
|
33379
|
+
},
|
|
33380
|
+
prioritizeCellViewUnmount: function (cellOrId) {
|
|
33381
|
+
if (!cellOrId) return false;
|
|
33382
|
+
const cid = this._idToCid[cellOrId.id || cellOrId];
|
|
33383
|
+
if (!cid) return false;
|
|
33384
|
+
const {
|
|
33385
|
+
mountedList
|
|
33386
|
+
} = this._updates;
|
|
33387
|
+
if (!mountedList.has(cid)) return false;
|
|
33388
|
+
// Move the view to the head of the unmounted list
|
|
33389
|
+
mountedList.moveToHead(cid);
|
|
33390
|
+
return true;
|
|
33391
|
+
},
|
|
33392
|
+
_evalCellVisibility: function (viewLike, isMounted, visibilityCallback) {
|
|
33393
|
+
if (!visibilityCallback || !viewLike.DETACHABLE) return true;
|
|
33394
|
+
if (this.legacyMode) {
|
|
33395
|
+
return visibilityCallback.call(this, viewLike, isMounted, this);
|
|
33396
|
+
}
|
|
33397
|
+
// The visibility check runs for CellView only.
|
|
33398
|
+
if (!viewLike[CELL_VIEW_MARKER] && !viewLike[CELL_VIEW_PLACEHOLDER_MARKER]) return true;
|
|
33399
|
+
// The cellView model must be a member of this graph.
|
|
33400
|
+
if (viewLike.model.graph !== this.model) {
|
|
33401
|
+
// It could have been removed from the graph.
|
|
33402
|
+
// If the view was mounted, we keep it mounted.
|
|
33403
|
+
return isMounted;
|
|
33404
|
+
}
|
|
33405
|
+
return visibilityCallback.call(this, viewLike.model, isMounted, this);
|
|
33406
|
+
},
|
|
33407
|
+
_getCellVisibilityCallback: function (opt) {
|
|
33408
|
+
const {
|
|
33409
|
+
options
|
|
33410
|
+
} = this;
|
|
33411
|
+
if (this.legacyMode) {
|
|
33412
|
+
const viewportFn = 'viewport' in opt ? opt.viewport : options.viewport;
|
|
33413
|
+
if (typeof viewportFn === 'function') return viewportFn;
|
|
33414
|
+
} else {
|
|
33415
|
+
const isVisibleFn = 'cellVisibility' in opt ? opt.cellVisibility : options.cellVisibility;
|
|
33416
|
+
if (typeof isVisibleFn === 'function') return isVisibleFn;
|
|
33417
|
+
}
|
|
33418
|
+
return null;
|
|
33419
|
+
},
|
|
32943
33420
|
updateViewsBatch: function (opt) {
|
|
32944
33421
|
opt || (opt = {});
|
|
32945
33422
|
var batchSize = opt.batchSize || UPDATE_BATCH_SIZE;
|
|
@@ -32952,8 +33429,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32952
33429
|
var empty = true;
|
|
32953
33430
|
var options = this.options;
|
|
32954
33431
|
var priorities = updates.priorities;
|
|
32955
|
-
|
|
32956
|
-
if (typeof viewportFn !== 'function') viewportFn = null;
|
|
33432
|
+
const visibilityCb = this._getCellVisibilityCallback(opt);
|
|
32957
33433
|
var postponeViewFn = options.onViewPostponed;
|
|
32958
33434
|
if (typeof postponeViewFn !== 'function') postponeViewFn = null;
|
|
32959
33435
|
var priorityIndexes = Object.keys(priorities); // convert priorities to a dense array
|
|
@@ -32967,31 +33443,53 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
32967
33443
|
}
|
|
32968
33444
|
var view = views[cid];
|
|
32969
33445
|
if (!view) {
|
|
32970
|
-
|
|
32971
|
-
|
|
32972
|
-
|
|
33446
|
+
view = this._viewPlaceholders[cid];
|
|
33447
|
+
if (!view) {
|
|
33448
|
+
/**
|
|
33449
|
+
* This can occur when:
|
|
33450
|
+
* - the model is removed and a new model with the same id is added
|
|
33451
|
+
* - the view `initialize` method was overridden and the view was not registered
|
|
33452
|
+
* - an mvc.View scheduled an update, was removed and paper was not notified
|
|
33453
|
+
*/
|
|
33454
|
+
delete priorityUpdates[cid];
|
|
33455
|
+
continue;
|
|
33456
|
+
}
|
|
32973
33457
|
}
|
|
32974
33458
|
var currentFlag = priorityUpdates[cid];
|
|
32975
|
-
if ((currentFlag &
|
|
33459
|
+
if ((currentFlag & this.FLAG_REMOVE) === 0) {
|
|
32976
33460
|
// We should never check a view for viewport if we are about to remove the view
|
|
32977
|
-
|
|
32978
|
-
if (
|
|
33461
|
+
const isMounted = !updates.unmountedList.has(cid);
|
|
33462
|
+
if (!this._evalCellVisibility(view, isMounted, visibilityCb)) {
|
|
32979
33463
|
// Unmount View
|
|
32980
|
-
if (
|
|
33464
|
+
if (isMounted) {
|
|
33465
|
+
// The view is currently mounted. Hide the view (detach or remove it).
|
|
32981
33466
|
this.registerUnmountedView(view);
|
|
32982
|
-
this.
|
|
33467
|
+
this._hideView(view);
|
|
33468
|
+
} else {
|
|
33469
|
+
// The view is not mounted. We can just update the unmounted list.
|
|
33470
|
+
// We ADD the current flag to the flag that was already scheduled.
|
|
33471
|
+
this._mergeUnmountedViewScheduledUpdates(cid, currentFlag);
|
|
32983
33472
|
}
|
|
32984
|
-
|
|
33473
|
+
// Delete the current update as it has been processed.
|
|
32985
33474
|
delete priorityUpdates[cid];
|
|
32986
33475
|
unmountCount++;
|
|
32987
33476
|
continue;
|
|
32988
33477
|
}
|
|
32989
33478
|
// Mount View
|
|
32990
|
-
if (
|
|
32991
|
-
|
|
33479
|
+
if (view[CELL_VIEW_PLACEHOLDER_MARKER]) {
|
|
33480
|
+
view = this._resolveCellViewPlaceholder(view);
|
|
33481
|
+
// Newly initialized view needs to be initialized
|
|
33482
|
+
currentFlag |= this.getCellViewInitFlag(view);
|
|
33483
|
+
}
|
|
33484
|
+
if (!isMounted) {
|
|
33485
|
+
currentFlag |= this.FLAG_INSERT;
|
|
32992
33486
|
mountCount++;
|
|
32993
33487
|
}
|
|
32994
33488
|
currentFlag |= this.registerMountedView(view);
|
|
33489
|
+
} else if (view[CELL_VIEW_PLACEHOLDER_MARKER]) {
|
|
33490
|
+
// We are trying to remove a placeholder view.
|
|
33491
|
+
// This should not occur as the placeholder should have been unregistered
|
|
33492
|
+
continue;
|
|
32995
33493
|
}
|
|
32996
33494
|
var leftoverFlag = this.updateView(view, currentFlag, opt);
|
|
32997
33495
|
if (leftoverFlag > 0) {
|
|
@@ -33017,102 +33515,127 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33017
33515
|
empty: empty
|
|
33018
33516
|
};
|
|
33019
33517
|
},
|
|
33518
|
+
getCellViewInitFlag: function (cellView) {
|
|
33519
|
+
return this.FLAG_INIT | cellView.getFlag(result(cellView, 'initFlag'));
|
|
33520
|
+
},
|
|
33521
|
+
/**
|
|
33522
|
+
* @ignore This method returns an array of cellViewLike objects and therefore
|
|
33523
|
+
* is meant for internal/test use only.
|
|
33524
|
+
* The view placeholders are not exposed via public API.
|
|
33525
|
+
*/
|
|
33020
33526
|
getUnmountedViews: function () {
|
|
33021
33527
|
const updates = this._updates;
|
|
33022
|
-
const
|
|
33023
|
-
const
|
|
33024
|
-
|
|
33025
|
-
for (
|
|
33026
|
-
|
|
33528
|
+
const unmountedViews = new Array(updates.unmountedList.length);
|
|
33529
|
+
const unmountedCids = updates.unmountedList.keys();
|
|
33530
|
+
let i = 0;
|
|
33531
|
+
for (const cid of unmountedCids) {
|
|
33532
|
+
// If the view is a placeholder, it won't be in the global views map
|
|
33533
|
+
// If the view is not a cell view, it won't be in the viewPlaceholders map
|
|
33534
|
+
unmountedViews[i++] = views[cid] || this._viewPlaceholders[cid];
|
|
33027
33535
|
}
|
|
33028
33536
|
return unmountedViews;
|
|
33029
33537
|
},
|
|
33538
|
+
/**
|
|
33539
|
+
* @ignore This method returns an array of cellViewLike objects and therefore
|
|
33540
|
+
* is meant for internal/test use only.
|
|
33541
|
+
* The view placeholders are not exposed via public API.
|
|
33542
|
+
*/
|
|
33030
33543
|
getMountedViews: function () {
|
|
33031
33544
|
const updates = this._updates;
|
|
33032
|
-
const
|
|
33033
|
-
const
|
|
33034
|
-
|
|
33035
|
-
for (
|
|
33036
|
-
mountedViews[i] = views[
|
|
33545
|
+
const mountedViews = new Array(updates.mountedList.length);
|
|
33546
|
+
const mountedCids = updates.mountedList.keys();
|
|
33547
|
+
let i = 0;
|
|
33548
|
+
for (const cid of mountedCids) {
|
|
33549
|
+
mountedViews[i++] = views[cid] || this._viewPlaceholders[cid];
|
|
33037
33550
|
}
|
|
33038
33551
|
return mountedViews;
|
|
33039
33552
|
},
|
|
33040
|
-
checkUnmountedViews: function (
|
|
33553
|
+
checkUnmountedViews: function (visibilityCb, opt) {
|
|
33041
33554
|
opt || (opt = {});
|
|
33042
33555
|
var mountCount = 0;
|
|
33043
|
-
if (typeof
|
|
33556
|
+
if (typeof visibilityCb !== 'function') visibilityCb = null;
|
|
33044
33557
|
var batchSize = 'mountBatchSize' in opt ? opt.mountBatchSize : Infinity;
|
|
33045
33558
|
var updates = this._updates;
|
|
33046
|
-
var
|
|
33047
|
-
var
|
|
33048
|
-
|
|
33049
|
-
|
|
33050
|
-
|
|
33051
|
-
|
|
33052
|
-
if (!view)
|
|
33053
|
-
|
|
33559
|
+
var unmountedList = updates.unmountedList;
|
|
33560
|
+
for (var i = 0, n = Math.min(unmountedList.length, batchSize); i < n; i++) {
|
|
33561
|
+
const {
|
|
33562
|
+
key: cid
|
|
33563
|
+
} = unmountedList.peekHead();
|
|
33564
|
+
let view = views[cid] || this._viewPlaceholders[cid];
|
|
33565
|
+
if (!view) {
|
|
33566
|
+
// This should not occur
|
|
33567
|
+
continue;
|
|
33568
|
+
}
|
|
33569
|
+
if (!this._evalCellVisibility(view, false, visibilityCb)) {
|
|
33054
33570
|
// Push at the end of all unmounted ids, so this can be check later again
|
|
33055
|
-
|
|
33571
|
+
unmountedList.rotate();
|
|
33056
33572
|
continue;
|
|
33057
33573
|
}
|
|
33574
|
+
// Remove the view from the unmounted list
|
|
33575
|
+
const {
|
|
33576
|
+
value: prevFlag
|
|
33577
|
+
} = unmountedList.popHead();
|
|
33058
33578
|
mountCount++;
|
|
33059
|
-
|
|
33579
|
+
const flag = this.registerMountedView(view) | prevFlag;
|
|
33060
33580
|
if (flag) this.scheduleViewUpdate(view, flag, view.UPDATE_PRIORITY, {
|
|
33061
33581
|
mounting: true
|
|
33062
33582
|
});
|
|
33063
33583
|
}
|
|
33064
|
-
// Get rid of views, that have been mounted
|
|
33065
|
-
unmountedCids.splice(0, i);
|
|
33066
33584
|
return mountCount;
|
|
33067
33585
|
},
|
|
33068
|
-
checkMountedViews: function (
|
|
33586
|
+
checkMountedViews: function (visibilityCb, opt) {
|
|
33069
33587
|
opt || (opt = {});
|
|
33070
33588
|
var unmountCount = 0;
|
|
33071
|
-
if (typeof
|
|
33589
|
+
if (typeof visibilityCb !== 'function') return unmountCount;
|
|
33072
33590
|
var batchSize = 'unmountBatchSize' in opt ? opt.unmountBatchSize : Infinity;
|
|
33073
33591
|
var updates = this._updates;
|
|
33074
|
-
|
|
33075
|
-
var
|
|
33076
|
-
|
|
33077
|
-
|
|
33078
|
-
|
|
33079
|
-
|
|
33080
|
-
if (!view)
|
|
33081
|
-
|
|
33592
|
+
const mountedList = updates.mountedList;
|
|
33593
|
+
for (var i = 0, n = Math.min(mountedList.length, batchSize); i < n; i++) {
|
|
33594
|
+
const {
|
|
33595
|
+
key: cid
|
|
33596
|
+
} = mountedList.peekHead();
|
|
33597
|
+
const view = views[cid];
|
|
33598
|
+
if (!view) {
|
|
33599
|
+
// A view (not a cell view) has been removed from the paper.
|
|
33600
|
+
// Remove it from the mounted list and continue.
|
|
33601
|
+
mountedList.popHead();
|
|
33602
|
+
continue;
|
|
33603
|
+
}
|
|
33604
|
+
if (this._evalCellVisibility(view, true, visibilityCb)) {
|
|
33082
33605
|
// Push at the end of all mounted ids, so this can be check later again
|
|
33083
|
-
|
|
33606
|
+
mountedList.rotate();
|
|
33084
33607
|
continue;
|
|
33085
33608
|
}
|
|
33609
|
+
// Remove the view from the mounted list
|
|
33610
|
+
mountedList.popHead();
|
|
33086
33611
|
unmountCount++;
|
|
33087
33612
|
var flag = this.registerUnmountedView(view);
|
|
33088
|
-
if (flag)
|
|
33613
|
+
if (flag) {
|
|
33614
|
+
this._hideView(view);
|
|
33615
|
+
}
|
|
33089
33616
|
}
|
|
33090
|
-
// Get rid of views, that have been unmounted
|
|
33091
|
-
mountedCids.splice(0, i);
|
|
33092
33617
|
return unmountCount;
|
|
33093
33618
|
},
|
|
33094
33619
|
checkViewVisibility: function (cellView, opt = {}) {
|
|
33095
|
-
|
|
33096
|
-
if (typeof viewportFn !== 'function') viewportFn = null;
|
|
33620
|
+
const visibilityCb = this._getCellVisibilityCallback(opt);
|
|
33097
33621
|
const updates = this._updates;
|
|
33098
33622
|
const {
|
|
33099
|
-
|
|
33100
|
-
|
|
33623
|
+
mountedList,
|
|
33624
|
+
unmountedList
|
|
33101
33625
|
} = updates;
|
|
33102
|
-
const visible =
|
|
33626
|
+
const visible = this._evalCellVisibility(cellView, false, visibilityCb);
|
|
33103
33627
|
let isUnmounted = false;
|
|
33104
33628
|
let isMounted = false;
|
|
33105
|
-
if (cellView.cid
|
|
33629
|
+
if (mountedList.has(cellView.cid) && !visible) {
|
|
33106
33630
|
const flag = this.registerUnmountedView(cellView);
|
|
33107
|
-
if (flag) this.
|
|
33108
|
-
|
|
33109
|
-
updates.mountedCids.splice(i, 1);
|
|
33631
|
+
if (flag) this._hideView(cellView);
|
|
33632
|
+
mountedList.delete(cellView.cid);
|
|
33110
33633
|
isUnmounted = true;
|
|
33111
33634
|
}
|
|
33112
|
-
if (!isUnmounted && cellView.cid
|
|
33113
|
-
const
|
|
33114
|
-
|
|
33115
|
-
|
|
33635
|
+
if (!isUnmounted && unmountedList.has(cellView.cid) && visible) {
|
|
33636
|
+
const unmountedItem = unmountedList.get(cellView.cid);
|
|
33637
|
+
unmountedList.delete(cellView.cid);
|
|
33638
|
+
const flag = unmountedItem.value | this.registerMountedView(cellView);
|
|
33116
33639
|
if (flag) this.scheduleViewUpdate(cellView, flag, cellView.UPDATE_PRIORITY, {
|
|
33117
33640
|
mounting: true
|
|
33118
33641
|
});
|
|
@@ -33123,24 +33646,64 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33123
33646
|
unmounted: isUnmounted ? 1 : 0
|
|
33124
33647
|
};
|
|
33125
33648
|
},
|
|
33126
|
-
|
|
33127
|
-
|
|
33649
|
+
/**
|
|
33650
|
+
* @public
|
|
33651
|
+
* Update the visibility of a single cell.
|
|
33652
|
+
*/
|
|
33653
|
+
updateCellVisibility: function (cell, opt = {}) {
|
|
33654
|
+
const cellViewLike = this._getCellViewLike(cell);
|
|
33655
|
+
if (!cellViewLike) return;
|
|
33656
|
+
const stats = this.checkViewVisibility(cellViewLike, opt);
|
|
33657
|
+
// Note: `unmounted` views are removed immediately
|
|
33658
|
+
if (stats.mounted > 0) {
|
|
33659
|
+
// Mounting is scheduled. Run the update.
|
|
33660
|
+
// Note: the view might be a placeholder.
|
|
33661
|
+
this.requireView(cell, opt);
|
|
33662
|
+
}
|
|
33663
|
+
},
|
|
33664
|
+
/**
|
|
33665
|
+
* @public
|
|
33666
|
+
* Update the visibility of all cells.
|
|
33667
|
+
*/
|
|
33668
|
+
updateCellsVisibility: function (opt = {}) {
|
|
33669
|
+
// Check the visibility of all cells and schedule their updates.
|
|
33670
|
+
this.scheduleCellsVisibilityUpdate(opt);
|
|
33671
|
+
// Perform the scheduled updates while avoiding re-evaluating the visibility.
|
|
33672
|
+
const keepCurrentVisibility = (_, isVisible) => isVisible;
|
|
33673
|
+
this.updateViews({
|
|
33674
|
+
...opt,
|
|
33675
|
+
cellVisibility: keepCurrentVisibility
|
|
33676
|
+
});
|
|
33677
|
+
},
|
|
33678
|
+
/**
|
|
33679
|
+
* @protected
|
|
33680
|
+
* Run visibility checks for all cells and schedule their updates.
|
|
33681
|
+
*/
|
|
33682
|
+
scheduleCellsVisibilityUpdate(opt) {
|
|
33683
|
+
const passingOpt = defaults({}, opt, {
|
|
33128
33684
|
mountBatchSize: Infinity,
|
|
33129
33685
|
unmountBatchSize: Infinity
|
|
33130
33686
|
});
|
|
33131
|
-
|
|
33132
|
-
|
|
33687
|
+
const visibilityCb = this._getCellVisibilityCallback(passingOpt);
|
|
33688
|
+
const unmountedCount = this.checkMountedViews(visibilityCb, passingOpt);
|
|
33133
33689
|
if (unmountedCount > 0) {
|
|
33134
33690
|
// Do not check views, that have been just unmounted and pushed at the end of the cids array
|
|
33135
|
-
var
|
|
33136
|
-
passingOpt.mountBatchSize = Math.min(
|
|
33691
|
+
var unmountedList = this._updates.unmountedList;
|
|
33692
|
+
passingOpt.mountBatchSize = Math.min(unmountedList.length - unmountedCount, passingOpt.mountBatchSize);
|
|
33137
33693
|
}
|
|
33138
|
-
|
|
33694
|
+
const mountedCount = this.checkUnmountedViews(visibilityCb, passingOpt);
|
|
33139
33695
|
return {
|
|
33140
33696
|
mounted: mountedCount,
|
|
33141
33697
|
unmounted: unmountedCount
|
|
33142
33698
|
};
|
|
33143
33699
|
},
|
|
33700
|
+
/**
|
|
33701
|
+
* @deprecated use `updateCellsVisibility` instead
|
|
33702
|
+
* This method will be renamed and made private in the future.
|
|
33703
|
+
*/
|
|
33704
|
+
checkViewport: function (opt) {
|
|
33705
|
+
return this.scheduleCellsVisibilityUpdate(opt);
|
|
33706
|
+
},
|
|
33144
33707
|
freeze: function (opt) {
|
|
33145
33708
|
opt || (opt = {});
|
|
33146
33709
|
var updates = this._updates;
|
|
@@ -33156,6 +33719,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33156
33719
|
this.options.frozen = true;
|
|
33157
33720
|
var id = updates.id;
|
|
33158
33721
|
updates.id = null;
|
|
33722
|
+
if (!this.legacyMode) {
|
|
33723
|
+
// Make sure the `freeze()` method ends the idle state.
|
|
33724
|
+
updates.idle = false;
|
|
33725
|
+
}
|
|
33159
33726
|
if (this.isAsync() && id) cancelFrame(id);
|
|
33160
33727
|
},
|
|
33161
33728
|
unfreeze: function (opt) {
|
|
@@ -33168,6 +33735,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33168
33735
|
updates.freezeKey = null;
|
|
33169
33736
|
// key passed, but the paper is already freezed
|
|
33170
33737
|
if (key && key === freezeKey && updates.keyFrozen) return;
|
|
33738
|
+
updates.idle = false;
|
|
33171
33739
|
if (this.isAsync()) {
|
|
33172
33740
|
this.freeze();
|
|
33173
33741
|
this.updateViewsAsync(opt);
|
|
@@ -33180,11 +33748,22 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33180
33748
|
updates.sort = false;
|
|
33181
33749
|
}
|
|
33182
33750
|
},
|
|
33751
|
+
wakeUp: function () {
|
|
33752
|
+
if (!this.isIdle()) return;
|
|
33753
|
+
this.unfreeze(this._updates.idle.wakeUpOptions);
|
|
33754
|
+
},
|
|
33183
33755
|
isAsync: function () {
|
|
33184
33756
|
return !!this.options.async;
|
|
33185
33757
|
},
|
|
33186
33758
|
isFrozen: function () {
|
|
33187
|
-
return !!this.options.frozen;
|
|
33759
|
+
return !!this.options.frozen && !this.isIdle();
|
|
33760
|
+
},
|
|
33761
|
+
isIdle: function () {
|
|
33762
|
+
if (this.legacyMode) {
|
|
33763
|
+
// Not implemented in the legacy mode.
|
|
33764
|
+
return false;
|
|
33765
|
+
}
|
|
33766
|
+
return !!(this._updates && this._updates.idle);
|
|
33188
33767
|
},
|
|
33189
33768
|
isExactSorting: function () {
|
|
33190
33769
|
return this.options.sorting === sortingTypes.EXACT;
|
|
@@ -33464,21 +34043,65 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33464
34043
|
}
|
|
33465
34044
|
return restrictedArea;
|
|
33466
34045
|
},
|
|
33467
|
-
|
|
34046
|
+
_resolveCellViewPlaceholder: function (placeholder) {
|
|
34047
|
+
const {
|
|
34048
|
+
model,
|
|
34049
|
+
viewClass,
|
|
34050
|
+
cid
|
|
34051
|
+
} = placeholder;
|
|
34052
|
+
const view = this._initializeCellView(viewClass, model, cid);
|
|
34053
|
+
this._registerCellView(view);
|
|
34054
|
+
this._unregisterCellViewPlaceholder(placeholder);
|
|
34055
|
+
return view;
|
|
34056
|
+
},
|
|
34057
|
+
_registerCellViewPlaceholder: function (cell, cid = uniqueId('view')) {
|
|
34058
|
+
const ViewClass = this._resolveCellViewClass(cell);
|
|
34059
|
+
const placeholder = {
|
|
34060
|
+
// A tag to identify the placeholder from a CellView.
|
|
34061
|
+
[CELL_VIEW_PLACEHOLDER_MARKER]: true,
|
|
34062
|
+
cid,
|
|
34063
|
+
model: cell,
|
|
34064
|
+
DETACHABLE: true,
|
|
34065
|
+
viewClass: ViewClass,
|
|
34066
|
+
UPDATE_PRIORITY: ViewClass.prototype.UPDATE_PRIORITY
|
|
34067
|
+
};
|
|
34068
|
+
this._viewPlaceholders[cid] = placeholder;
|
|
34069
|
+
return placeholder;
|
|
34070
|
+
},
|
|
34071
|
+
_registerCellView: function (cellView) {
|
|
34072
|
+
cellView.paper = this;
|
|
34073
|
+
this._views[cellView.model.id] = cellView;
|
|
34074
|
+
},
|
|
34075
|
+
_unregisterCellViewPlaceholder: function (placeholder) {
|
|
34076
|
+
delete this._viewPlaceholders[placeholder.cid];
|
|
34077
|
+
},
|
|
34078
|
+
_initializeCellView: function (ViewClass, cell, cid) {
|
|
34079
|
+
const {
|
|
34080
|
+
options
|
|
34081
|
+
} = this;
|
|
34082
|
+
const {
|
|
34083
|
+
interactive,
|
|
34084
|
+
labelsLayer
|
|
34085
|
+
} = options;
|
|
34086
|
+
return new ViewClass({
|
|
34087
|
+
cid,
|
|
34088
|
+
model: cell,
|
|
34089
|
+
interactive,
|
|
34090
|
+
labelsLayer: labelsLayer === true ? LayersNames.LABELS : labelsLayer
|
|
34091
|
+
});
|
|
34092
|
+
},
|
|
34093
|
+
_resolveCellViewClass: function (cell) {
|
|
33468
34094
|
const {
|
|
33469
34095
|
options
|
|
33470
34096
|
} = this;
|
|
34097
|
+
const {
|
|
34098
|
+
cellViewNamespace
|
|
34099
|
+
} = options;
|
|
34100
|
+
const type = cell.get('type') + 'View';
|
|
34101
|
+
const namespaceViewClass = getByPath(cellViewNamespace, type, '.');
|
|
33471
34102
|
// A class taken from the paper options.
|
|
33472
|
-
|
|
33473
|
-
|
|
33474
|
-
// A default basic class (either dia.ElementView or dia.LinkView)
|
|
33475
|
-
var defaultViewClass;
|
|
33476
|
-
|
|
33477
|
-
// A special class defined for this model in the corresponding namespace.
|
|
33478
|
-
// e.g. joint.shapes.standard.Rectangle searches for joint.shapes.standard.RectangleView
|
|
33479
|
-
var namespace = options.cellViewNamespace;
|
|
33480
|
-
var type = cell.get('type') + 'View';
|
|
33481
|
-
var namespaceViewClass = getByPath(namespace, type, '.');
|
|
34103
|
+
let optionalViewClass;
|
|
34104
|
+
let defaultViewClass;
|
|
33482
34105
|
if (cell.isLink()) {
|
|
33483
34106
|
optionalViewClass = options.linkView;
|
|
33484
34107
|
defaultViewClass = LinkView;
|
|
@@ -33486,7 +34109,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33486
34109
|
optionalViewClass = options.elementView;
|
|
33487
34110
|
defaultViewClass = ElementView;
|
|
33488
34111
|
}
|
|
33489
|
-
|
|
33490
34112
|
// a) the paper options view is a class (deprecated)
|
|
33491
34113
|
// 1. search the namespace for a view
|
|
33492
34114
|
// 2. if no view was found, use view from the paper options
|
|
@@ -33494,12 +34116,33 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33494
34116
|
// 1. call the function from the paper options
|
|
33495
34117
|
// 2. if no view was return, search the namespace for a view
|
|
33496
34118
|
// 3. if no view was found, use the default
|
|
33497
|
-
|
|
33498
|
-
|
|
33499
|
-
|
|
33500
|
-
|
|
33501
|
-
|
|
33502
|
-
|
|
34119
|
+
return optionalViewClass.prototype instanceof ViewBase ? namespaceViewClass || optionalViewClass : optionalViewClass.call(this, cell) || namespaceViewClass || defaultViewClass;
|
|
34120
|
+
},
|
|
34121
|
+
// Returns a CellView instance or its placeholder for the given cell.
|
|
34122
|
+
_getCellViewLike: function (cell) {
|
|
34123
|
+
let id;
|
|
34124
|
+
if (isString(cell) || isNumber(cell)) {
|
|
34125
|
+
// If the cell is a string or number, it is an id of the view.
|
|
34126
|
+
id = cell;
|
|
34127
|
+
} else if (cell) {
|
|
34128
|
+
// If the cell is an object, it should have an id property.
|
|
34129
|
+
id = cell.id;
|
|
34130
|
+
} else {
|
|
34131
|
+
// If the cell is falsy, return null.
|
|
34132
|
+
return null;
|
|
34133
|
+
}
|
|
34134
|
+
const view = this._views[id];
|
|
34135
|
+
if (view) return view;
|
|
34136
|
+
|
|
34137
|
+
// If the view is not found, it may be a placeholder
|
|
34138
|
+
const cid = this._idToCid[id];
|
|
34139
|
+
if (cid) {
|
|
34140
|
+
return this._viewPlaceholders[cid];
|
|
34141
|
+
}
|
|
34142
|
+
return null;
|
|
34143
|
+
},
|
|
34144
|
+
createViewForModel: function (cell, cid) {
|
|
34145
|
+
return this._initializeCellView(this._resolveCellViewClass(cell), cell, cid);
|
|
33503
34146
|
},
|
|
33504
34147
|
removeView: function (cell) {
|
|
33505
34148
|
const {
|
|
@@ -33515,13 +34158,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33515
34158
|
cid
|
|
33516
34159
|
} = view;
|
|
33517
34160
|
const {
|
|
33518
|
-
|
|
33519
|
-
|
|
34161
|
+
mountedList,
|
|
34162
|
+
unmountedList
|
|
33520
34163
|
} = _updates;
|
|
33521
34164
|
view.remove();
|
|
33522
34165
|
delete _views[id];
|
|
33523
|
-
delete
|
|
33524
|
-
delete
|
|
34166
|
+
delete this._idToCid[id];
|
|
34167
|
+
mountedList.delete(cid);
|
|
34168
|
+
unmountedList.delete(cid);
|
|
33525
34169
|
}
|
|
33526
34170
|
return view;
|
|
33527
34171
|
},
|
|
@@ -33535,7 +34179,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33535
34179
|
if (id in views) {
|
|
33536
34180
|
view = views[id];
|
|
33537
34181
|
if (view.model === cell) {
|
|
33538
|
-
flag =
|
|
34182
|
+
flag = this.FLAG_INSERT;
|
|
33539
34183
|
create = false;
|
|
33540
34184
|
} else {
|
|
33541
34185
|
// The view for this `id` already exist.
|
|
@@ -33545,13 +34189,42 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33545
34189
|
}
|
|
33546
34190
|
}
|
|
33547
34191
|
if (create) {
|
|
33548
|
-
|
|
33549
|
-
|
|
33550
|
-
|
|
34192
|
+
const {
|
|
34193
|
+
viewManagement
|
|
34194
|
+
} = this.options;
|
|
34195
|
+
const cid = uniqueId('view');
|
|
34196
|
+
this._idToCid[cell.id] = cid;
|
|
34197
|
+
if (viewManagement.lazyInitialize) {
|
|
34198
|
+
// Register only a placeholder for the view
|
|
34199
|
+
view = this._registerCellViewPlaceholder(cell, cid);
|
|
34200
|
+
flag = this.registerUnmountedView(view);
|
|
34201
|
+
} else {
|
|
34202
|
+
// Create a new view instance
|
|
34203
|
+
view = this.createViewForModel(cell, cid);
|
|
34204
|
+
this._registerCellView(view);
|
|
34205
|
+
flag = this.registerUnmountedView(view);
|
|
34206
|
+
// The newly created view needs to be initialized
|
|
34207
|
+
flag |= this.getCellViewInitFlag(view);
|
|
34208
|
+
}
|
|
34209
|
+
if (viewManagement.initializeUnmounted) {
|
|
34210
|
+
// Save the initialization flags for later and exit early
|
|
34211
|
+
this._mergeUnmountedViewScheduledUpdates(cid, flag);
|
|
34212
|
+
return view;
|
|
34213
|
+
}
|
|
33551
34214
|
}
|
|
33552
34215
|
this.requestViewUpdate(view, flag, view.UPDATE_PRIORITY, opt);
|
|
33553
34216
|
return view;
|
|
33554
34217
|
},
|
|
34218
|
+
// Update the view flags in the `unmountedList` using the bitwise OR operation
|
|
34219
|
+
_mergeUnmountedViewScheduledUpdates: function (cid, flag) {
|
|
34220
|
+
const {
|
|
34221
|
+
unmountedList
|
|
34222
|
+
} = this._updates;
|
|
34223
|
+
const unmountedItem = unmountedList.get(cid);
|
|
34224
|
+
if (unmountedItem) {
|
|
34225
|
+
unmountedItem.value |= flag;
|
|
34226
|
+
}
|
|
34227
|
+
},
|
|
33555
34228
|
onImageDragStart: function () {
|
|
33556
34229
|
// This is the only way to prevent image dragging in Firefox that works.
|
|
33557
34230
|
// Setting -moz-user-select: none, draggable="false" attribute or user-drag: none didn't help.
|
|
@@ -33561,11 +34234,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33561
34234
|
resetViews: function (cells, opt) {
|
|
33562
34235
|
opt || (opt = {});
|
|
33563
34236
|
cells || (cells = []);
|
|
34237
|
+
// Allows to unfreeze normally while in the idle state using autoFreeze option
|
|
34238
|
+
const key = (this.legacyMode ? this.options.autoFreeze : this.isIdle()) ? null : 'reset';
|
|
33564
34239
|
this._resetUpdates();
|
|
33565
34240
|
// clearing views removes any event listeners
|
|
33566
34241
|
this.removeViews();
|
|
33567
|
-
// Allows to unfreeze normally while in the idle state using autoFreeze option
|
|
33568
|
-
const key = this.options.autoFreeze ? null : 'reset';
|
|
33569
34242
|
this.freeze({
|
|
33570
34243
|
key
|
|
33571
34244
|
});
|
|
@@ -33578,15 +34251,23 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33578
34251
|
this.sortViews();
|
|
33579
34252
|
},
|
|
33580
34253
|
removeViews: function () {
|
|
33581
|
-
|
|
34254
|
+
// Remove all views and their references from the paper.
|
|
34255
|
+
for (const id in this._views) {
|
|
34256
|
+
const view = this._views[id];
|
|
34257
|
+
if (view) {
|
|
34258
|
+
view.remove();
|
|
34259
|
+
}
|
|
34260
|
+
}
|
|
33582
34261
|
this._views = {};
|
|
34262
|
+
this._viewPlaceholders = {};
|
|
34263
|
+
this._idToCid = {};
|
|
33583
34264
|
},
|
|
33584
34265
|
sortViews: function () {
|
|
33585
34266
|
if (!this.isExactSorting()) {
|
|
33586
34267
|
// noop
|
|
33587
34268
|
return;
|
|
33588
34269
|
}
|
|
33589
|
-
if (this.isFrozen()) {
|
|
34270
|
+
if (this.isFrozen() || this.isIdle()) {
|
|
33590
34271
|
// sort views once unfrozen
|
|
33591
34272
|
this._updates.sort = true;
|
|
33592
34273
|
return;
|
|
@@ -33625,9 +34306,54 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33625
34306
|
}
|
|
33626
34307
|
view.onMount(isInitialInsert);
|
|
33627
34308
|
},
|
|
33628
|
-
|
|
33629
|
-
|
|
33630
|
-
|
|
34309
|
+
_hideView: function (viewLike) {
|
|
34310
|
+
if (!viewLike || viewLike[CELL_VIEW_PLACEHOLDER_MARKER]) {
|
|
34311
|
+
// A placeholder view was never mounted
|
|
34312
|
+
return;
|
|
34313
|
+
}
|
|
34314
|
+
if (viewLike[CELL_VIEW_MARKER]) {
|
|
34315
|
+
this._hideCellView(viewLike);
|
|
34316
|
+
} else {
|
|
34317
|
+
// A generic view that is not a cell view.
|
|
34318
|
+
viewLike.unmount();
|
|
34319
|
+
}
|
|
34320
|
+
},
|
|
34321
|
+
// If `cellVisibility` returns `false`, the view will be hidden using this method.
|
|
34322
|
+
_hideCellView: function (cellView) {
|
|
34323
|
+
if (this.options.viewManagement.disposeHidden) {
|
|
34324
|
+
if (this._disposeCellView(cellView)) return;
|
|
34325
|
+
}
|
|
34326
|
+
// Detach the view from the paper, but keep it in memory
|
|
34327
|
+
this._detachCellView(cellView);
|
|
34328
|
+
},
|
|
34329
|
+
_disposeCellView: function (cellView) {
|
|
34330
|
+
if (HighlighterView.has(cellView) || cellView.hasTools()) {
|
|
34331
|
+
// We currently do not dispose views which has a highlighter or tools attached
|
|
34332
|
+
// Note: Possible improvement would be to serialize highlighters/tools and
|
|
34333
|
+
// restore them on view re-mount.
|
|
34334
|
+
return false;
|
|
34335
|
+
}
|
|
34336
|
+
const cell = cellView.model;
|
|
34337
|
+
// Remove the view from the paper and dispose it
|
|
34338
|
+
cellView.remove();
|
|
34339
|
+
delete this._views[cell.id];
|
|
34340
|
+
this._registerCellViewPlaceholder(cell, cellView.cid);
|
|
34341
|
+
return true;
|
|
34342
|
+
},
|
|
34343
|
+
// Dispose (release resources) all hidden views.
|
|
34344
|
+
disposeHiddenCellViews: function () {
|
|
34345
|
+
// Only cell views can be in the unmounted list (not in the legacy mode).
|
|
34346
|
+
if (this.legacyMode) return;
|
|
34347
|
+
const unmountedCids = this._updates.unmountedList.keys();
|
|
34348
|
+
for (const cid of unmountedCids) {
|
|
34349
|
+
const cellView = views[cid];
|
|
34350
|
+
cellView && this._disposeCellView(cellView);
|
|
34351
|
+
}
|
|
34352
|
+
},
|
|
34353
|
+
// Detach a view from the paper, but keep it in memory.
|
|
34354
|
+
_detachCellView(cellView) {
|
|
34355
|
+
cellView.unmount();
|
|
34356
|
+
cellView.onDetach();
|
|
33631
34357
|
},
|
|
33632
34358
|
// Find the first view climbing up the DOM tree starting at element `el`. Note that `el` can also
|
|
33633
34359
|
// be a selector or a jQuery object.
|
|
@@ -33638,9 +34364,31 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33638
34364
|
return undefined;
|
|
33639
34365
|
},
|
|
33640
34366
|
// Find a view for a model `cell`. `cell` can also be a string or number representing a model `id`.
|
|
33641
|
-
findViewByModel: function (
|
|
33642
|
-
|
|
33643
|
-
return
|
|
34367
|
+
findViewByModel: function (cellOrId) {
|
|
34368
|
+
const cellViewLike = this._getCellViewLike(cellOrId);
|
|
34369
|
+
if (!cellViewLike) return undefined;
|
|
34370
|
+
if (cellViewLike[CELL_VIEW_MARKER]) {
|
|
34371
|
+
// If the view is not a placeholder, return it directly
|
|
34372
|
+
return cellViewLike;
|
|
34373
|
+
}
|
|
34374
|
+
// We do not expose placeholder views directly. We resolve them before returning.
|
|
34375
|
+
const cellView = this._resolveCellViewPlaceholder(cellViewLike);
|
|
34376
|
+
const flag = this.getCellViewInitFlag(cellView);
|
|
34377
|
+
if (this.isViewMounted(cellView)) {
|
|
34378
|
+
// The view was acting as a placeholder and is already present in the `mounted` list,
|
|
34379
|
+
// indicating that its visibility has been checked, but the update hasn't occurred yet.
|
|
34380
|
+
// Placeholders are resolved during the update routine. Since we're handling it
|
|
34381
|
+
// manually here, we must ensure the view is properly initialized on the next update.
|
|
34382
|
+
this.scheduleViewUpdate(cellView, flag, cellView.UPDATE_PRIORITY, {
|
|
34383
|
+
// It's important to run in isolation to avoid triggering the update of
|
|
34384
|
+
// connected links
|
|
34385
|
+
isolate: true
|
|
34386
|
+
});
|
|
34387
|
+
} else {
|
|
34388
|
+
// Update the flags in the `unmounted` list
|
|
34389
|
+
this._mergeUnmountedViewScheduledUpdates(cellView.cid, flag);
|
|
34390
|
+
}
|
|
34391
|
+
return cellView;
|
|
33644
34392
|
},
|
|
33645
34393
|
// Find all views at given point
|
|
33646
34394
|
findViewsFromPoint: function (p) {
|
|
@@ -33687,6 +34435,93 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
33687
34435
|
// because the `strict` option works differently for querying at a point
|
|
33688
34436
|
extArea => this.model.findCellsInArea(extArea), opt);
|
|
33689
34437
|
},
|
|
34438
|
+
findClosestMagnetToPoint: function (point, options = {}) {
|
|
34439
|
+
let minDistance = Number.MAX_SAFE_INTEGER;
|
|
34440
|
+
let bestPriority = -Infinity;
|
|
34441
|
+
const pointer = new Point(point);
|
|
34442
|
+
const radius = options.radius || Number.MAX_SAFE_INTEGER;
|
|
34443
|
+
const viewsInArea = this.findCellViewsInArea({
|
|
34444
|
+
x: pointer.x - radius,
|
|
34445
|
+
y: pointer.y - radius,
|
|
34446
|
+
width: 2 * radius,
|
|
34447
|
+
height: 2 * radius
|
|
34448
|
+
}, options.findInAreaOptions);
|
|
34449
|
+
// Enable all connections by default
|
|
34450
|
+
const filterFn = typeof options.filter === 'function' ? options.filter : null;
|
|
34451
|
+
let closestView = null;
|
|
34452
|
+
let closestMagnet = null;
|
|
34453
|
+
|
|
34454
|
+
// Note: If snapRadius is smaller than magnet size, views will not be found.
|
|
34455
|
+
viewsInArea.forEach(view => {
|
|
34456
|
+
const candidates = [];
|
|
34457
|
+
const {
|
|
34458
|
+
model
|
|
34459
|
+
} = view;
|
|
34460
|
+
// skip connecting to the element in case '.': { magnet: false } attribute present
|
|
34461
|
+
if (view.el.getAttribute('magnet') !== 'false') {
|
|
34462
|
+
if (model.isLink()) {
|
|
34463
|
+
const connection = view.getConnection();
|
|
34464
|
+
candidates.push({
|
|
34465
|
+
// find distance from the closest point of a link to pointer coordinates
|
|
34466
|
+
priority: 0,
|
|
34467
|
+
distance: connection.closestPoint(pointer).squaredDistance(pointer),
|
|
34468
|
+
magnet: view.el
|
|
34469
|
+
});
|
|
34470
|
+
} else {
|
|
34471
|
+
candidates.push({
|
|
34472
|
+
// Set the priority to the level of nested elements of the model
|
|
34473
|
+
// To ensure that the embedded cells get priority over the parent cells
|
|
34474
|
+
priority: model.getAncestors().length,
|
|
34475
|
+
// find distance from the center of the model to pointer coordinates
|
|
34476
|
+
distance: model.getBBox().center().squaredDistance(pointer),
|
|
34477
|
+
magnet: view.el
|
|
34478
|
+
});
|
|
34479
|
+
}
|
|
34480
|
+
}
|
|
34481
|
+
view.$('[magnet]').toArray().forEach(magnet => {
|
|
34482
|
+
const magnetBBox = view.getNodeBBox(magnet);
|
|
34483
|
+
let magnetDistance = magnetBBox.pointNearestToPoint(pointer).squaredDistance(pointer);
|
|
34484
|
+
if (magnetBBox.containsPoint(pointer)) {
|
|
34485
|
+
// Pointer sits inside this magnet.
|
|
34486
|
+
// Push its distance far into the negative range so any
|
|
34487
|
+
// "under-pointer" magnet outranks magnets that are only nearby
|
|
34488
|
+
// (positive distance) and every non-magnet candidate.
|
|
34489
|
+
// We add the original distance back to keep ordering among
|
|
34490
|
+
// overlapping magnets: the one whose border is closest to the
|
|
34491
|
+
// pointer (smaller original distance) still wins.
|
|
34492
|
+
magnetDistance = -Number.MAX_SAFE_INTEGER + magnetDistance;
|
|
34493
|
+
}
|
|
34494
|
+
|
|
34495
|
+
// Check if magnet is inside the snap radius.
|
|
34496
|
+
if (magnetDistance <= radius * radius) {
|
|
34497
|
+
candidates.push({
|
|
34498
|
+
// Give magnets priority over other candidates.
|
|
34499
|
+
priority: Number.MAX_SAFE_INTEGER,
|
|
34500
|
+
distance: magnetDistance,
|
|
34501
|
+
magnet
|
|
34502
|
+
});
|
|
34503
|
+
}
|
|
34504
|
+
});
|
|
34505
|
+
candidates.forEach(candidate => {
|
|
34506
|
+
const {
|
|
34507
|
+
magnet,
|
|
34508
|
+
distance,
|
|
34509
|
+
priority
|
|
34510
|
+
} = candidate;
|
|
34511
|
+
const isBetterCandidate = priority > bestPriority || priority === bestPriority && distance < minDistance;
|
|
34512
|
+
if (isBetterCandidate && (!filterFn || filterFn(view, magnet))) {
|
|
34513
|
+
bestPriority = priority;
|
|
34514
|
+
minDistance = distance;
|
|
34515
|
+
closestView = view;
|
|
34516
|
+
closestMagnet = magnet;
|
|
34517
|
+
}
|
|
34518
|
+
});
|
|
34519
|
+
});
|
|
34520
|
+
return closestView ? {
|
|
34521
|
+
view: closestView,
|
|
34522
|
+
magnet: closestMagnet
|
|
34523
|
+
} : null;
|
|
34524
|
+
},
|
|
33690
34525
|
_findInExtendedArea: function (area, findCellsFn, opt = {}) {
|
|
33691
34526
|
const {
|
|
33692
34527
|
buffer = this.DEFAULT_FIND_BUFFER
|
|
@@ -34069,8 +34904,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
34069
34904
|
if (mousemoved <= this.options.moveThreshold) return;
|
|
34070
34905
|
evt = normalizeEvent(evt);
|
|
34071
34906
|
var localPoint = this.snapToGrid(evt.clientX, evt.clientY);
|
|
34072
|
-
|
|
34907
|
+
let view = data.sourceView;
|
|
34073
34908
|
if (view) {
|
|
34909
|
+
// The view could have been disposed during dragging
|
|
34910
|
+
// e.g. dragged outside of the viewport and hidden
|
|
34911
|
+
view = this.findViewByModel(view.model);
|
|
34074
34912
|
view.pointermove(evt, localPoint.x, localPoint.y);
|
|
34075
34913
|
} else {
|
|
34076
34914
|
this.trigger('blank:pointermove', evt, localPoint.x, localPoint.y);
|
|
@@ -34081,8 +34919,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
34081
34919
|
this.undelegateDocumentEvents();
|
|
34082
34920
|
var normalizedEvt = normalizeEvent(evt);
|
|
34083
34921
|
var localPoint = this.snapToGrid(normalizedEvt.clientX, normalizedEvt.clientY);
|
|
34084
|
-
|
|
34922
|
+
let view = this.eventData(evt).sourceView;
|
|
34085
34923
|
if (view) {
|
|
34924
|
+
// The view could have been disposed during dragging
|
|
34925
|
+
// e.g. dragged outside of the viewport and hidden
|
|
34926
|
+
view = this.findViewByModel(view.model);
|
|
34086
34927
|
view.pointerup(normalizedEvt, localPoint.x, localPoint.y);
|
|
34087
34928
|
} else {
|
|
34088
34929
|
this.trigger('blank:pointerup', normalizedEvt, localPoint.x, localPoint.y);
|
|
@@ -34948,6 +35789,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
34948
35789
|
isVisible: function () {
|
|
34949
35790
|
return !!this._visible;
|
|
34950
35791
|
},
|
|
35792
|
+
isOverlay: function () {
|
|
35793
|
+
return !!this.parentView && this.parentView.hasLayer();
|
|
35794
|
+
},
|
|
34951
35795
|
focus: function () {
|
|
34952
35796
|
var opacity = this.options.focusOpacity;
|
|
34953
35797
|
if (isFinite(opacity)) this.el.style.opacity = opacity;
|
|
@@ -35093,6 +35937,15 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
35093
35937
|
}
|
|
35094
35938
|
this.tools = null;
|
|
35095
35939
|
},
|
|
35940
|
+
getLayer() {
|
|
35941
|
+
const {
|
|
35942
|
+
layer = LayersNames.TOOLS
|
|
35943
|
+
} = this.options;
|
|
35944
|
+
return layer;
|
|
35945
|
+
},
|
|
35946
|
+
hasLayer() {
|
|
35947
|
+
return !!this.getLayer();
|
|
35948
|
+
},
|
|
35096
35949
|
mount: function () {
|
|
35097
35950
|
const {
|
|
35098
35951
|
options,
|
|
@@ -35100,12 +35953,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
35100
35953
|
} = this;
|
|
35101
35954
|
const {
|
|
35102
35955
|
relatedView,
|
|
35103
|
-
layer = LayersNames.TOOLS,
|
|
35104
35956
|
z
|
|
35105
35957
|
} = options;
|
|
35106
35958
|
if (relatedView) {
|
|
35107
|
-
if (
|
|
35108
|
-
relatedView.paper.getLayerView(
|
|
35959
|
+
if (this.hasLayer()) {
|
|
35960
|
+
relatedView.paper.getLayerView(this.getLayer()).insertSortedNode(el, z);
|
|
35109
35961
|
} else {
|
|
35110
35962
|
relatedView.el.appendChild(el);
|
|
35111
35963
|
}
|
|
@@ -35116,6 +35968,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
35116
35968
|
|
|
35117
35969
|
var index$2 = {
|
|
35118
35970
|
__proto__: null,
|
|
35971
|
+
CELL_VIEW_MARKER: CELL_VIEW_MARKER,
|
|
35119
35972
|
Cell: Cell,
|
|
35120
35973
|
CellView: CellView,
|
|
35121
35974
|
Element: Element$1,
|
|
@@ -35464,12 +36317,57 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
35464
36317
|
VertexHandle: VertexHandle // keep as class property
|
|
35465
36318
|
});
|
|
35466
36319
|
|
|
35467
|
-
|
|
36320
|
+
/**
|
|
36321
|
+
* Common helper for getting a cell view’s bounding box,
|
|
36322
|
+
* configurable with `useModelGeometry`, `relative`, and `el`.
|
|
36323
|
+
*/
|
|
36324
|
+
function getViewBBox(view, {
|
|
36325
|
+
useModelGeometry = false,
|
|
36326
|
+
relative = false,
|
|
36327
|
+
el = view.el
|
|
36328
|
+
} = {}) {
|
|
35468
36329
|
const {
|
|
35469
36330
|
model
|
|
35470
36331
|
} = view;
|
|
35471
|
-
|
|
35472
|
-
|
|
36332
|
+
let bbox;
|
|
36333
|
+
if (useModelGeometry) {
|
|
36334
|
+
// cell model bbox
|
|
36335
|
+
bbox = model.getBBox();
|
|
36336
|
+
} else if (model.isLink()) {
|
|
36337
|
+
// link view bbox
|
|
36338
|
+
bbox = view.getConnection().bbox();
|
|
36339
|
+
} else {
|
|
36340
|
+
// element view bbox
|
|
36341
|
+
bbox = view.getNodeUnrotatedBBox(el);
|
|
36342
|
+
}
|
|
36343
|
+
if (relative) {
|
|
36344
|
+
// Relative to the element position.
|
|
36345
|
+
const position = model.position();
|
|
36346
|
+
bbox.x -= position.x;
|
|
36347
|
+
bbox.y -= position.y;
|
|
36348
|
+
}
|
|
36349
|
+
return bbox;
|
|
36350
|
+
}
|
|
36351
|
+
|
|
36352
|
+
/**
|
|
36353
|
+
* Retrieves the tool options.
|
|
36354
|
+
* Automatically overrides `useModelGeometry` and `rotate`
|
|
36355
|
+
* if the tool is positioned relative to the element.
|
|
36356
|
+
*/
|
|
36357
|
+
function getToolOptions(toolView) {
|
|
36358
|
+
// Positioning is relative if the tool is drawn within the element view.
|
|
36359
|
+
const relative = !toolView.isOverlay();
|
|
36360
|
+
const {
|
|
36361
|
+
useModelGeometry,
|
|
36362
|
+
rotate,
|
|
36363
|
+
...otherOptions
|
|
36364
|
+
} = toolView.options;
|
|
36365
|
+
return {
|
|
36366
|
+
...otherOptions,
|
|
36367
|
+
useModelGeometry: useModelGeometry || relative,
|
|
36368
|
+
rotate: rotate || relative,
|
|
36369
|
+
relative
|
|
36370
|
+
};
|
|
35473
36371
|
}
|
|
35474
36372
|
function getAnchor(coords, view, magnet) {
|
|
35475
36373
|
// take advantage of an existing logic inside of the
|
|
@@ -36307,29 +37205,40 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36307
37205
|
return this;
|
|
36308
37206
|
},
|
|
36309
37207
|
updateHandle: function (handleNode) {
|
|
37208
|
+
const {
|
|
37209
|
+
options: {
|
|
37210
|
+
handleAttributes
|
|
37211
|
+
}
|
|
37212
|
+
} = this;
|
|
37213
|
+
handleNode.setAttribute('transform', this.getHandleTransformString());
|
|
37214
|
+
if (handleAttributes) {
|
|
37215
|
+
for (let attrName in handleAttributes) {
|
|
37216
|
+
handleNode.setAttribute(attrName, handleAttributes[attrName]);
|
|
37217
|
+
}
|
|
37218
|
+
}
|
|
37219
|
+
},
|
|
37220
|
+
getHandleTransformString() {
|
|
36310
37221
|
const {
|
|
36311
37222
|
relatedView,
|
|
36312
37223
|
options
|
|
36313
37224
|
} = this;
|
|
37225
|
+
const {
|
|
37226
|
+
scale
|
|
37227
|
+
} = options;
|
|
36314
37228
|
const {
|
|
36315
37229
|
model
|
|
36316
37230
|
} = relatedView;
|
|
36317
37231
|
const relativePos = this.getPosition(relatedView, this);
|
|
36318
|
-
const
|
|
36319
|
-
|
|
36320
|
-
|
|
36321
|
-
|
|
36322
|
-
|
|
36323
|
-
let transformString = `translate(${
|
|
37232
|
+
const translate = this.isOverlay()
|
|
37233
|
+
// The tool is rendered in the coordinate system of the paper
|
|
37234
|
+
? model.getAbsolutePointFromRelative(relativePos)
|
|
37235
|
+
// The tool is rendered in the coordinate system of the relatedView
|
|
37236
|
+
: relativePos;
|
|
37237
|
+
let transformString = `translate(${translate.x},${translate.y})`;
|
|
36324
37238
|
if (scale) {
|
|
36325
37239
|
transformString += ` scale(${scale})`;
|
|
36326
37240
|
}
|
|
36327
|
-
|
|
36328
|
-
if (handleAttributes) {
|
|
36329
|
-
for (let attrName in handleAttributes) {
|
|
36330
|
-
handleNode.setAttribute(attrName, handleAttributes[attrName]);
|
|
36331
|
-
}
|
|
36332
|
-
}
|
|
37241
|
+
return transformString;
|
|
36333
37242
|
},
|
|
36334
37243
|
updateExtras: function (extrasNode) {
|
|
36335
37244
|
const {
|
|
@@ -36337,19 +37246,40 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36337
37246
|
options
|
|
36338
37247
|
} = this;
|
|
36339
37248
|
const {
|
|
36340
|
-
selector
|
|
36341
|
-
|
|
37249
|
+
selector,
|
|
37250
|
+
relative,
|
|
37251
|
+
useModelGeometry
|
|
37252
|
+
} = getToolOptions(this);
|
|
36342
37253
|
if (!selector) {
|
|
37254
|
+
// Hide the extras if no selector is given.
|
|
36343
37255
|
this.toggleExtras(false);
|
|
36344
37256
|
return;
|
|
36345
37257
|
}
|
|
36346
|
-
|
|
36347
|
-
|
|
37258
|
+
// Get the size for the extras rectangle and update it.
|
|
37259
|
+
let bbox;
|
|
37260
|
+
if (useModelGeometry) {
|
|
37261
|
+
if (selector !== 'root') {
|
|
37262
|
+
// A selector other than null or `root` was provided.
|
|
37263
|
+
console.warn('Control: selector will be ignored when `useModelGeometry` is used.');
|
|
37264
|
+
}
|
|
37265
|
+
bbox = getViewBBox(relatedView, {
|
|
37266
|
+
useModelGeometry,
|
|
37267
|
+
relative
|
|
37268
|
+
});
|
|
37269
|
+
} else {
|
|
37270
|
+
// The reference node for calculating the bounding box of the extras.
|
|
37271
|
+
const el = relatedView.findNode(selector);
|
|
37272
|
+
if (!el) throw new Error('Control: invalid selector.');
|
|
37273
|
+
bbox = getViewBBox(relatedView, {
|
|
37274
|
+
el
|
|
37275
|
+
});
|
|
37276
|
+
}
|
|
36348
37277
|
let padding = options.padding;
|
|
36349
37278
|
if (!isFinite(padding)) padding = 0;
|
|
36350
|
-
const bbox = relatedView.getNodeUnrotatedBBox(magnet);
|
|
36351
37279
|
const model = relatedView.model;
|
|
36352
|
-
|
|
37280
|
+
// With relative positioning, rotation is implicit
|
|
37281
|
+
// (the tool rotates along with the element).
|
|
37282
|
+
const angle = relative ? 0 : model.angle();
|
|
36353
37283
|
const center = bbox.center();
|
|
36354
37284
|
if (angle) center.rotate(model.getCenter(), -angle);
|
|
36355
37285
|
bbox.inflate(padding);
|
|
@@ -36560,8 +37490,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36560
37490
|
},
|
|
36561
37491
|
getElementMatrix() {
|
|
36562
37492
|
const {
|
|
36563
|
-
relatedView: view
|
|
36564
|
-
options
|
|
37493
|
+
relatedView: view
|
|
36565
37494
|
} = this;
|
|
36566
37495
|
let {
|
|
36567
37496
|
x = 0,
|
|
@@ -36569,9 +37498,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36569
37498
|
offset = {},
|
|
36570
37499
|
useModelGeometry,
|
|
36571
37500
|
rotate,
|
|
36572
|
-
scale
|
|
36573
|
-
|
|
36574
|
-
|
|
37501
|
+
scale,
|
|
37502
|
+
relative
|
|
37503
|
+
} = getToolOptions(this);
|
|
37504
|
+
let bbox = getViewBBox(view, {
|
|
37505
|
+
useModelGeometry,
|
|
37506
|
+
relative
|
|
37507
|
+
});
|
|
36575
37508
|
const angle = view.model.angle();
|
|
36576
37509
|
if (!rotate) bbox = bbox.bbox(angle);
|
|
36577
37510
|
const {
|
|
@@ -36589,7 +37522,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36589
37522
|
y = Number(evalCalcExpression(y, bbox));
|
|
36590
37523
|
}
|
|
36591
37524
|
let matrix = V.createSVGMatrix().translate(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2);
|
|
36592
|
-
|
|
37525
|
+
// With relative positioning, rotation is implicit
|
|
37526
|
+
// (the tool rotates along with the element).
|
|
37527
|
+
if (rotate && !relative) matrix = matrix.rotate(angle);
|
|
36593
37528
|
matrix = matrix.translate(x + offsetX - bbox.width / 2, y + offsetY - bbox.height / 2);
|
|
36594
37529
|
if (scale) matrix = matrix.scale(scale);
|
|
36595
37530
|
return matrix;
|
|
@@ -36687,26 +37622,32 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36687
37622
|
update: function () {
|
|
36688
37623
|
const {
|
|
36689
37624
|
relatedView: view,
|
|
36690
|
-
options,
|
|
36691
37625
|
vel
|
|
36692
37626
|
} = this;
|
|
36693
37627
|
const {
|
|
36694
37628
|
useModelGeometry,
|
|
36695
|
-
rotate
|
|
36696
|
-
|
|
36697
|
-
|
|
36698
|
-
|
|
36699
|
-
|
|
36700
|
-
|
|
36701
|
-
|
|
36702
|
-
|
|
37629
|
+
rotate,
|
|
37630
|
+
relative,
|
|
37631
|
+
padding
|
|
37632
|
+
} = getToolOptions(this);
|
|
37633
|
+
const normalizedPadding = normalizeSides(padding);
|
|
37634
|
+
let bbox = getViewBBox(view, {
|
|
37635
|
+
useModelGeometry,
|
|
37636
|
+
relative
|
|
37637
|
+
}).moveAndExpand({
|
|
37638
|
+
x: -normalizedPadding.left,
|
|
37639
|
+
y: -normalizedPadding.top,
|
|
37640
|
+
width: normalizedPadding.left + normalizedPadding.right,
|
|
37641
|
+
height: normalizedPadding.top + normalizedPadding.bottom
|
|
36703
37642
|
});
|
|
36704
|
-
|
|
36705
|
-
|
|
36706
|
-
|
|
37643
|
+
const model = view.model;
|
|
37644
|
+
// With relative positioning, rotation is implicit
|
|
37645
|
+
// (the tool rotates along with the element).
|
|
37646
|
+
if (model.isElement() && !relative) {
|
|
37647
|
+
const angle = model.angle();
|
|
36707
37648
|
if (angle) {
|
|
36708
37649
|
if (rotate) {
|
|
36709
|
-
|
|
37650
|
+
const origin = model.getCenter();
|
|
36710
37651
|
vel.rotate(angle, origin.x, origin.y, {
|
|
36711
37652
|
absolute: true
|
|
36712
37653
|
});
|
|
@@ -36932,13 +37873,16 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36932
37873
|
getTrackMatrix() {
|
|
36933
37874
|
return V.createSVGMatrix();
|
|
36934
37875
|
},
|
|
37876
|
+
getTrackMatrixAbsolute() {
|
|
37877
|
+
return this.getTrackMatrix();
|
|
37878
|
+
},
|
|
36935
37879
|
getTrackRatioFromEvent(evt) {
|
|
36936
37880
|
const {
|
|
36937
37881
|
relatedView,
|
|
36938
37882
|
trackPath
|
|
36939
37883
|
} = this;
|
|
36940
37884
|
const localPoint = relatedView.paper.clientToLocalPoint(evt.clientX, evt.clientY);
|
|
36941
|
-
const trackPoint = V.transformPoint(localPoint, this.
|
|
37885
|
+
const trackPoint = V.transformPoint(localPoint, this.getTrackMatrixAbsolute().inverse());
|
|
36942
37886
|
return trackPath.closestPointLength(trackPoint);
|
|
36943
37887
|
},
|
|
36944
37888
|
canShowButton() {
|
|
@@ -36992,32 +37936,40 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
36992
37936
|
const HoverConnect = HoverConnect$1.extend({
|
|
36993
37937
|
getTrackPath() {
|
|
36994
37938
|
const {
|
|
36995
|
-
relatedView: view
|
|
36996
|
-
options
|
|
37939
|
+
relatedView: view
|
|
36997
37940
|
} = this;
|
|
36998
37941
|
let {
|
|
36999
37942
|
useModelGeometry,
|
|
37943
|
+
relative,
|
|
37000
37944
|
trackPath = 'M 0 0 H calc(w) V calc(h) H 0 Z'
|
|
37001
|
-
} =
|
|
37945
|
+
} = getToolOptions(this);
|
|
37002
37946
|
if (typeof trackPath === 'function') {
|
|
37003
37947
|
trackPath = trackPath.call(this, view);
|
|
37004
37948
|
}
|
|
37005
37949
|
if (isCalcExpression(trackPath)) {
|
|
37006
|
-
const bbox = getViewBBox(view,
|
|
37950
|
+
const bbox = getViewBBox(view, {
|
|
37951
|
+
useModelGeometry,
|
|
37952
|
+
relative
|
|
37953
|
+
});
|
|
37007
37954
|
trackPath = evalCalcExpression(trackPath, bbox);
|
|
37008
37955
|
}
|
|
37009
37956
|
return new Path$1(V.normalizePathData(trackPath));
|
|
37010
37957
|
},
|
|
37011
37958
|
getTrackMatrix() {
|
|
37959
|
+
if (this.isOverlay()) return this.getTrackMatrixAbsolute();
|
|
37960
|
+
return V.createSVGMatrix();
|
|
37961
|
+
},
|
|
37962
|
+
getTrackMatrixAbsolute() {
|
|
37012
37963
|
const {
|
|
37013
|
-
relatedView: view
|
|
37014
|
-
options
|
|
37964
|
+
relatedView: view
|
|
37015
37965
|
} = this;
|
|
37016
37966
|
let {
|
|
37017
37967
|
useModelGeometry,
|
|
37018
37968
|
rotate
|
|
37019
|
-
} =
|
|
37020
|
-
let bbox = getViewBBox(view,
|
|
37969
|
+
} = getToolOptions(this);
|
|
37970
|
+
let bbox = getViewBBox(view, {
|
|
37971
|
+
useModelGeometry
|
|
37972
|
+
});
|
|
37021
37973
|
const angle = view.model.angle();
|
|
37022
37974
|
if (!rotate) bbox = bbox.bbox(angle);
|
|
37023
37975
|
let matrix = V.createSVGMatrix().translate(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2);
|
|
@@ -37037,7 +37989,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
37037
37989
|
Remove: Remove
|
|
37038
37990
|
};
|
|
37039
37991
|
|
|
37040
|
-
var version = "4.2.0-alpha.
|
|
37992
|
+
var version = "4.2.0-alpha.1";
|
|
37041
37993
|
|
|
37042
37994
|
const Vectorizer = V;
|
|
37043
37995
|
const layout$1 = {
|