@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
@@ -0,0 +1,224 @@
1
+ import * as g from '../../g/index.mjs';
2
+ import * as util from '../../util/index.mjs';
3
+
4
+ function labelAttributes(opt1, opt2) {
5
+
6
+ // use value from `opt2` if it is missing in `opt1`
7
+ // use value from this object if it is missing in `opt2` as well
8
+ return util.defaultsDeep({}, opt1, opt2, {
9
+ x: 0,
10
+ y: 0,
11
+ angle: 0,
12
+ attrs: {}
13
+ });
14
+ }
15
+
16
+ function getBBoxAngles(elBBox) {
17
+
18
+ var center = elBBox.center();
19
+
20
+ var tl = center.theta(elBBox.origin());
21
+ var bl = center.theta(elBBox.bottomLeft());
22
+ var br = center.theta(elBBox.corner());
23
+ var tr = center.theta(elBBox.topRight());
24
+
25
+ return [tl, tr, br, bl];
26
+ }
27
+
28
+ function outsideLayout(portPosition, elBBox, autoOrient, opt) {
29
+
30
+ opt = util.defaults({}, opt, { offset: 15 });
31
+ var angle = elBBox.center().theta(portPosition);
32
+
33
+ var tx, ty, y, textAnchor;
34
+ var offset = opt.offset;
35
+ var orientAngle = 0;
36
+
37
+ const [topLeftAngle, bottomLeftAngle, bottomRightAngle, topRightAngle] = getBBoxAngles(elBBox);
38
+ if ((angle < bottomLeftAngle) || (angle > bottomRightAngle)) {
39
+ y = '.3em';
40
+ tx = offset;
41
+ ty = 0;
42
+ textAnchor = 'start';
43
+ } else if (angle < topLeftAngle) {
44
+ tx = 0;
45
+ ty = -offset;
46
+ if (autoOrient) {
47
+ orientAngle = -90;
48
+ textAnchor = 'start';
49
+ y = '.3em';
50
+ } else {
51
+ textAnchor = 'middle';
52
+ y = '0';
53
+ }
54
+ } else if (angle < topRightAngle) {
55
+ y = '.3em';
56
+ tx = -offset;
57
+ ty = 0;
58
+ textAnchor = 'end';
59
+ } else {
60
+ tx = 0;
61
+ ty = offset;
62
+ if (autoOrient) {
63
+ orientAngle = 90;
64
+ textAnchor = 'start';
65
+ y = '.3em';
66
+ } else {
67
+ textAnchor = 'middle';
68
+ y = '.6em';
69
+ }
70
+ }
71
+
72
+ var round = Math.round;
73
+ return labelAttributes(opt, {
74
+ x: round(tx),
75
+ y: round(ty),
76
+ angle: orientAngle,
77
+ attrs: { labelText: { y, textAnchor }}
78
+ });
79
+ }
80
+
81
+ function insideLayout(portPosition, elBBox, autoOrient, opt) {
82
+
83
+ opt = util.defaults({}, opt, { offset: 15 });
84
+ var angle = elBBox.center().theta(portPosition);
85
+
86
+ var tx, ty, y, textAnchor;
87
+ var offset = opt.offset;
88
+ var orientAngle = 0;
89
+
90
+ const [topLeftAngle, bottomLeftAngle, bottomRightAngle, topRightAngle] = getBBoxAngles(elBBox);
91
+ if ((angle < bottomLeftAngle) || (angle > bottomRightAngle)) {
92
+ y = '.3em';
93
+ tx = -offset;
94
+ ty = 0;
95
+ textAnchor = 'end';
96
+ } else if (angle < topLeftAngle) {
97
+ tx = 0;
98
+ ty = offset;
99
+ if (autoOrient) {
100
+ orientAngle = 90;
101
+ textAnchor = 'start';
102
+ y = '.3em';
103
+ } else {
104
+ textAnchor = 'middle';
105
+ y = '.6em';
106
+ }
107
+ } else if (angle < topRightAngle) {
108
+ y = '.3em';
109
+ tx = offset;
110
+ ty = 0;
111
+ textAnchor = 'start';
112
+ } else {
113
+ tx = 0;
114
+ ty = -offset;
115
+ if (autoOrient) {
116
+ orientAngle = -90;
117
+ textAnchor = 'start';
118
+ y = '.3em';
119
+ } else {
120
+ textAnchor = 'middle';
121
+ y = '0';
122
+ }
123
+ }
124
+
125
+ var round = Math.round;
126
+ return labelAttributes(opt, {
127
+ x: round(tx),
128
+ y: round(ty),
129
+ angle: orientAngle,
130
+ attrs: { labelText: { y, textAnchor }}
131
+ });
132
+ }
133
+
134
+ function radialLayout(portCenterOffset, autoOrient, opt) {
135
+
136
+ opt = util.defaults({}, opt, { offset: 20 });
137
+
138
+ var origin = g.point(0, 0);
139
+ var angle = -portCenterOffset.theta(origin);
140
+ var orientAngle = angle;
141
+ var offset = portCenterOffset.clone()
142
+ .move(origin, opt.offset)
143
+ .difference(portCenterOffset)
144
+ .round();
145
+
146
+ var y = '.3em';
147
+ var textAnchor;
148
+
149
+ if ((angle + 90) % 180 === 0) {
150
+ textAnchor = autoOrient ? 'end' : 'middle';
151
+ if (!autoOrient && angle === -270) {
152
+ y = '0em';
153
+ }
154
+ } else if (angle > -270 && angle < -90) {
155
+ textAnchor = 'start';
156
+ orientAngle = angle - 180;
157
+ } else {
158
+ textAnchor = 'end';
159
+ }
160
+
161
+ var round = Math.round;
162
+ return labelAttributes(opt, {
163
+ x: round(offset.x),
164
+ y: round(offset.y),
165
+ angle: ((autoOrient) ? orientAngle : 0),
166
+ attrs: { labelText: { y, textAnchor }}
167
+ });
168
+ }
169
+
170
+ export const manual = function(_portPosition, _elBBox, opt) {
171
+ return labelAttributes(opt);
172
+ };
173
+
174
+ export const left = function(portPosition, elBBox, opt) {
175
+ return labelAttributes(opt, {
176
+ x: -15,
177
+ attrs: { labelText: { y: '.3em', textAnchor: 'end' }},
178
+ });
179
+ };
180
+
181
+ export const right = function(portPosition, elBBox, opt) {
182
+ return labelAttributes(opt, {
183
+ x: 15,
184
+ attrs: { labelText: { y: '.3em', textAnchor: 'start' }},
185
+ });
186
+ };
187
+
188
+ export const top = function(portPosition, elBBox, opt) {
189
+ return labelAttributes(opt, {
190
+ y: -15,
191
+ attrs: { labelText: { y: '0', textAnchor: 'middle' }},
192
+ });
193
+ };
194
+
195
+ export const bottom = function(portPosition, elBBox, opt) {
196
+ return labelAttributes(opt, {
197
+ y: 15,
198
+ attrs: { labelText: { y: '.6em', textAnchor: 'middle' }},
199
+ });
200
+ };
201
+
202
+ export const outsideOriented = function(portPosition, elBBox, opt) {
203
+ return outsideLayout(portPosition, elBBox, true, opt);
204
+ };
205
+
206
+ export const outside = function(portPosition, elBBox, opt) {
207
+ return outsideLayout(portPosition, elBBox, false, opt);
208
+ };
209
+
210
+ export const insideOriented = function(portPosition, elBBox, opt) {
211
+ return insideLayout(portPosition, elBBox, true, opt);
212
+ };
213
+
214
+ export const inside = function(portPosition, elBBox, opt) {
215
+ return insideLayout(portPosition, elBBox, false, opt);
216
+ };
217
+
218
+ export const radial = function(portPosition, elBBox, opt) {
219
+ return radialLayout(portPosition.difference(elBBox.center()), false, opt);
220
+ };
221
+
222
+ export const radialOriented = function(portPosition, elBBox, opt) {
223
+ return radialLayout(portPosition.difference(elBBox.center()), true, opt);
224
+ };
@@ -0,0 +1,76 @@
1
+ import { Line, Point } from '../g/index.mjs';
2
+ import { isPercentage } from '../util/index.mjs';
3
+
4
+ function connectionRatio(view, _magnet, _refPoint, opt) {
5
+
6
+ var ratio = ('ratio' in opt) ? opt.ratio : 0.5;
7
+ return view.getPointAtRatio(ratio);
8
+ }
9
+
10
+ function connectionLength(view, _magnet, _refPoint, opt) {
11
+
12
+ var length = ('length' in opt) ? opt.length : 20;
13
+ return view.getPointAtLength(length);
14
+ }
15
+
16
+ function _connectionPerpendicular(view, _magnet, refPoint, opt) {
17
+
18
+ var OFFSET = 1e6;
19
+ var path = view.getConnection();
20
+ var segmentSubdivisions = view.getConnectionSubdivisions();
21
+ var verticalLine = new Line(refPoint.clone().offset(0, OFFSET), refPoint.clone().offset(0, -OFFSET));
22
+ var horizontalLine = new Line(refPoint.clone().offset(OFFSET, 0), refPoint.clone().offset(-OFFSET, 0));
23
+ var verticalIntersections = verticalLine.intersect(path, { segmentSubdivisions: segmentSubdivisions });
24
+ var horizontalIntersections = horizontalLine.intersect(path, { segmentSubdivisions: segmentSubdivisions });
25
+ var intersections = [];
26
+ if (verticalIntersections) Array.prototype.push.apply(intersections, verticalIntersections);
27
+ if (horizontalIntersections) Array.prototype.push.apply(intersections, horizontalIntersections);
28
+ if (intersections.length > 0) return refPoint.chooseClosest(intersections);
29
+ if ('fallbackAt' in opt) {
30
+ return getPointAtLink(view, opt.fallbackAt);
31
+ }
32
+ return connectionClosest(view, _magnet, refPoint, opt);
33
+ }
34
+
35
+ function _connectionClosest(view, _magnet, refPoint, _opt) {
36
+
37
+ var closestPoint = view.getClosestPoint(refPoint);
38
+ if (!closestPoint) return new Point();
39
+ return closestPoint;
40
+ }
41
+
42
+ export function resolveRef(fn) {
43
+ return function(view, magnet, ref, opt) {
44
+ if (ref instanceof Element) {
45
+ var refView = this.paper.findView(ref);
46
+ var refPoint;
47
+ if (refView) {
48
+ if (refView.isNodeConnection(ref)) {
49
+ var distance = ('fixedAt' in opt) ? opt.fixedAt : '50%';
50
+ refPoint = getPointAtLink(refView, distance);
51
+ } else {
52
+ refPoint = refView.getNodeBBox(ref).center();
53
+ }
54
+ } else {
55
+ // Something went wrong
56
+ refPoint = new Point();
57
+ }
58
+ return fn.call(this, view, magnet, refPoint, opt);
59
+ }
60
+ return fn.apply(this, arguments);
61
+ };
62
+ }
63
+
64
+ function getPointAtLink(view, value) {
65
+ var parsedValue = parseFloat(value);
66
+ if (isPercentage(value)) {
67
+ return view.getPointAtRatio(parsedValue / 100);
68
+ } else {
69
+ return view.getPointAtLength(parsedValue);
70
+ }
71
+ }
72
+
73
+ // joint.linkAnchors
74
+ export { connectionRatio, connectionLength };
75
+ export const connectionPerpendicular = resolveRef(_connectionPerpendicular);
76
+ export const connectionClosest = resolveRef(_connectionClosest);
@@ -0,0 +1,235 @@
1
+ import * as g from '../g/index.mjs';
2
+ import * as util from '../util/index.mjs';
3
+ import { ToolView } from '../dia/ToolView.mjs';
4
+ import { getAnchor, snapAnchor } from './helpers.mjs';
5
+
6
+ const Anchor = ToolView.extend({
7
+ tagName: 'g',
8
+ type: null,
9
+ children: [{
10
+ tagName: 'circle',
11
+ selector: 'anchor',
12
+ attributes: {
13
+ 'cursor': 'pointer'
14
+ }
15
+ }, {
16
+ tagName: 'rect',
17
+ selector: 'area',
18
+ attributes: {
19
+ 'pointer-events': 'none',
20
+ 'fill': 'none',
21
+ 'stroke': '#33334F',
22
+ 'stroke-dasharray': '2,4',
23
+ 'rx': 5,
24
+ 'ry': 5
25
+ }
26
+ }],
27
+ events: {
28
+ mousedown: 'onPointerDown',
29
+ touchstart: 'onPointerDown',
30
+ dblclick: 'onPointerDblClick',
31
+ dbltap: 'onPointerDblClick'
32
+ },
33
+ documentEvents: {
34
+ mousemove: 'onPointerMove',
35
+ touchmove: 'onPointerMove',
36
+ mouseup: 'onPointerUp',
37
+ touchend: 'onPointerUp',
38
+ touchcancel: 'onPointerUp'
39
+ },
40
+ options: {
41
+ snap: snapAnchor,
42
+ anchor: getAnchor,
43
+ scale: null,
44
+ resetAnchor: true,
45
+ customAnchorAttributes: {
46
+ 'stroke-width': 4,
47
+ 'stroke': '#33334F',
48
+ 'fill': '#FFFFFF',
49
+ 'r': 5
50
+ },
51
+ defaultAnchorAttributes: {
52
+ 'stroke-width': 2,
53
+ 'stroke': '#FFFFFF',
54
+ 'fill': '#33334F',
55
+ 'r': 6
56
+ },
57
+ areaPadding: 6,
58
+ snapRadius: 10,
59
+ restrictArea: true,
60
+ redundancyRemoval: true
61
+ },
62
+ onRender: function() {
63
+ this.renderChildren();
64
+ this.toggleArea(false);
65
+ this.update();
66
+ },
67
+ update: function() {
68
+ var type = this.type;
69
+ var relatedView = this.relatedView;
70
+ var view = relatedView.getEndView(type);
71
+ if (view) {
72
+ this.updateAnchor();
73
+ this.updateArea();
74
+ this.el.style.display = '';
75
+ } else {
76
+ this.el.style.display = 'none';
77
+ }
78
+ return this;
79
+ },
80
+ updateAnchor: function() {
81
+ var childNodes = this.childNodes;
82
+ if (!childNodes) return;
83
+ var anchorNode = childNodes.anchor;
84
+ if (!anchorNode) return;
85
+ var relatedView = this.relatedView;
86
+ var type = this.type;
87
+ var position = relatedView.getEndAnchor(type);
88
+ var options = this.options;
89
+ var customAnchor = relatedView.model.prop([type, 'anchor']);
90
+ let transformString = `translate(${position.x},${position.y})`;
91
+ if (options.scale) {
92
+ transformString += ` scale(${options.scale})`;
93
+ }
94
+ anchorNode.setAttribute('transform', transformString);
95
+ var anchorAttributes = (customAnchor) ? options.customAnchorAttributes : options.defaultAnchorAttributes;
96
+ for (var attrName in anchorAttributes) {
97
+ anchorNode.setAttribute(attrName, anchorAttributes[attrName]);
98
+ }
99
+ },
100
+ updateArea: function() {
101
+ var childNodes = this.childNodes;
102
+ if (!childNodes) return;
103
+ var areaNode = childNodes.area;
104
+ if (!areaNode) return;
105
+ var relatedView = this.relatedView;
106
+ var type = this.type;
107
+ var view = relatedView.getEndView(type);
108
+ var model = view.model;
109
+ var magnet = relatedView.getEndMagnet(type);
110
+ var padding = this.options.areaPadding;
111
+ if (!isFinite(padding)) padding = 0;
112
+ var bbox, angle, center;
113
+ if (view.isNodeConnection(magnet)) {
114
+ bbox = view.getNodeBBox(magnet);
115
+ angle = 0;
116
+ center = bbox.center();
117
+ } else {
118
+ bbox = view.getNodeUnrotatedBBox(magnet);
119
+ angle = model.angle();
120
+ center = bbox.center();
121
+ if (angle) center.rotate(model.getBBox().center(), -angle);
122
+ // TODO: get the link's magnet rotation into account
123
+ }
124
+ bbox.inflate(padding);
125
+ areaNode.setAttribute('x', -bbox.width / 2);
126
+ areaNode.setAttribute('y', -bbox.height / 2);
127
+ areaNode.setAttribute('width', bbox.width);
128
+ areaNode.setAttribute('height', bbox.height);
129
+ areaNode.setAttribute('transform', 'translate(' + center.x + ',' + center.y + ') rotate(' + angle + ')');
130
+ },
131
+ toggleArea: function(visible) {
132
+ var childNodes = this.childNodes;
133
+ if (!childNodes) return;
134
+ var areaNode = childNodes.area;
135
+ if (!areaNode) return;
136
+ areaNode.style.display = (visible) ? '' : 'none';
137
+ },
138
+ onPointerDown: function(evt) {
139
+ if (this.guard(evt)) return;
140
+ evt.stopPropagation();
141
+ evt.preventDefault();
142
+ this.paper.undelegateEvents();
143
+ this.delegateDocumentEvents();
144
+ this.focus();
145
+ this.toggleArea(this.options.restrictArea);
146
+ this.relatedView.model.startBatch('anchor-move', { ui: true, tool: this.cid });
147
+ },
148
+ resetAnchor: function(anchor) {
149
+ var type = this.type;
150
+ var relatedModel = this.relatedView.model;
151
+ if (anchor) {
152
+ relatedModel.prop([type, 'anchor'], anchor, {
153
+ rewrite: true,
154
+ ui: true,
155
+ tool: this.cid
156
+ });
157
+ } else {
158
+ relatedModel.removeProp([type, 'anchor'], {
159
+ ui: true,
160
+ tool: this.cid
161
+ });
162
+ }
163
+ },
164
+ onPointerMove: function(evt) {
165
+
166
+ var relatedView = this.relatedView;
167
+ var type = this.type;
168
+ var view = relatedView.getEndView(type);
169
+ var model = view.model;
170
+ var magnet = relatedView.getEndMagnet(type);
171
+ var normalizedEvent = util.normalizeEvent(evt);
172
+ var coords = this.paper.clientToLocalPoint(normalizedEvent.clientX, normalizedEvent.clientY);
173
+ var snapFn = this.options.snap;
174
+ if (typeof snapFn === 'function') {
175
+ coords = snapFn.call(relatedView, coords, view, magnet, type, relatedView, this);
176
+ coords = new g.Point(coords);
177
+ }
178
+
179
+ if (this.options.restrictArea) {
180
+ if (view.isNodeConnection(magnet)) {
181
+ // snap coords to the link's connection
182
+ var pointAtConnection = view.getClosestPoint(coords);
183
+ if (pointAtConnection) coords = pointAtConnection;
184
+ } else {
185
+ // snap coords within node bbox
186
+ var bbox = view.getNodeUnrotatedBBox(magnet);
187
+ var angle = model.angle();
188
+ var origin = model.getBBox().center();
189
+ var rotatedCoords = coords.clone().rotate(origin, angle);
190
+ if (!bbox.containsPoint(rotatedCoords)) {
191
+ coords = bbox.pointNearestToPoint(rotatedCoords).rotate(origin, -angle);
192
+ }
193
+ }
194
+ }
195
+
196
+ var anchor;
197
+ var anchorFn = this.options.anchor;
198
+ if (typeof anchorFn === 'function') {
199
+ anchor = anchorFn.call(relatedView, coords, view, magnet, type, relatedView);
200
+ }
201
+
202
+ this.resetAnchor(anchor);
203
+ this.update();
204
+ },
205
+
206
+ onPointerUp: function(evt) {
207
+ const normalizedEvent = util.normalizeEvent(evt);
208
+ this.paper.delegateEvents();
209
+ this.undelegateDocumentEvents();
210
+ this.blur();
211
+ this.toggleArea(false);
212
+ var linkView = this.relatedView;
213
+ if (this.options.redundancyRemoval) linkView.removeRedundantLinearVertices({ ui: true, tool: this.cid });
214
+ linkView.checkMouseleave(normalizedEvent);
215
+ linkView.model.stopBatch('anchor-move', { ui: true, tool: this.cid });
216
+ },
217
+
218
+ onPointerDblClick: function() {
219
+ var anchor = this.options.resetAnchor;
220
+ if (anchor === false) return; // reset anchor disabled
221
+ if (anchor === true) anchor = null; // remove the current anchor
222
+ this.resetAnchor(util.cloneDeep(anchor));
223
+ this.update();
224
+ }
225
+ });
226
+
227
+ export const SourceAnchor = Anchor.extend({
228
+ name: 'source-anchor',
229
+ type: 'source'
230
+ });
231
+
232
+ export const TargetAnchor = Anchor.extend({
233
+ name: 'target-anchor',
234
+ type: 'target'
235
+ });
@@ -0,0 +1,103 @@
1
+ import * as g from '../g/index.mjs';
2
+ import V from '../V/index.mjs';
3
+ import * as util from '../util/index.mjs';
4
+ import { ToolView } from '../dia/ToolView.mjs';
5
+
6
+ // End Markers
7
+ const Arrowhead = ToolView.extend({
8
+ tagName: 'path',
9
+ xAxisVector: new g.Point(1, 0),
10
+ events: {
11
+ mousedown: 'onPointerDown',
12
+ touchstart: 'onPointerDown'
13
+ },
14
+ documentEvents: {
15
+ mousemove: 'onPointerMove',
16
+ touchmove: 'onPointerMove',
17
+ mouseup: 'onPointerUp',
18
+ touchend: 'onPointerUp',
19
+ touchcancel: 'onPointerUp'
20
+ },
21
+ options: {
22
+ scale: null
23
+ },
24
+ onRender: function() {
25
+ this.update();
26
+ },
27
+ update: function() {
28
+ var ratio = this.ratio;
29
+ var view = this.relatedView;
30
+ var tangent = view.getTangentAtRatio(ratio);
31
+ var position, angle;
32
+ if (tangent) {
33
+ position = tangent.start;
34
+ angle = tangent.vector().vectorAngle(this.xAxisVector) || 0;
35
+ } else {
36
+ position = view.getPointAtRatio(ratio);
37
+ angle = 0;
38
+ }
39
+ if (!position) return this;
40
+ var matrix = V.createSVGMatrix().translate(position.x, position.y).rotate(angle);
41
+ const { scale } = this.options;
42
+ if (scale) matrix = matrix.scale(scale);
43
+ this.vel.transform(matrix, { absolute: true });
44
+ return this;
45
+ },
46
+ onPointerDown: function(evt) {
47
+ if (this.guard(evt)) return;
48
+ evt.stopPropagation();
49
+ evt.preventDefault();
50
+ var relatedView = this.relatedView;
51
+ relatedView.model.startBatch('arrowhead-move', { ui: true, tool: this.cid });
52
+ relatedView.startArrowheadMove(this.arrowheadType);
53
+ this.delegateDocumentEvents();
54
+ relatedView.paper.undelegateEvents();
55
+ this.focus();
56
+ this.el.style.pointerEvents = 'none';
57
+ },
58
+ onPointerMove: function(evt) {
59
+ var normalizedEvent = util.normalizeEvent(evt);
60
+ var coords = this.paper.snapToGrid(normalizedEvent.clientX, normalizedEvent.clientY);
61
+ this.relatedView.pointermove(normalizedEvent, coords.x, coords.y);
62
+ },
63
+ onPointerUp: function(evt) {
64
+ this.undelegateDocumentEvents();
65
+ var relatedView = this.relatedView;
66
+ var paper = relatedView.paper;
67
+ var normalizedEvent = util.normalizeEvent(evt);
68
+ var coords = paper.snapToGrid(normalizedEvent.clientX, normalizedEvent.clientY);
69
+ relatedView.pointerup(normalizedEvent, coords.x, coords.y);
70
+ paper.delegateEvents();
71
+ this.blur();
72
+ this.el.style.pointerEvents = '';
73
+ relatedView.model.stopBatch('arrowhead-move', { ui: true, tool: this.cid });
74
+ }
75
+ });
76
+
77
+ export const TargetArrowhead = Arrowhead.extend({
78
+ name: 'target-arrowhead',
79
+ ratio: 1,
80
+ arrowheadType: 'target',
81
+ attributes: {
82
+ 'd': 'M -10 -8 10 0 -10 8 Z',
83
+ 'fill': '#33334F',
84
+ 'stroke': '#FFFFFF',
85
+ 'stroke-width': 2,
86
+ 'cursor': 'move',
87
+ 'class': 'target-arrowhead'
88
+ }
89
+ });
90
+
91
+ export const SourceArrowhead = Arrowhead.extend({
92
+ name: 'source-arrowhead',
93
+ ratio: 0,
94
+ arrowheadType: 'source',
95
+ attributes: {
96
+ 'd': 'M 10 -8 -10 0 10 8 Z',
97
+ 'fill': '#33334F',
98
+ 'stroke': '#FFFFFF',
99
+ 'stroke-width': 2,
100
+ 'cursor': 'move',
101
+ 'class': 'source-arrowhead'
102
+ }
103
+ });
@@ -0,0 +1,48 @@
1
+
2
+ import * as util from '../util/index.mjs';
3
+ import { ToolView } from '../dia/ToolView.mjs';
4
+ import { getViewBBox } from './helpers.mjs';
5
+
6
+ export const Boundary = ToolView.extend({
7
+ name: 'boundary',
8
+ tagName: 'rect',
9
+ options: {
10
+ padding: 10,
11
+ useModelGeometry: false,
12
+ },
13
+ attributes: {
14
+ 'fill': 'none',
15
+ 'stroke': '#33334F',
16
+ 'stroke-width': .5,
17
+ 'stroke-dasharray': '5, 5',
18
+ 'pointer-events': 'none'
19
+ },
20
+ onRender: function() {
21
+ this.update();
22
+ },
23
+ update: function() {
24
+ const { relatedView: view, options, vel } = this;
25
+ const { useModelGeometry, rotate } = options;
26
+ const padding = util.normalizeSides(options.padding);
27
+ let bbox = getViewBBox(view, useModelGeometry).moveAndExpand({
28
+ x: -padding.left,
29
+ y: -padding.top,
30
+ width: padding.left + padding.right,
31
+ height: padding.top + padding.bottom
32
+ });
33
+ var model = view.model;
34
+ if (model.isElement()) {
35
+ var angle = model.angle();
36
+ if (angle) {
37
+ if (rotate) {
38
+ var origin = model.getBBox().center();
39
+ vel.rotate(angle, origin.x, origin.y, { absolute: true });
40
+ } else {
41
+ bbox = bbox.bbox(angle);
42
+ }
43
+ }
44
+ }
45
+ vel.attr(bbox.toJSON());
46
+ return this;
47
+ }
48
+ });