@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.
Files changed (139) hide show
  1. package/LICENSE +376 -0
  2. package/README.md +49 -0
  3. package/dist/geometry.js +6486 -0
  4. package/dist/geometry.min.js +8 -0
  5. package/dist/joint.d.ts +5536 -0
  6. package/dist/joint.js +39629 -0
  7. package/dist/joint.min.js +8 -0
  8. package/dist/joint.nowrap.js +39626 -0
  9. package/dist/joint.nowrap.min.js +8 -0
  10. package/dist/vectorizer.js +9135 -0
  11. package/dist/vectorizer.min.js +8 -0
  12. package/dist/version.mjs +3 -0
  13. package/index.js +3 -0
  14. package/joint.mjs +27 -0
  15. package/package.json +192 -0
  16. package/src/V/annotation.mjs +0 -0
  17. package/src/V/index.mjs +2642 -0
  18. package/src/anchors/index.mjs +123 -0
  19. package/src/config/index.mjs +12 -0
  20. package/src/connectionPoints/index.mjs +202 -0
  21. package/src/connectionStrategies/index.mjs +73 -0
  22. package/src/connectors/curve.mjs +553 -0
  23. package/src/connectors/index.mjs +6 -0
  24. package/src/connectors/jumpover.mjs +452 -0
  25. package/src/connectors/normal.mjs +12 -0
  26. package/src/connectors/rounded.mjs +17 -0
  27. package/src/connectors/smooth.mjs +44 -0
  28. package/src/connectors/straight.mjs +110 -0
  29. package/src/dia/Cell.mjs +945 -0
  30. package/src/dia/CellView.mjs +1316 -0
  31. package/src/dia/Element.mjs +519 -0
  32. package/src/dia/ElementView.mjs +859 -0
  33. package/src/dia/Graph.mjs +1112 -0
  34. package/src/dia/HighlighterView.mjs +319 -0
  35. package/src/dia/Link.mjs +565 -0
  36. package/src/dia/LinkView.mjs +2207 -0
  37. package/src/dia/Paper.mjs +3171 -0
  38. package/src/dia/PaperLayer.mjs +75 -0
  39. package/src/dia/ToolView.mjs +69 -0
  40. package/src/dia/ToolsView.mjs +128 -0
  41. package/src/dia/attributes/calc.mjs +128 -0
  42. package/src/dia/attributes/connection.mjs +75 -0
  43. package/src/dia/attributes/defs.mjs +76 -0
  44. package/src/dia/attributes/eval.mjs +64 -0
  45. package/src/dia/attributes/index.mjs +69 -0
  46. package/src/dia/attributes/legacy.mjs +148 -0
  47. package/src/dia/attributes/offset.mjs +53 -0
  48. package/src/dia/attributes/props.mjs +30 -0
  49. package/src/dia/attributes/shape.mjs +92 -0
  50. package/src/dia/attributes/text.mjs +180 -0
  51. package/src/dia/index.mjs +13 -0
  52. package/src/dia/layers/GridLayer.mjs +176 -0
  53. package/src/dia/ports.mjs +874 -0
  54. package/src/elementTools/Control.mjs +153 -0
  55. package/src/elementTools/HoverConnect.mjs +37 -0
  56. package/src/elementTools/index.mjs +5 -0
  57. package/src/env/index.mjs +43 -0
  58. package/src/g/bezier.mjs +175 -0
  59. package/src/g/curve.mjs +956 -0
  60. package/src/g/ellipse.mjs +245 -0
  61. package/src/g/extend.mjs +64 -0
  62. package/src/g/geometry.helpers.mjs +58 -0
  63. package/src/g/index.mjs +17 -0
  64. package/src/g/intersection.mjs +511 -0
  65. package/src/g/line.bearing.mjs +30 -0
  66. package/src/g/line.length.mjs +5 -0
  67. package/src/g/line.mjs +356 -0
  68. package/src/g/line.squaredLength.mjs +10 -0
  69. package/src/g/path.mjs +2260 -0
  70. package/src/g/point.mjs +375 -0
  71. package/src/g/points.mjs +247 -0
  72. package/src/g/polygon.mjs +51 -0
  73. package/src/g/polyline.mjs +523 -0
  74. package/src/g/rect.mjs +556 -0
  75. package/src/g/types.mjs +10 -0
  76. package/src/highlighters/addClass.mjs +27 -0
  77. package/src/highlighters/index.mjs +5 -0
  78. package/src/highlighters/list.mjs +111 -0
  79. package/src/highlighters/mask.mjs +220 -0
  80. package/src/highlighters/opacity.mjs +17 -0
  81. package/src/highlighters/stroke.mjs +100 -0
  82. package/src/layout/index.mjs +4 -0
  83. package/src/layout/ports/port.mjs +188 -0
  84. package/src/layout/ports/portLabel.mjs +224 -0
  85. package/src/linkAnchors/index.mjs +76 -0
  86. package/src/linkTools/Anchor.mjs +235 -0
  87. package/src/linkTools/Arrowhead.mjs +103 -0
  88. package/src/linkTools/Boundary.mjs +48 -0
  89. package/src/linkTools/Button.mjs +121 -0
  90. package/src/linkTools/Connect.mjs +85 -0
  91. package/src/linkTools/HoverConnect.mjs +161 -0
  92. package/src/linkTools/Segments.mjs +393 -0
  93. package/src/linkTools/Vertices.mjs +253 -0
  94. package/src/linkTools/helpers.mjs +33 -0
  95. package/src/linkTools/index.mjs +8 -0
  96. package/src/mvc/Collection.mjs +560 -0
  97. package/src/mvc/Data.mjs +46 -0
  98. package/src/mvc/Dom/Dom.mjs +587 -0
  99. package/src/mvc/Dom/Event.mjs +130 -0
  100. package/src/mvc/Dom/animations.mjs +122 -0
  101. package/src/mvc/Dom/events.mjs +69 -0
  102. package/src/mvc/Dom/index.mjs +13 -0
  103. package/src/mvc/Dom/methods.mjs +392 -0
  104. package/src/mvc/Dom/props.mjs +77 -0
  105. package/src/mvc/Dom/vars.mjs +5 -0
  106. package/src/mvc/Events.mjs +337 -0
  107. package/src/mvc/Listener.mjs +33 -0
  108. package/src/mvc/Model.mjs +239 -0
  109. package/src/mvc/View.mjs +323 -0
  110. package/src/mvc/ViewBase.mjs +182 -0
  111. package/src/mvc/index.mjs +9 -0
  112. package/src/mvc/mvcUtils.mjs +90 -0
  113. package/src/polyfills/array.js +4 -0
  114. package/src/polyfills/base64.js +68 -0
  115. package/src/polyfills/index.mjs +5 -0
  116. package/src/polyfills/number.js +3 -0
  117. package/src/polyfills/string.js +3 -0
  118. package/src/polyfills/typedArray.js +47 -0
  119. package/src/routers/index.mjs +6 -0
  120. package/src/routers/manhattan.mjs +856 -0
  121. package/src/routers/metro.mjs +91 -0
  122. package/src/routers/normal.mjs +6 -0
  123. package/src/routers/oneSide.mjs +60 -0
  124. package/src/routers/orthogonal.mjs +323 -0
  125. package/src/routers/rightAngle.mjs +1056 -0
  126. package/src/shapes/index.mjs +3 -0
  127. package/src/shapes/standard.mjs +755 -0
  128. package/src/util/cloneCells.mjs +67 -0
  129. package/src/util/getRectPoint.mjs +65 -0
  130. package/src/util/index.mjs +5 -0
  131. package/src/util/svgTagTemplate.mjs +110 -0
  132. package/src/util/util.mjs +1754 -0
  133. package/src/util/utilHelpers.mjs +2402 -0
  134. package/src/util/wrappers.mjs +56 -0
  135. package/types/geometry.d.ts +815 -0
  136. package/types/index.d.ts +53 -0
  137. package/types/joint.d.ts +4391 -0
  138. package/types/joint.head.d.ts +12 -0
  139. package/types/vectorizer.d.ts +327 -0
