@joint/core 4.0.0
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/LICENSE +376 -0
- package/README.md +49 -0
- package/dist/geometry.js +6486 -0
- package/dist/geometry.min.js +8 -0
- package/dist/joint.d.ts +5536 -0
- package/dist/joint.js +39629 -0
- package/dist/joint.min.js +8 -0
- package/dist/joint.nowrap.js +39626 -0
- package/dist/joint.nowrap.min.js +8 -0
- package/dist/vectorizer.js +9135 -0
- package/dist/vectorizer.min.js +8 -0
- package/dist/version.mjs +3 -0
- package/index.js +3 -0
- package/joint.mjs +27 -0
- package/package.json +192 -0
- package/src/V/annotation.mjs +0 -0
- package/src/V/index.mjs +2642 -0
- package/src/anchors/index.mjs +123 -0
- package/src/config/index.mjs +12 -0
- package/src/connectionPoints/index.mjs +202 -0
- package/src/connectionStrategies/index.mjs +73 -0
- package/src/connectors/curve.mjs +553 -0
- package/src/connectors/index.mjs +6 -0
- package/src/connectors/jumpover.mjs +452 -0
- package/src/connectors/normal.mjs +12 -0
- package/src/connectors/rounded.mjs +17 -0
- package/src/connectors/smooth.mjs +44 -0
- package/src/connectors/straight.mjs +110 -0
- package/src/dia/Cell.mjs +945 -0
- package/src/dia/CellView.mjs +1316 -0
- package/src/dia/Element.mjs +519 -0
- package/src/dia/ElementView.mjs +859 -0
- package/src/dia/Graph.mjs +1112 -0
- package/src/dia/HighlighterView.mjs +319 -0
- package/src/dia/Link.mjs +565 -0
- package/src/dia/LinkView.mjs +2207 -0
- package/src/dia/Paper.mjs +3171 -0
- package/src/dia/PaperLayer.mjs +75 -0
- package/src/dia/ToolView.mjs +69 -0
- package/src/dia/ToolsView.mjs +128 -0
- package/src/dia/attributes/calc.mjs +128 -0
- package/src/dia/attributes/connection.mjs +75 -0
- package/src/dia/attributes/defs.mjs +76 -0
- package/src/dia/attributes/eval.mjs +64 -0
- package/src/dia/attributes/index.mjs +69 -0
- package/src/dia/attributes/legacy.mjs +148 -0
- package/src/dia/attributes/offset.mjs +53 -0
- package/src/dia/attributes/props.mjs +30 -0
- package/src/dia/attributes/shape.mjs +92 -0
- package/src/dia/attributes/text.mjs +180 -0
- package/src/dia/index.mjs +13 -0
- package/src/dia/layers/GridLayer.mjs +176 -0
- package/src/dia/ports.mjs +874 -0
- package/src/elementTools/Control.mjs +153 -0
- package/src/elementTools/HoverConnect.mjs +37 -0
- package/src/elementTools/index.mjs +5 -0
- package/src/env/index.mjs +43 -0
- package/src/g/bezier.mjs +175 -0
- package/src/g/curve.mjs +956 -0
- package/src/g/ellipse.mjs +245 -0
- package/src/g/extend.mjs +64 -0
- package/src/g/geometry.helpers.mjs +58 -0
- package/src/g/index.mjs +17 -0
- package/src/g/intersection.mjs +511 -0
- package/src/g/line.bearing.mjs +30 -0
- package/src/g/line.length.mjs +5 -0
- package/src/g/line.mjs +356 -0
- package/src/g/line.squaredLength.mjs +10 -0
- package/src/g/path.mjs +2260 -0
- package/src/g/point.mjs +375 -0
- package/src/g/points.mjs +247 -0
- package/src/g/polygon.mjs +51 -0
- package/src/g/polyline.mjs +523 -0
- package/src/g/rect.mjs +556 -0
- package/src/g/types.mjs +10 -0
- package/src/highlighters/addClass.mjs +27 -0
- package/src/highlighters/index.mjs +5 -0
- package/src/highlighters/list.mjs +111 -0
- package/src/highlighters/mask.mjs +220 -0
- package/src/highlighters/opacity.mjs +17 -0
- package/src/highlighters/stroke.mjs +100 -0
- package/src/layout/index.mjs +4 -0
- package/src/layout/ports/port.mjs +188 -0
- package/src/layout/ports/portLabel.mjs +224 -0
- package/src/linkAnchors/index.mjs +76 -0
- package/src/linkTools/Anchor.mjs +235 -0
- package/src/linkTools/Arrowhead.mjs +103 -0
- package/src/linkTools/Boundary.mjs +48 -0
- package/src/linkTools/Button.mjs +121 -0
- package/src/linkTools/Connect.mjs +85 -0
- package/src/linkTools/HoverConnect.mjs +161 -0
- package/src/linkTools/Segments.mjs +393 -0
- package/src/linkTools/Vertices.mjs +253 -0
- package/src/linkTools/helpers.mjs +33 -0
- package/src/linkTools/index.mjs +8 -0
- package/src/mvc/Collection.mjs +560 -0
- package/src/mvc/Data.mjs +46 -0
- package/src/mvc/Dom/Dom.mjs +587 -0
- package/src/mvc/Dom/Event.mjs +130 -0
- package/src/mvc/Dom/animations.mjs +122 -0
- package/src/mvc/Dom/events.mjs +69 -0
- package/src/mvc/Dom/index.mjs +13 -0
- package/src/mvc/Dom/methods.mjs +392 -0
- package/src/mvc/Dom/props.mjs +77 -0
- package/src/mvc/Dom/vars.mjs +5 -0
- package/src/mvc/Events.mjs +337 -0
- package/src/mvc/Listener.mjs +33 -0
- package/src/mvc/Model.mjs +239 -0
- package/src/mvc/View.mjs +323 -0
- package/src/mvc/ViewBase.mjs +182 -0
- package/src/mvc/index.mjs +9 -0
- package/src/mvc/mvcUtils.mjs +90 -0
- package/src/polyfills/array.js +4 -0
- package/src/polyfills/base64.js +68 -0
- package/src/polyfills/index.mjs +5 -0
- package/src/polyfills/number.js +3 -0
- package/src/polyfills/string.js +3 -0
- package/src/polyfills/typedArray.js +47 -0
- package/src/routers/index.mjs +6 -0
- package/src/routers/manhattan.mjs +856 -0
- package/src/routers/metro.mjs +91 -0
- package/src/routers/normal.mjs +6 -0
- package/src/routers/oneSide.mjs +60 -0
- package/src/routers/orthogonal.mjs +323 -0
- package/src/routers/rightAngle.mjs +1056 -0
- package/src/shapes/index.mjs +3 -0
- package/src/shapes/standard.mjs +755 -0
- package/src/util/cloneCells.mjs +67 -0
- package/src/util/getRectPoint.mjs +65 -0
- package/src/util/index.mjs +5 -0
- package/src/util/svgTagTemplate.mjs +110 -0
- package/src/util/util.mjs +1754 -0
- package/src/util/utilHelpers.mjs +2402 -0
- package/src/util/wrappers.mjs +56 -0
- package/types/geometry.d.ts +815 -0
- package/types/index.d.ts +53 -0
- package/types/joint.d.ts +4391 -0
- package/types/joint.head.d.ts +12 -0
- package/types/vectorizer.d.ts +327 -0
package/src/dia/Link.mjs
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
import { Cell } from './Cell.mjs';
|
|
2
|
+
import { clone, isPlainObject, isFunction, isString, isNumber } from '../util/index.mjs';
|
|
3
|
+
import { Point, Polyline } from '../g/index.mjs';
|
|
4
|
+
|
|
5
|
+
// Link base model.
|
|
6
|
+
// --------------------------
|
|
7
|
+
|
|
8
|
+
export const Link = Cell.extend({
|
|
9
|
+
|
|
10
|
+
// may be overwritten by user to change default label (its markup, size, attrs, position)
|
|
11
|
+
defaultLabel: undefined,
|
|
12
|
+
|
|
13
|
+
// deprecated
|
|
14
|
+
// may be overwritten by user to change default label markup
|
|
15
|
+
// lower priority than defaultLabel.markup
|
|
16
|
+
labelMarkup: undefined,
|
|
17
|
+
|
|
18
|
+
// private
|
|
19
|
+
_builtins: {
|
|
20
|
+
defaultLabel: {
|
|
21
|
+
// builtin default markup:
|
|
22
|
+
// used if neither defaultLabel.markup
|
|
23
|
+
// nor label.markup is set
|
|
24
|
+
markup: [
|
|
25
|
+
{
|
|
26
|
+
tagName: 'rect',
|
|
27
|
+
selector: 'rect' // faster than tagName CSS selector
|
|
28
|
+
}, {
|
|
29
|
+
tagName: 'text',
|
|
30
|
+
selector: 'text' // faster than tagName CSS selector
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
// builtin default attributes:
|
|
34
|
+
// applied only if builtin default markup is used
|
|
35
|
+
attrs: {
|
|
36
|
+
text: {
|
|
37
|
+
fill: '#000000',
|
|
38
|
+
fontSize: 14,
|
|
39
|
+
textAnchor: 'middle',
|
|
40
|
+
textVerticalAnchor: 'middle',
|
|
41
|
+
pointerEvents: 'none'
|
|
42
|
+
},
|
|
43
|
+
rect: {
|
|
44
|
+
ref: 'text',
|
|
45
|
+
fill: '#ffffff',
|
|
46
|
+
rx: 3,
|
|
47
|
+
ry: 3,
|
|
48
|
+
x: 'calc(x)',
|
|
49
|
+
y: 'calc(y)',
|
|
50
|
+
width: 'calc(w)',
|
|
51
|
+
height: 'calc(h)'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
// builtin default position:
|
|
55
|
+
// used if neither defaultLabel.position
|
|
56
|
+
// nor label.position is set
|
|
57
|
+
position: {
|
|
58
|
+
distance: 0.5
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
defaults: {
|
|
64
|
+
source: {},
|
|
65
|
+
target: {}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
isLink: function() {
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
disconnect: function(opt) {
|
|
74
|
+
|
|
75
|
+
return this.set({
|
|
76
|
+
source: { x: 0, y: 0 },
|
|
77
|
+
target: { x: 0, y: 0 }
|
|
78
|
+
}, opt);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
source: function(source, args, opt) {
|
|
82
|
+
|
|
83
|
+
// getter
|
|
84
|
+
if (source === undefined) {
|
|
85
|
+
return clone(this.get('source'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// setter
|
|
89
|
+
var setSource;
|
|
90
|
+
var setOpt;
|
|
91
|
+
|
|
92
|
+
// `source` is a cell
|
|
93
|
+
// take only its `id` and combine with `args`
|
|
94
|
+
var isCellProvided = source instanceof Cell;
|
|
95
|
+
if (isCellProvided) { // three arguments
|
|
96
|
+
setSource = clone(args) || {};
|
|
97
|
+
setSource.id = source.id;
|
|
98
|
+
setOpt = opt;
|
|
99
|
+
return this.set('source', setSource, setOpt);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// `source` is a point-like object
|
|
103
|
+
// for example, a g.Point
|
|
104
|
+
// take only its `x` and `y` and combine with `args`
|
|
105
|
+
var isPointProvided = !isPlainObject(source);
|
|
106
|
+
if (isPointProvided) { // three arguments
|
|
107
|
+
setSource = clone(args) || {};
|
|
108
|
+
setSource.x = source.x;
|
|
109
|
+
setSource.y = source.y;
|
|
110
|
+
setOpt = opt;
|
|
111
|
+
return this.set('source', setSource, setOpt);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// `source` is an object
|
|
115
|
+
// no checking
|
|
116
|
+
// two arguments
|
|
117
|
+
setSource = source;
|
|
118
|
+
setOpt = args;
|
|
119
|
+
return this.set('source', setSource, setOpt);
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
target: function(target, args, opt) {
|
|
123
|
+
|
|
124
|
+
// getter
|
|
125
|
+
if (target === undefined) {
|
|
126
|
+
return clone(this.get('target'));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// setter
|
|
130
|
+
var setTarget;
|
|
131
|
+
var setOpt;
|
|
132
|
+
|
|
133
|
+
// `target` is a cell
|
|
134
|
+
// take only its `id` argument and combine with `args`
|
|
135
|
+
var isCellProvided = target instanceof Cell;
|
|
136
|
+
if (isCellProvided) { // three arguments
|
|
137
|
+
setTarget = clone(args) || {};
|
|
138
|
+
setTarget.id = target.id;
|
|
139
|
+
setOpt = opt;
|
|
140
|
+
return this.set('target', setTarget, setOpt);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// `target` is a point-like object
|
|
144
|
+
// for example, a g.Point
|
|
145
|
+
// take only its `x` and `y` and combine with `args`
|
|
146
|
+
var isPointProvided = !isPlainObject(target);
|
|
147
|
+
if (isPointProvided) { // three arguments
|
|
148
|
+
setTarget = clone(args) || {};
|
|
149
|
+
setTarget.x = target.x;
|
|
150
|
+
setTarget.y = target.y;
|
|
151
|
+
setOpt = opt;
|
|
152
|
+
return this.set('target', setTarget, setOpt);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// `target` is an object
|
|
156
|
+
// no checking
|
|
157
|
+
// two arguments
|
|
158
|
+
setTarget = target;
|
|
159
|
+
setOpt = args;
|
|
160
|
+
return this.set('target', setTarget, setOpt);
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
router: function(name, args, opt) {
|
|
164
|
+
|
|
165
|
+
// getter
|
|
166
|
+
if (name === undefined) {
|
|
167
|
+
var router = this.get('router');
|
|
168
|
+
if (!router) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
if (typeof router === 'object') return clone(router);
|
|
172
|
+
return router; // e.g. a function
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// setter
|
|
176
|
+
var isRouterProvided = ((typeof name === 'object') || (typeof name === 'function'));
|
|
177
|
+
var localRouter = isRouterProvided ? name : { name: name, args: args };
|
|
178
|
+
var localOpt = isRouterProvided ? args : opt;
|
|
179
|
+
|
|
180
|
+
return this.set('router', localRouter, localOpt);
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
connector: function(name, args, opt) {
|
|
184
|
+
|
|
185
|
+
// getter
|
|
186
|
+
if (name === undefined) {
|
|
187
|
+
var connector = this.get('connector');
|
|
188
|
+
if (!connector) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
if (typeof connector === 'object') return clone(connector);
|
|
192
|
+
return connector; // e.g. a function
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// setter
|
|
196
|
+
var isConnectorProvided = ((typeof name === 'object' || typeof name === 'function'));
|
|
197
|
+
var localConnector = isConnectorProvided ? name : { name: name, args: args };
|
|
198
|
+
var localOpt = isConnectorProvided ? args : opt;
|
|
199
|
+
|
|
200
|
+
return this.set('connector', localConnector, localOpt);
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// Labels API
|
|
204
|
+
|
|
205
|
+
// A convenient way to set labels. Currently set values will be mixined with `value` if used as a setter.
|
|
206
|
+
label: function(idx, label, opt) {
|
|
207
|
+
|
|
208
|
+
var labels = this.labels();
|
|
209
|
+
|
|
210
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : 0;
|
|
211
|
+
if (idx < 0) idx = labels.length + idx;
|
|
212
|
+
|
|
213
|
+
// getter
|
|
214
|
+
if (arguments.length <= 1) return this.prop(['labels', idx]);
|
|
215
|
+
// setter
|
|
216
|
+
return this.prop(['labels', idx], label, opt);
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
labels: function(labels, opt) {
|
|
220
|
+
|
|
221
|
+
// getter
|
|
222
|
+
if (arguments.length === 0) {
|
|
223
|
+
labels = this.get('labels');
|
|
224
|
+
if (!Array.isArray(labels)) return [];
|
|
225
|
+
return labels.slice();
|
|
226
|
+
}
|
|
227
|
+
// setter
|
|
228
|
+
if (!Array.isArray(labels)) labels = [];
|
|
229
|
+
return this.set('labels', labels, opt);
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
hasLabels: function() {
|
|
233
|
+
const { labels } = this.attributes;
|
|
234
|
+
return Array.isArray(labels) && labels.length > 0;
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
insertLabel: function(idx, label, opt) {
|
|
238
|
+
|
|
239
|
+
if (!label) throw new Error('dia.Link: no label provided');
|
|
240
|
+
|
|
241
|
+
var labels = this.labels();
|
|
242
|
+
var n = labels.length;
|
|
243
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : n;
|
|
244
|
+
if (idx < 0) idx = n + idx + 1;
|
|
245
|
+
|
|
246
|
+
labels.splice(idx, 0, label);
|
|
247
|
+
return this.labels(labels, opt);
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
// convenience function
|
|
251
|
+
// add label to end of labels array
|
|
252
|
+
appendLabel: function(label, opt) {
|
|
253
|
+
|
|
254
|
+
return this.insertLabel(-1, label, opt);
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
removeLabel: function(idx, opt) {
|
|
258
|
+
|
|
259
|
+
var labels = this.labels();
|
|
260
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : -1;
|
|
261
|
+
|
|
262
|
+
labels.splice(idx, 1);
|
|
263
|
+
return this.labels(labels, opt);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
// Vertices API
|
|
267
|
+
|
|
268
|
+
vertex: function(idx, vertex, opt) {
|
|
269
|
+
|
|
270
|
+
var vertices = this.vertices();
|
|
271
|
+
|
|
272
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : 0;
|
|
273
|
+
if (idx < 0) idx = vertices.length + idx;
|
|
274
|
+
|
|
275
|
+
// getter
|
|
276
|
+
if (arguments.length <= 1) return this.prop(['vertices', idx]);
|
|
277
|
+
|
|
278
|
+
// setter
|
|
279
|
+
var setVertex = this._normalizeVertex(vertex);
|
|
280
|
+
return this.prop(['vertices', idx], setVertex, opt);
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
vertices: function(vertices, opt) {
|
|
284
|
+
|
|
285
|
+
// getter
|
|
286
|
+
if (arguments.length === 0) {
|
|
287
|
+
vertices = this.get('vertices');
|
|
288
|
+
if (!Array.isArray(vertices)) return [];
|
|
289
|
+
return vertices.slice();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// setter
|
|
293
|
+
if (!Array.isArray(vertices)) vertices = [];
|
|
294
|
+
var setVertices = [];
|
|
295
|
+
for (var i = 0; i < vertices.length; i++) {
|
|
296
|
+
var vertex = vertices[i];
|
|
297
|
+
var setVertex = this._normalizeVertex(vertex);
|
|
298
|
+
setVertices.push(setVertex);
|
|
299
|
+
}
|
|
300
|
+
return this.set('vertices', setVertices, opt);
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
insertVertex: function(idx, vertex, opt) {
|
|
304
|
+
|
|
305
|
+
if (!vertex) throw new Error('dia.Link: no vertex provided');
|
|
306
|
+
|
|
307
|
+
var vertices = this.vertices();
|
|
308
|
+
var n = vertices.length;
|
|
309
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : n;
|
|
310
|
+
if (idx < 0) idx = n + idx + 1;
|
|
311
|
+
|
|
312
|
+
var setVertex = this._normalizeVertex(vertex);
|
|
313
|
+
vertices.splice(idx, 0, setVertex);
|
|
314
|
+
return this.vertices(vertices, opt);
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
removeVertex: function(idx, opt) {
|
|
318
|
+
|
|
319
|
+
var vertices = this.vertices();
|
|
320
|
+
idx = (isFinite(idx) && idx !== null) ? (idx | 0) : -1;
|
|
321
|
+
|
|
322
|
+
vertices.splice(idx, 1);
|
|
323
|
+
return this.vertices(vertices, opt);
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
_normalizeVertex: function(vertex) {
|
|
327
|
+
|
|
328
|
+
// is vertex a point-like object?
|
|
329
|
+
// for example, a g.Point
|
|
330
|
+
var isPointProvided = !isPlainObject(vertex);
|
|
331
|
+
if (isPointProvided) return { x: vertex.x, y: vertex.y };
|
|
332
|
+
|
|
333
|
+
// else: return vertex unchanged
|
|
334
|
+
return vertex;
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
// Transformations
|
|
338
|
+
|
|
339
|
+
translate: function(tx, ty, opt) {
|
|
340
|
+
|
|
341
|
+
// enrich the option object
|
|
342
|
+
opt = opt || {};
|
|
343
|
+
opt.translateBy = opt.translateBy || this.id;
|
|
344
|
+
opt.tx = tx;
|
|
345
|
+
opt.ty = ty;
|
|
346
|
+
|
|
347
|
+
return this.applyToPoints(function(p) {
|
|
348
|
+
return { x: (p.x || 0) + tx, y: (p.y || 0) + ty };
|
|
349
|
+
}, opt);
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
scale: function(sx, sy, origin, opt) {
|
|
353
|
+
|
|
354
|
+
return this.applyToPoints(function(p) {
|
|
355
|
+
return Point(p).scale(sx, sy, origin).toJSON();
|
|
356
|
+
}, opt);
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
applyToPoints: function(fn, opt) {
|
|
360
|
+
|
|
361
|
+
if (!isFunction(fn)) {
|
|
362
|
+
throw new TypeError('dia.Link: applyToPoints expects its first parameter to be a function.');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
var attrs = {};
|
|
366
|
+
|
|
367
|
+
var { source, target } = this.attributes;
|
|
368
|
+
if (!source.id) {
|
|
369
|
+
attrs.source = fn(source);
|
|
370
|
+
}
|
|
371
|
+
if (!target.id) {
|
|
372
|
+
attrs.target = fn(target);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
var vertices = this.vertices();
|
|
376
|
+
if (vertices.length > 0) {
|
|
377
|
+
attrs.vertices = vertices.map(fn);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return this.set(attrs, opt);
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
getSourcePoint: function() {
|
|
384
|
+
var sourceCell = this.getSourceCell();
|
|
385
|
+
if (!sourceCell) return new Point(this.source());
|
|
386
|
+
return sourceCell.getPointFromConnectedLink(this, 'source');
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
getTargetPoint: function() {
|
|
390
|
+
var targetCell = this.getTargetCell();
|
|
391
|
+
if (!targetCell) return new Point(this.target());
|
|
392
|
+
return targetCell.getPointFromConnectedLink(this, 'target');
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
getPointFromConnectedLink: function(/* link, endType */) {
|
|
396
|
+
return this.getPolyline().pointAt(0.5);
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
getPolyline: function() {
|
|
400
|
+
const points = [
|
|
401
|
+
this.getSourcePoint(),
|
|
402
|
+
...this.vertices().map(Point),
|
|
403
|
+
this.getTargetPoint()
|
|
404
|
+
];
|
|
405
|
+
return new Polyline(points);
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
getBBox: function() {
|
|
409
|
+
return this.getPolyline().bbox();
|
|
410
|
+
},
|
|
411
|
+
|
|
412
|
+
reparent: function(opt) {
|
|
413
|
+
|
|
414
|
+
var newParent;
|
|
415
|
+
|
|
416
|
+
if (this.graph) {
|
|
417
|
+
|
|
418
|
+
var source = this.getSourceElement();
|
|
419
|
+
var target = this.getTargetElement();
|
|
420
|
+
var prevParent = this.getParentCell();
|
|
421
|
+
|
|
422
|
+
if (source && target) {
|
|
423
|
+
if (source === target || source.isEmbeddedIn(target)) {
|
|
424
|
+
newParent = target;
|
|
425
|
+
} else if (target.isEmbeddedIn(source)) {
|
|
426
|
+
newParent = source;
|
|
427
|
+
} else {
|
|
428
|
+
newParent = this.graph.getCommonAncestor(source, target);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (prevParent && (!newParent || newParent.id !== prevParent.id)) {
|
|
433
|
+
// Unembed the link if source and target has no common ancestor
|
|
434
|
+
// or common ancestor changed
|
|
435
|
+
prevParent.unembed(this, opt);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (newParent) {
|
|
439
|
+
newParent.embed(this, opt);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return newParent;
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
hasLoop: function(opt) {
|
|
447
|
+
|
|
448
|
+
opt = opt || {};
|
|
449
|
+
|
|
450
|
+
var { source, target } = this.attributes;
|
|
451
|
+
var sourceId = source.id;
|
|
452
|
+
var targetId = target.id;
|
|
453
|
+
|
|
454
|
+
if (!sourceId || !targetId) {
|
|
455
|
+
// Link "pinned" to the paper does not have a loop.
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
var loop = sourceId === targetId;
|
|
460
|
+
|
|
461
|
+
// Note that there in the deep mode a link can have a loop,
|
|
462
|
+
// even if it connects only a parent and its embed.
|
|
463
|
+
// A loop "target equals source" is valid in both shallow and deep mode.
|
|
464
|
+
if (!loop && opt.deep && this.graph) {
|
|
465
|
+
|
|
466
|
+
var sourceElement = this.getSourceCell();
|
|
467
|
+
var targetElement = this.getTargetCell();
|
|
468
|
+
|
|
469
|
+
loop = sourceElement.isEmbeddedIn(targetElement) || targetElement.isEmbeddedIn(sourceElement);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return loop;
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
// unlike source(), this method returns null if source is a point
|
|
476
|
+
getSourceCell: function() {
|
|
477
|
+
|
|
478
|
+
const { graph, attributes } = this;
|
|
479
|
+
var source = attributes.source;
|
|
480
|
+
return (source && source.id && graph && graph.getCell(source.id)) || null;
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
getSourceElement: function() {
|
|
484
|
+
var cell = this;
|
|
485
|
+
var visited = {};
|
|
486
|
+
do {
|
|
487
|
+
if (visited[cell.id]) return null;
|
|
488
|
+
visited[cell.id] = true;
|
|
489
|
+
cell = cell.getSourceCell();
|
|
490
|
+
} while (cell && cell.isLink());
|
|
491
|
+
return cell;
|
|
492
|
+
},
|
|
493
|
+
|
|
494
|
+
// unlike target(), this method returns null if target is a point
|
|
495
|
+
getTargetCell: function() {
|
|
496
|
+
|
|
497
|
+
const { graph, attributes } = this;
|
|
498
|
+
var target = attributes.target;
|
|
499
|
+
return (target && target.id && graph && graph.getCell(target.id)) || null;
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
getTargetElement: function() {
|
|
503
|
+
var cell = this;
|
|
504
|
+
var visited = {};
|
|
505
|
+
do {
|
|
506
|
+
if (visited[cell.id]) return null;
|
|
507
|
+
visited[cell.id] = true;
|
|
508
|
+
cell = cell.getTargetCell();
|
|
509
|
+
} while (cell && cell.isLink());
|
|
510
|
+
return cell;
|
|
511
|
+
},
|
|
512
|
+
|
|
513
|
+
// Returns the common ancestor for the source element,
|
|
514
|
+
// target element and the link itself.
|
|
515
|
+
getRelationshipAncestor: function() {
|
|
516
|
+
|
|
517
|
+
var connectionAncestor;
|
|
518
|
+
|
|
519
|
+
if (this.graph) {
|
|
520
|
+
|
|
521
|
+
var cells = [
|
|
522
|
+
this,
|
|
523
|
+
this.getSourceElement(), // null if source is a point
|
|
524
|
+
this.getTargetElement() // null if target is a point
|
|
525
|
+
].filter(function(item) {
|
|
526
|
+
return !!item;
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
connectionAncestor = this.graph.getCommonAncestor.apply(this.graph, cells);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return connectionAncestor || null;
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
// Is source, target and the link itself embedded in a given cell?
|
|
536
|
+
isRelationshipEmbeddedIn: function(cell) {
|
|
537
|
+
|
|
538
|
+
var cellId = (isString(cell) || isNumber(cell)) ? cell : cell.id;
|
|
539
|
+
var ancestor = this.getRelationshipAncestor();
|
|
540
|
+
|
|
541
|
+
return !!ancestor && (ancestor.id === cellId || ancestor.isEmbeddedIn(cellId));
|
|
542
|
+
},
|
|
543
|
+
|
|
544
|
+
// Get resolved default label.
|
|
545
|
+
_getDefaultLabel: function() {
|
|
546
|
+
|
|
547
|
+
var defaultLabel = this.get('defaultLabel') || this.defaultLabel || {};
|
|
548
|
+
|
|
549
|
+
var label = {};
|
|
550
|
+
label.markup = defaultLabel.markup || this.get('labelMarkup') || this.labelMarkup;
|
|
551
|
+
label.position = defaultLabel.position;
|
|
552
|
+
label.attrs = defaultLabel.attrs;
|
|
553
|
+
label.size = defaultLabel.size;
|
|
554
|
+
|
|
555
|
+
return label;
|
|
556
|
+
}
|
|
557
|
+
}, {
|
|
558
|
+
|
|
559
|
+
endsEqual: function(a, b) {
|
|
560
|
+
|
|
561
|
+
var portsEqual = a.port === b.port || !a.port && !b.port;
|
|
562
|
+
return a.id === b.id && portsEqual;
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|