package/src/g/rect.mjs ADDED
@@ -0,0 +1,556 @@
1
+ import { toRad } from './geometry.helpers.mjs';
2
+ import { Line } from './line.mjs';
3
+ import { Point } from './point.mjs';
4
+ import { Ellipse } from './ellipse.mjs';
5
+ import { types } from './types.mjs';
6
+
7
+ const {
8
+ abs,
9
+ cos,
10
+ sin,
11
+ min,
12
+ max,
13
+ round,
14
+ pow
15
+ } = Math;
16
+
17
+ export const Rect = function(x, y, w, h) {
18
+
19
+ if (!(this instanceof Rect)) {
20
+ return new Rect(x, y, w, h);
21
+ }
22
+
23
+ if ((Object(x) === x)) {
24
+ y = x.y;
25
+ w = x.width;
26
+ h = x.height;
27
+ x = x.x;
28
+ }
29
+
30
+ this.x = x === undefined ? 0 : x;
31
+ this.y = y === undefined ? 0 : y;
32
+ this.width = w === undefined ? 0 : w;
33
+ this.height = h === undefined ? 0 : h;
34
+ };
35
+
36
+ Rect.fromEllipse = function(e) {
37
+
38
+ e = new Ellipse(e);
39
+ return new Rect(e.x - e.a, e.y - e.b, 2 * e.a, 2 * e.b);
40
+ };
41
+
42
+ Rect.fromPointUnion = function(...points) {
43
+
44
+ if (points.length === 0) return null;
45
+
46
+ const p = new Point();
47
+ let minX, minY, maxX, maxY;
48
+ minX = minY = Infinity;
49
+ maxX = maxY = -Infinity;
50
+
51
+ for (let i = 0; i < points.length; i++) {
52
+ p.update(points[i]);
53
+ const x = p.x;
54
+ const y = p.y;
55
+
56
+ if (x < minX) minX = x;
57
+ if (x > maxX) maxX = x;
58
+ if (y < minY) minY = y;
59
+ if (y > maxY) maxY = y;
60
+ }
61
+
62
+ return new Rect(minX, minY, maxX - minX, maxY - minY);
63
+ };
64
+
65
+ Rect.fromRectUnion = function(...rects) {
66
+
67
+ if (rects.length === 0) return null;
68
+
69
+ const r = new Rect();
70
+ let minX, minY, maxX, maxY;
71
+ minX = minY = Infinity;
72
+ maxX = maxY = -Infinity;
73
+
74
+ for (let i = 0; i < rects.length; i++) {
75
+ r.update(rects[i]);
76
+ const x = r.x;
77
+ const y = r.y;
78
+ const mX = x + r.width;
79
+ const mY = y + r.height;
80
+
81
+ if (x < minX) minX = x;
82
+ if (mX > maxX) maxX = mX;
83
+ if (y < minY) minY = y;
84
+ if (mY > maxY) maxY = mY;
85
+ }
86
+
87
+ return new Rect(minX, minY, maxX - minX, maxY - minY);
88
+ };
89
+
90
+ Rect.prototype = {
91
+
92
+ type: types.Rect,
93
+
94
+ // Find my bounding box when I'm rotated with the center of rotation in the center of me.
95
+ // @return r {rectangle} representing a bounding box
96
+ bbox: function(angle) {
97
+ return this.clone().rotateAroundCenter(angle);
98
+ },
99
+
100
+ rotateAroundCenter: function(angle) {
101
+ if (!angle) return this;
102
+ const { width, height } = this;
103
+ const theta = toRad(angle);
104
+ const st = abs(sin(theta));
105
+ const ct = abs(cos(theta));
106
+ const w = width * ct + height * st;
107
+ const h = width * st + height * ct;
108
+ this.x += (width - w) / 2;
109
+ this.y += (height - h) / 2;
110
+ this.width = w;
111
+ this.height = h;
112
+ return this;
113
+ },
114
+
115
+ bottomLeft: function() {
116
+
117
+ return new Point(this.x, this.y + this.height);
118
+ },
119
+
120
+ bottomLine: function() {
121
+
122
+ return new Line(this.bottomLeft(), this.bottomRight());
123
+ },
124
+
125
+ bottomMiddle: function() {
126
+
127
+ return new Point(this.x + this.width / 2, this.y + this.height);
128
+ },
129
+
130
+ center: function() {
131
+
132
+ return new Point(this.x + this.width / 2, this.y + this.height / 2);
133
+ },
134
+
135
+ clone: function() {
136
+
137
+ return new Rect(this);
138
+ },
139
+
140
+ // @return {bool} true if point p is inside me.
141
+ containsPoint: function(p) {
142
+
143
+ if (!(p instanceof Point)) {
144
+ p = new Point(p);
145
+ }
146
+ return p.x >= this.x && p.x <= this.x + this.width && p.y >= this.y && p.y <= this.y + this.height;
147
+ },
148
+
149
+ // @return {bool} true if rectangle `r` is inside me.
150
+ containsRect: function(r) {
151
+
152
+ var r0 = new Rect(this).normalize();
153
+ var r1 = new Rect(r).normalize();
154
+ var w0 = r0.width;
155
+ var h0 = r0.height;
156
+ var w1 = r1.width;
157
+ var h1 = r1.height;
158
+
159
+ if (!w0 || !h0 || !w1 || !h1) {
160
+ // At least one of the dimensions is 0
161
+ return false;
162
+ }
163
+
164
+ var x0 = r0.x;
165
+ var y0 = r0.y;
166
+ var x1 = r1.x;
167
+ var y1 = r1.y;
168
+
169
+ w1 += x1;
170
+ w0 += x0;
171
+ h1 += y1;
172
+ h0 += y0;
173
+
174
+ return x0 <= x1 && w1 <= w0 && y0 <= y1 && h1 <= h0;
175
+ },
176
+
177
+ corner: function() {
178
+
179
+ return new Point(this.x + this.width, this.y + this.height);
180
+ },
181
+
182
+ // @return {boolean} true if rectangles are equal.
183
+ equals: function(r) {
184
+
185
+ var mr = (new Rect(this)).normalize();
186
+ var nr = (new Rect(r)).normalize();
187
+ return mr.x === nr.x && mr.y === nr.y && mr.width === nr.width && mr.height === nr.height;
188
+ },
189
+
190
+ // inflate by dx and dy, recompute origin [x, y]
191
+ // @param dx {delta_x} representing additional size to x
192
+ // @param dy {delta_y} representing additional size to y -
193
+ // dy param is not required -> in that case y is sized by dx
194
+ inflate: function(dx, dy) {
195
+
196
+ if (dx === undefined) {
197
+ dx = 0;
198
+ }
199
+
200
+ if (dy === undefined) {
201
+ dy = dx;
202
+ }
203
+
204
+ this.x -= dx;
205
+ this.y -= dy;
206
+ this.width += 2 * dx;
207
+ this.height += 2 * dy;
208
+
209
+ return this;
210
+ },
211
+
212
+ // @return {rect} if rectangles intersect, {null} if not.
213
+ intersect: function(r) {
214
+
215
+ var myOrigin = this.origin();
216
+ var myCorner = this.corner();
217
+ var rOrigin = r.origin();
218
+ var rCorner = r.corner();
219
+
220
+ // No intersection found
221
+ if (rCorner.x <= myOrigin.x ||
222
+ rCorner.y <= myOrigin.y ||
223
+ rOrigin.x >= myCorner.x ||
224
+ rOrigin.y >= myCorner.y) return null;
225
+
226
+ var x = max(myOrigin.x, rOrigin.x);
227
+ var y = max(myOrigin.y, rOrigin.y);
228
+
229
+ return new Rect(x, y, min(myCorner.x, rCorner.x) - x, min(myCorner.y, rCorner.y) - y);
230
+ },
231
+
232
+ intersectionWithLine: function(line) {
233
+
234
+ var r = this;
235
+ var rectLines = [r.topLine(), r.rightLine(), r.bottomLine(), r.leftLine()];
236
+ var points = [];
237
+ var dedupeArr = [];
238
+ var pt, i;
239
+
240
+ var n = rectLines.length;
241
+ for (i = 0; i < n; i++) {
242
+
243
+ pt = line.intersect(rectLines[i]);
244
+ if (pt !== null && dedupeArr.indexOf(pt.toString()) < 0) {
245
+ points.push(pt);
246
+ dedupeArr.push(pt.toString());
247
+ }
248
+ }
249
+
250
+ return points.length > 0 ? points : null;
251
+ },
252
+
253
+ // Find point on my boundary where line starting
254
+ // from my center ending in point p intersects me.
255
+ // @param {number} angle If angle is specified, intersection with rotated rectangle is computed.
256
+ intersectionWithLineFromCenterToPoint: function(p, angle) {
257
+
258
+ p = new Point(p);
259
+ var center = new Point(this.x + this.width / 2, this.y + this.height / 2);
260
+ var result;
261
+
262
+ if (angle) p.rotate(center, angle);
263
+
264
+ // (clockwise, starting from the top side)
265
+ var sides = [
266
+ this.topLine(),
267
+ this.rightLine(),
268
+ this.bottomLine(),
269
+ this.leftLine()
270
+ ];
271
+ var connector = new Line(center, p);
272
+
273
+ for (var i = sides.length - 1; i >= 0; --i) {
274
+ var intersection = sides[i].intersection(connector);
275
+ if (intersection !== null) {
276
+ result = intersection;
277
+ break;
278
+ }
279
+ }
280
+ if (result && angle) result.rotate(center, -angle);
281
+ return result;
282
+ },
283
+
284
+ leftLine: function() {
285
+
286
+ return new Line(this.topLeft(), this.bottomLeft());
287
+ },
288
+
289
+ leftMiddle: function() {
290
+
291
+ return new Point(this.x, this.y + this.height / 2);
292
+ },
293
+
294
+ maxRectScaleToFit: function(rect, origin) {
295
+
296
+ rect = new Rect(rect);
297
+ origin || (origin = rect.center());
298
+
299
+ var sx1, sx2, sx3, sx4, sy1, sy2, sy3, sy4;
300
+ var ox = origin.x;
301
+ var oy = origin.y;
302
+
303
+ // Here we find the maximal possible scale for all corner points (for x and y axis) of the rectangle,
304
+ // so when the scale is applied the point is still inside the rectangle.
305
+
306
+ sx1 = sx2 = sx3 = sx4 = sy1 = sy2 = sy3 = sy4 = Infinity;
307
+
308
+ // Top Left
309
+ var p1 = rect.topLeft();
310
+ if (p1.x < ox) {
311
+ sx1 = (this.x - ox) / (p1.x - ox);
312
+ }
313
+ if (p1.y < oy) {
314
+ sy1 = (this.y - oy) / (p1.y - oy);
315
+ }
316
+ // Bottom Right
317
+ var p2 = rect.bottomRight();
318
+ if (p2.x > ox) {
319
+ sx2 = (this.x + this.width - ox) / (p2.x - ox);
320
+ }
321
+ if (p2.y > oy) {
322
+ sy2 = (this.y + this.height - oy) / (p2.y - oy);
323
+ }
324
+ // Top Right
325
+ var p3 = rect.topRight();
326
+ if (p3.x > ox) {
327
+ sx3 = (this.x + this.width - ox) / (p3.x - ox);
328
+ }
329
+ if (p3.y < oy) {
330
+ sy3 = (this.y - oy) / (p3.y - oy);
331
+ }
332
+ // Bottom Left
333
+ var p4 = rect.bottomLeft();
334
+ if (p4.x < ox) {
335
+ sx4 = (this.x - ox) / (p4.x - ox);
336
+ }
337
+ if (p4.y > oy) {
338
+ sy4 = (this.y + this.height - oy) / (p4.y - oy);
339
+ }
340
+
341
+ return {
342
+ sx: min(sx1, sx2, sx3, sx4),
343
+ sy: min(sy1, sy2, sy3, sy4)
344
+ };
345
+ },
346
+
347
+ maxRectUniformScaleToFit: function(rect, origin) {
348
+
349
+ var scale = this.maxRectScaleToFit(rect, origin);
350
+ return min(scale.sx, scale.sy);
351
+ },
352
+
353
+ // Move and expand me.
354
+ // @param r {rectangle} representing deltas
355
+ moveAndExpand: function(r) {
356
+
357
+ this.x += r.x || 0;
358
+ this.y += r.y || 0;
359
+ this.width += r.width || 0;
360
+ this.height += r.height || 0;
361
+ return this;
362
+ },
363
+
364
+ // Normalize the rectangle; i.e., make it so that it has a non-negative width and height.
365
+ // If width < 0 the function swaps the left and right corners,
366
+ // and it swaps the top and bottom corners if height < 0
367
+ // like in http://qt-project.org/doc/qt-4.8/qrectf.html#normalized
368
+ normalize: function() {
369
+
370
+ var newx = this.x;
371
+ var newy = this.y;
372
+ var newwidth = this.width;
373
+ var newheight = this.height;
374
+ if (this.width < 0) {
375
+ newx = this.x + this.width;
376
+ newwidth = -this.width;
377
+ }
378
+ if (this.height < 0) {
379
+ newy = this.y + this.height;
380
+ newheight = -this.height;
381
+ }
382
+ this.x = newx;
383
+ this.y = newy;
384
+ this.width = newwidth;
385
+ this.height = newheight;
386
+ return this;
387
+ },
388
+
389
+ // Offset me by the specified amount.
390
+ offset: function(dx, dy) {
391
+
392
+ // pretend that this is a point and call offset()
393
+ // rewrites x and y according to dx and dy
394
+ return Point.prototype.offset.call(this, dx, dy);
395
+ },
396
+
397
+ origin: function() {
398
+
399
+ return new Point(this.x, this.y);
400
+ },
401
+
402
+ // @return {point} a point on my boundary nearest to the given point.
403
+ // @see Squeak Smalltalk, Rectangle>>pointNearestTo:
404
+ pointNearestToPoint: function(point) {
405
+
406
+ point = new Point(point);
407
+ if (this.containsPoint(point)) {
408
+ var side = this.sideNearestToPoint(point);
409
+ switch (side) {
410
+ case 'right':
411
+ return new Point(this.x + this.width, point.y);
412
+ case 'left':
413
+ return new Point(this.x, point.y);
414
+ case 'bottom':
415
+ return new Point(point.x, this.y + this.height);
416
+ case 'top':
417
+ return new Point(point.x, this.y);
418
+ }
419
+ }
420
+ return point.adhereToRect(this);
421
+ },
422
+
423
+ rightLine: function() {
424
+
425
+ return new Line(this.topRight(), this.bottomRight());
426
+ },
427
+
428
+ rightMiddle: function() {
429
+
430
+ return new Point(this.x + this.width, this.y + this.height / 2);
431
+ },
432
+
433
+ round: function(precision) {
434
+
435
+ let f = 1; // case 0
436
+ if (precision) {
437
+ switch (precision) {
438
+ case 1: f = 10; break;
439
+ case 2: f = 100; break;
440
+ case 3: f = 1000; break;
441
+ default: f = pow(10, precision); break;
442
+ }
443
+ }
444
+
445
+ this.x = round(this.x * f) / f;
446
+ this.y = round(this.y * f) / f;
447
+ this.width = round(this.width * f) / f;
448
+ this.height = round(this.height * f) / f;
449
+ return this;
450
+ },
451
+
452
+ // Scale rectangle with origin.
453
+ scale: function(sx, sy, origin) {
454
+
455
+ origin = this.origin().scale(sx, sy, origin);
456
+ this.x = origin.x;
457
+ this.y = origin.y;
458
+ this.width *= sx;
459
+ this.height *= sy;
460
+ return this;
461
+ },
462
+
463
+ // @return {string} (left|right|top|bottom) side which is nearest to point
464
+ // @see Squeak Smalltalk, Rectangle>>sideNearestTo:
465
+ sideNearestToPoint: function(point) {
466
+
467
+ point = new Point(point);
468
+ var distToLeft = point.x - this.x;
469
+ var distToRight = (this.x + this.width) - point.x;
470
+ var distToTop = point.y - this.y;
471
+ var distToBottom = (this.y + this.height) - point.y;
472
+ var closest = distToLeft;
473
+ var side = 'left';
474
+
475
+ if (distToRight < closest) {
476
+ closest = distToRight;
477
+ side = 'right';
478
+ }
479
+ if (distToTop < closest) {
480
+ closest = distToTop;
481
+ side = 'top';
482
+ }
483
+ if (distToBottom < closest) {
484
+ // closest = distToBottom;
485
+ side = 'bottom';
486
+ }
487
+ return side;
488
+ },
489
+
490
+ snapToGrid: function(gx, gy) {
491
+
492
+ var origin = this.origin().snapToGrid(gx, gy);
493
+ var corner = this.corner().snapToGrid(gx, gy);
494
+ this.x = origin.x;
495
+ this.y = origin.y;
496
+ this.width = corner.x - origin.x;
497
+ this.height = corner.y - origin.y;
498
+ return this;
499
+ },
500
+
501
+ toJSON: function() {
502
+
503
+ return { x: this.x, y: this.y, width: this.width, height: this.height };
504
+ },
505
+
506
+ topLine: function() {
507
+
508
+ return new Line(this.topLeft(), this.topRight());
509
+ },
510
+
511
+ topMiddle: function() {
512
+
513
+ return new Point(this.x + this.width / 2, this.y);
514
+ },
515
+
516
+ topRight: function() {
517
+
518
+ return new Point(this.x + this.width, this.y);
519
+ },
520
+
521
+ toString: function() {
522
+
523
+ return this.origin().toString() + ' ' + this.corner().toString();
524
+ },
525
+
526
+ // @return {rect} representing the union of both rectangles.
527
+ union: function(rect) {
528
+
529
+ return Rect.fromRectUnion(this, rect);
530
+ },
531
+
532
+ update: function(x, y, w, h) {
533
+
534
+ if ((Object(x) === x)) {
535
+ y = x.y;
536
+ w = x.width;
537
+ h = x.height;
538
+ x = x.x;
539
+ }
540
+
541
+ this.x = x || 0;
542
+ this.y = y || 0;
543
+ this.width = w || 0;
544
+ this.height = h || 0;
545
+ return this;
546
+ }
547
+ };
548
+
549
+ Rect.prototype.bottomRight = Rect.prototype.corner;
550
+
551
+ Rect.prototype.topLeft = Rect.prototype.origin;
552
+
553
+ Rect.prototype.translate = Rect.prototype.offset;
554
+
555
+ // For backwards compatibility:
556
+ export const rect = Rect;
@@ -0,0 +1,10 @@
1
+ export const types = {
2
+ Point: 1,
3
+ Line: 2,
4
+ Ellipse: 3,
5
+ Rect: 4,
6
+ Polyline: 5,
7
+ Polygon: 6,
8
+ Curve: 7,
9
+ Path: 8
10
+ };
@@ -0,0 +1,27 @@
1
+ import * as util from '../util/index.mjs';
2
+ import V from '../V/index.mjs';
3
+ import { HighlighterView } from '../dia/HighlighterView.mjs';
4
+
5
+ const className = util.addClassNamePrefix('highlighted');
6
+
7
+ export const addClass = HighlighterView.extend({
8
+
9
+ UPDATABLE: false,
10
+ MOUNTABLE: false,
11
+
12
+ options: {
13
+ className
14
+ },
15
+
16
+ highlight: function(_cellView, node) {
17
+ V(node).addClass(this.options.className);
18
+ },
19
+
20
+ unhighlight: function(_cellView, node) {
21
+ V(node).removeClass(this.options.className);
22
+ }
23
+
24
+ }, {
25
+ // Backwards Compatibility
26
+ className
27
+ });
@@ -0,0 +1,5 @@
1
+ export * from './stroke.mjs';
2
+ export * from './mask.mjs';
3
+ export * from './opacity.mjs';
4
+ export * from './addClass.mjs';
5
+ export * from './list.mjs';
@@ -0,0 +1,111 @@
1
+ import { Rect } from '../g/index.mjs';
2
+ import { HighlighterView } from '../dia/HighlighterView.mjs';
3
+ import {
4
+ normalizeSides,
5
+ isEqual,
6
+ } from '../util/index.mjs';
7
+ import {
8
+ Positions,
9
+ getRectPoint,
10
+ } from '../util/getRectPoint.mjs';
11
+
12
+ const Directions = {
13
+ ROW: 'row',
14
+ COLUMN: 'column'
15
+ };
16
+
17
+ export const list = HighlighterView.extend({
18
+
19
+ tagName: 'g',
20
+ MOUNTABLE: true,
21
+ UPDATE_ATTRIBUTES: function() {
22
+ return [this.options.attribute];
23
+ },
24
+
25
+ _prevItems: null,
26
+
27
+ highlight(elementView, node) {
28
+ const element = elementView.model;
29
+ const { attribute, size = 20, gap = 5, direction = Directions.ROW } = this.options;
30
+ if (!attribute) throw new Error('List: attribute is required');
31
+ const normalizedSize = (typeof size === 'number') ? { width: size, height: size } : size;
32
+ const isRowDirection = (direction === Directions.ROW);
33
+ const itemWidth = isRowDirection ? normalizedSize.width : normalizedSize.height;
34
+ let items = element.get(attribute);
35
+ if (!Array.isArray(items)) items = [];
36
+ const prevItems = this._prevItems || [];
37
+ const comparison = items.map((item, index) => isEqual(prevItems[index], items[index]));
38
+ if (prevItems.length !== items.length || comparison.some(unchanged => !unchanged)) {
39
+ const prevEls = this.vel.children();
40
+ const itemsEls = items.map((item, index) => {
41
+ const prevEl = (index in prevEls) ? prevEls[index].node : null;
42
+ if (comparison[index]) return prevEl;
43
+ const itemEl = this.createListItem(item, normalizedSize, prevEl);
44
+ if (!itemEl) return null;
45
+ if (!(itemEl instanceof SVGElement)) throw new Error('List: item must be an SVGElement');
46
+ itemEl.dataset.index = index;
47
+ itemEl.dataset.attribute = attribute;
48
+ const offset = index * (itemWidth + gap);
49
+ itemEl.setAttribute('transform', (isRowDirection)
50
+ ? `translate(${offset}, 0)`
51
+ : `translate(0, ${offset})`
52
+ );
53
+ return itemEl;
54
+ });
55
+ this.vel.empty().append(itemsEls);
56
+ this._prevItems = items;
57
+ }
58
+ const itemsCount = items.length;
59
+ const length = (itemsCount === 0)
60
+ ? 0
61
+ : (itemsCount * itemWidth + (itemsCount - 1) * gap);
62
+ const listSize = (isRowDirection)
63
+ ? { width: length, height: normalizedSize.height }
64
+ : { width: normalizedSize.width, height: length };
65
+
66
+ this.position(element, listSize);
67
+ },
68
+
69
+ position(element, listSize) {
70
+ const { vel, options } = this;
71
+ const { margin = 5, position = 'top-left' } = options;
72
+ const { width, height } = element.size();
73
+ const { left, right, top, bottom } = normalizeSides(margin);
74
+ const bbox = new Rect(left, top, width - (left + right), height - (top + bottom));
75
+ let { x, y } = getRectPoint(bbox, position);
76
+ // x
77
+ switch (position) {
78
+ case Positions.CENTER:
79
+ case Positions.TOP:
80
+ case Positions.BOTTOM: {
81
+ x -= listSize.width / 2;
82
+ break;
83
+ }
84
+ case Positions.RIGHT:
85
+ case Positions.BOTTOM_RIGHT:
86
+ case Positions.TOP_RIGHT: {
87
+ x -= listSize.width;
88
+ break;
89
+ }
90
+ }
91
+ // y
92
+ switch (position) {
93
+ case Positions.CENTER:
94
+ case Positions.RIGHT:
95
+ case Positions.LEFT: {
96
+ y -= listSize.height / 2;
97
+ break;
98
+ }
99
+ case Positions.BOTTOM:
100
+ case Positions.BOTTOM_RIGHT:
101
+ case Positions.BOTTOM_LEFT: {
102
+ y -= listSize.height;
103
+ break;
104
+ }
105
+ }
106
+ vel.attr('transform', `translate(${x}, ${y})`);
107
+ }
108
+ }, {
109
+ Directions,
110
+ Positions
111
+ });