@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
|
@@ -0,0 +1,393 @@
|
|
|
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 * as mvc from '../mvc/index.mjs';
|
|
5
|
+
import { ToolView } from '../dia/ToolView.mjs';
|
|
6
|
+
import { getAnchor } from './helpers.mjs';
|
|
7
|
+
|
|
8
|
+
var SegmentHandle = mvc.View.extend({
|
|
9
|
+
tagName: 'g',
|
|
10
|
+
svgElement: true,
|
|
11
|
+
className: 'marker-segment',
|
|
12
|
+
events: {
|
|
13
|
+
mousedown: 'onPointerDown',
|
|
14
|
+
touchstart: 'onPointerDown'
|
|
15
|
+
},
|
|
16
|
+
documentEvents: {
|
|
17
|
+
mousemove: 'onPointerMove',
|
|
18
|
+
touchmove: 'onPointerMove',
|
|
19
|
+
mouseup: 'onPointerUp',
|
|
20
|
+
touchend: 'onPointerUp',
|
|
21
|
+
touchcancel: 'onPointerUp'
|
|
22
|
+
},
|
|
23
|
+
children: [{
|
|
24
|
+
tagName: 'line',
|
|
25
|
+
selector: 'line',
|
|
26
|
+
attributes: {
|
|
27
|
+
'stroke': '#33334F',
|
|
28
|
+
'stroke-width': 2,
|
|
29
|
+
'fill': 'none',
|
|
30
|
+
'pointer-events': 'none'
|
|
31
|
+
}
|
|
32
|
+
}, {
|
|
33
|
+
tagName: 'rect',
|
|
34
|
+
selector: 'handle',
|
|
35
|
+
attributes: {
|
|
36
|
+
'width': 20,
|
|
37
|
+
'height': 8,
|
|
38
|
+
'x': -10,
|
|
39
|
+
'y': -4,
|
|
40
|
+
'rx': 4,
|
|
41
|
+
'ry': 4,
|
|
42
|
+
'fill': '#33334F',
|
|
43
|
+
'stroke': '#FFFFFF',
|
|
44
|
+
'stroke-width': 2
|
|
45
|
+
}
|
|
46
|
+
}],
|
|
47
|
+
onRender: function() {
|
|
48
|
+
this.renderChildren();
|
|
49
|
+
},
|
|
50
|
+
position: function(x, y, angle, view) {
|
|
51
|
+
const { scale } = this.options;
|
|
52
|
+
let matrix = V.createSVGMatrix().translate(x, y).rotate(angle);
|
|
53
|
+
if (scale) matrix = matrix.scale(scale);
|
|
54
|
+
|
|
55
|
+
var handle = this.childNodes.handle;
|
|
56
|
+
handle.setAttribute('transform', V.matrixToTransformString(matrix));
|
|
57
|
+
handle.setAttribute('cursor', (angle % 180 === 0) ? 'row-resize' : 'col-resize');
|
|
58
|
+
|
|
59
|
+
var viewPoint = view.getClosestPoint(new g.Point(x, y));
|
|
60
|
+
var line = this.childNodes.line;
|
|
61
|
+
line.setAttribute('x1', x);
|
|
62
|
+
line.setAttribute('y1', y);
|
|
63
|
+
line.setAttribute('x2', viewPoint.x);
|
|
64
|
+
line.setAttribute('y2', viewPoint.y);
|
|
65
|
+
},
|
|
66
|
+
onPointerDown: function(evt) {
|
|
67
|
+
if (this.options.guard(evt)) return;
|
|
68
|
+
this.trigger('change:start', this, evt);
|
|
69
|
+
evt.stopPropagation();
|
|
70
|
+
evt.preventDefault();
|
|
71
|
+
this.options.paper.undelegateEvents();
|
|
72
|
+
this.delegateDocumentEvents(null, evt.data);
|
|
73
|
+
},
|
|
74
|
+
onPointerMove: function(evt) {
|
|
75
|
+
this.trigger('changing', this, evt);
|
|
76
|
+
},
|
|
77
|
+
onPointerUp: function(evt) {
|
|
78
|
+
this.undelegateDocumentEvents();
|
|
79
|
+
this.options.paper.delegateEvents();
|
|
80
|
+
this.trigger('change:end', this, evt);
|
|
81
|
+
},
|
|
82
|
+
show: function() {
|
|
83
|
+
this.el.style.display = '';
|
|
84
|
+
},
|
|
85
|
+
hide: function() {
|
|
86
|
+
this.el.style.display = 'none';
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export const Segments = ToolView.extend({
|
|
91
|
+
name: 'segments',
|
|
92
|
+
precision: .5,
|
|
93
|
+
options: {
|
|
94
|
+
handleClass: SegmentHandle,
|
|
95
|
+
segmentLengthThreshold: 40,
|
|
96
|
+
redundancyRemoval: true,
|
|
97
|
+
anchor: getAnchor,
|
|
98
|
+
snapRadius: 10,
|
|
99
|
+
snapHandle: true,
|
|
100
|
+
stopPropagation: true
|
|
101
|
+
},
|
|
102
|
+
handles: null,
|
|
103
|
+
onRender: function() {
|
|
104
|
+
this.resetHandles();
|
|
105
|
+
var relatedView = this.relatedView;
|
|
106
|
+
var vertices = relatedView.model.vertices();
|
|
107
|
+
vertices.unshift(relatedView.sourcePoint);
|
|
108
|
+
vertices.push(relatedView.targetPoint);
|
|
109
|
+
for (var i = 0, n = vertices.length; i < n - 1; i++) {
|
|
110
|
+
var vertex = vertices[i];
|
|
111
|
+
var nextVertex = vertices[i + 1];
|
|
112
|
+
var handle = this.renderHandle(vertex, nextVertex);
|
|
113
|
+
this.simulateRelatedView(handle.el);
|
|
114
|
+
this.handles.push(handle);
|
|
115
|
+
handle.options.index = i;
|
|
116
|
+
}
|
|
117
|
+
return this;
|
|
118
|
+
},
|
|
119
|
+
renderHandle: function(vertex, nextVertex) {
|
|
120
|
+
var handle = new (this.options.handleClass)({
|
|
121
|
+
paper: this.paper,
|
|
122
|
+
scale: this.options.scale,
|
|
123
|
+
guard: evt => this.guard(evt)
|
|
124
|
+
});
|
|
125
|
+
handle.render();
|
|
126
|
+
this.updateHandle(handle, vertex, nextVertex);
|
|
127
|
+
handle.vel.appendTo(this.el);
|
|
128
|
+
this.startHandleListening(handle);
|
|
129
|
+
return handle;
|
|
130
|
+
},
|
|
131
|
+
update: function() {
|
|
132
|
+
this.render();
|
|
133
|
+
return this;
|
|
134
|
+
},
|
|
135
|
+
startHandleListening: function(handle) {
|
|
136
|
+
this.listenTo(handle, 'change:start', this.onHandleChangeStart);
|
|
137
|
+
this.listenTo(handle, 'changing', this.onHandleChanging);
|
|
138
|
+
this.listenTo(handle, 'change:end', this.onHandleChangeEnd);
|
|
139
|
+
},
|
|
140
|
+
resetHandles: function() {
|
|
141
|
+
var handles = this.handles;
|
|
142
|
+
this.handles = [];
|
|
143
|
+
this.stopListening();
|
|
144
|
+
if (!Array.isArray(handles)) return;
|
|
145
|
+
for (var i = 0, n = handles.length; i < n; i++) {
|
|
146
|
+
handles[i].remove();
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
shiftHandleIndexes: function(value) {
|
|
150
|
+
var handles = this.handles;
|
|
151
|
+
for (var i = 0, n = handles.length; i < n; i++) handles[i].options.index += value;
|
|
152
|
+
},
|
|
153
|
+
resetAnchor: function(type, anchor) {
|
|
154
|
+
var relatedModel = this.relatedView.model;
|
|
155
|
+
if (anchor) {
|
|
156
|
+
relatedModel.prop([type, 'anchor'], anchor, {
|
|
157
|
+
rewrite: true,
|
|
158
|
+
ui: true,
|
|
159
|
+
tool: this.cid
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
relatedModel.removeProp([type, 'anchor'], {
|
|
163
|
+
ui: true,
|
|
164
|
+
tool: this.cid
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
snapHandle: function(handle, position, data) {
|
|
169
|
+
|
|
170
|
+
var index = handle.options.index;
|
|
171
|
+
var linkView = this.relatedView;
|
|
172
|
+
var link = linkView.model;
|
|
173
|
+
var vertices = link.vertices();
|
|
174
|
+
var axis = handle.options.axis;
|
|
175
|
+
var prev = vertices[index - 2] || data.sourceAnchor;
|
|
176
|
+
var next = vertices[index + 1] || data.targetAnchor;
|
|
177
|
+
var snapRadius = this.options.snapRadius;
|
|
178
|
+
if (Math.abs(position[axis] - prev[axis]) < snapRadius) {
|
|
179
|
+
position[axis] = prev[axis];
|
|
180
|
+
} else if (Math.abs(position[axis] - next[axis]) < snapRadius) {
|
|
181
|
+
position[axis] = next[axis];
|
|
182
|
+
}
|
|
183
|
+
return position;
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
onHandleChanging: function(handle, evt) {
|
|
187
|
+
|
|
188
|
+
const { options } = this;
|
|
189
|
+
var data = this.eventData(evt);
|
|
190
|
+
var relatedView = this.relatedView;
|
|
191
|
+
var paper = relatedView.paper;
|
|
192
|
+
var index = handle.options.index - 1;
|
|
193
|
+
var normalizedEvent = util.normalizeEvent(evt);
|
|
194
|
+
var coords = paper.snapToGrid(normalizedEvent.clientX, normalizedEvent.clientY);
|
|
195
|
+
var position = this.snapHandle(handle, coords.clone(), data);
|
|
196
|
+
var axis = handle.options.axis;
|
|
197
|
+
var offset = (this.options.snapHandle) ? 0 : (coords[axis] - position[axis]);
|
|
198
|
+
var link = relatedView.model;
|
|
199
|
+
var vertices = util.cloneDeep(link.vertices());
|
|
200
|
+
var anchorFn = this.options.anchor;
|
|
201
|
+
if (typeof anchorFn !== 'function') anchorFn = null;
|
|
202
|
+
|
|
203
|
+
const handleIndex = handle.options.index;
|
|
204
|
+
|
|
205
|
+
const vertexPoints = [relatedView.sourcePoint.clone(), ...vertices, relatedView.targetPoint.clone()];
|
|
206
|
+
let indexOffset = 0;
|
|
207
|
+
|
|
208
|
+
// check if vertex before handle vertex exists
|
|
209
|
+
if (handleIndex - 1 >= 0) {
|
|
210
|
+
const v1 = vertexPoints[handleIndex - 1];
|
|
211
|
+
const v2 = vertexPoints[handleIndex];
|
|
212
|
+
|
|
213
|
+
const theta = new g.Line(v1, v2).vector().theta();
|
|
214
|
+
|
|
215
|
+
// check only non-orthogonal segments
|
|
216
|
+
if (theta % 90 !== 0) {
|
|
217
|
+
vertices.splice(handleIndex - 1, 0, data.originalVertices[handleIndex - 1]);
|
|
218
|
+
indexOffset++;
|
|
219
|
+
this.shiftHandleIndexes(1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
var vertex = vertices[index + indexOffset];
|
|
224
|
+
var nextVertex = vertices[index + 1 + indexOffset];
|
|
225
|
+
|
|
226
|
+
// check if vertex after handle vertex exists
|
|
227
|
+
if (handleIndex + 2 < vertexPoints.length) {
|
|
228
|
+
const v1 = vertexPoints[handleIndex + 1];
|
|
229
|
+
const v2 = vertexPoints[handleIndex + 2];
|
|
230
|
+
|
|
231
|
+
const theta = new g.Line(v1, v2).vector().theta();
|
|
232
|
+
|
|
233
|
+
// check only non-orthogonal segments
|
|
234
|
+
if (theta % 90 !== 0) {
|
|
235
|
+
const isSingleVertex = data.originalVertices.length === 1;
|
|
236
|
+
const origVIndex = isSingleVertex ? 0 : handleIndex;
|
|
237
|
+
const additionalOffset = data.firstHandleShifted && !isSingleVertex ? 1 : 0;
|
|
238
|
+
let nextVIndex = 1 + indexOffset;
|
|
239
|
+
vertices.splice(handleIndex + nextVIndex, 0, data.originalVertices[origVIndex - additionalOffset]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// First Segment
|
|
244
|
+
var sourceView = relatedView.sourceView;
|
|
245
|
+
var sourceBBox = relatedView.sourceBBox;
|
|
246
|
+
var changeSourceAnchor = false;
|
|
247
|
+
var deleteSourceAnchor = false;
|
|
248
|
+
if (!vertex) {
|
|
249
|
+
vertex = relatedView.sourceAnchor.toJSON();
|
|
250
|
+
vertex[axis] = position[axis];
|
|
251
|
+
if (sourceBBox.containsPoint(vertex)) {
|
|
252
|
+
vertex[axis] = position[axis];
|
|
253
|
+
changeSourceAnchor = true;
|
|
254
|
+
} else {
|
|
255
|
+
// we left the area of the source magnet for the first time
|
|
256
|
+
vertices.unshift(vertex);
|
|
257
|
+
this.shiftHandleIndexes(1);
|
|
258
|
+
data.firstHandleShifted = true;
|
|
259
|
+
deleteSourceAnchor = true;
|
|
260
|
+
}
|
|
261
|
+
} else if (index === 0) {
|
|
262
|
+
if (sourceBBox.containsPoint(vertex)) {
|
|
263
|
+
vertices.shift();
|
|
264
|
+
this.shiftHandleIndexes(-1);
|
|
265
|
+
changeSourceAnchor = true;
|
|
266
|
+
} else {
|
|
267
|
+
vertex[axis] = position[axis];
|
|
268
|
+
deleteSourceAnchor = true;
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
vertex[axis] = position[axis];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (anchorFn && sourceView) {
|
|
275
|
+
if (changeSourceAnchor) {
|
|
276
|
+
var sourceAnchorPosition = data.sourceAnchor.clone();
|
|
277
|
+
sourceAnchorPosition[axis] = position[axis];
|
|
278
|
+
var sourceAnchor = anchorFn.call(relatedView, sourceAnchorPosition, sourceView, relatedView.sourceMagnet || sourceView.el, 'source', relatedView);
|
|
279
|
+
this.resetAnchor('source', sourceAnchor);
|
|
280
|
+
}
|
|
281
|
+
if (deleteSourceAnchor) {
|
|
282
|
+
this.resetAnchor('source', data.sourceAnchorDef);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Last segment
|
|
287
|
+
var targetView = relatedView.targetView;
|
|
288
|
+
var targetBBox = relatedView.targetBBox;
|
|
289
|
+
var changeTargetAnchor = false;
|
|
290
|
+
var deleteTargetAnchor = false;
|
|
291
|
+
if (!nextVertex) {
|
|
292
|
+
nextVertex = relatedView.targetAnchor.toJSON();
|
|
293
|
+
nextVertex[axis] = position[axis];
|
|
294
|
+
if (targetBBox.containsPoint(nextVertex)) {
|
|
295
|
+
changeTargetAnchor = true;
|
|
296
|
+
} else {
|
|
297
|
+
// we left the area of the target magnet for the first time
|
|
298
|
+
vertices.push(nextVertex);
|
|
299
|
+
deleteTargetAnchor = true;
|
|
300
|
+
}
|
|
301
|
+
} else if (index === vertices.length - 2) {
|
|
302
|
+
if (targetBBox.containsPoint(nextVertex)) {
|
|
303
|
+
vertices.pop();
|
|
304
|
+
changeTargetAnchor = true;
|
|
305
|
+
} else {
|
|
306
|
+
nextVertex[axis] = position[axis];
|
|
307
|
+
deleteTargetAnchor = true;
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
nextVertex[axis] = position[axis];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (anchorFn && targetView) {
|
|
314
|
+
if (changeTargetAnchor) {
|
|
315
|
+
var targetAnchorPosition = data.targetAnchor.clone();
|
|
316
|
+
targetAnchorPosition[axis] = position[axis];
|
|
317
|
+
var targetAnchor = anchorFn.call(relatedView, targetAnchorPosition, targetView, relatedView.targetMagnet || targetView.el, 'target', relatedView);
|
|
318
|
+
this.resetAnchor('target', targetAnchor);
|
|
319
|
+
}
|
|
320
|
+
if (deleteTargetAnchor) {
|
|
321
|
+
this.resetAnchor('target', data.targetAnchorDef);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (vertices.some(v => !v)) {
|
|
325
|
+
// This can happen when the link is using a smart routing and the number of
|
|
326
|
+
// vertices is not the same as the number of route points.
|
|
327
|
+
throw new Error('Segments: incompatible router in use');
|
|
328
|
+
}
|
|
329
|
+
link.vertices(vertices, { ui: true, tool: this.cid });
|
|
330
|
+
this.updateHandle(handle, vertex, nextVertex, offset);
|
|
331
|
+
if (!options.stopPropagation) relatedView.notifyPointermove(normalizedEvent, coords.x, coords.y);
|
|
332
|
+
},
|
|
333
|
+
onHandleChangeStart: function(handle, evt) {
|
|
334
|
+
const { options, handles, relatedView: linkView } = this;
|
|
335
|
+
const { model, paper } = linkView;
|
|
336
|
+
var index = handle.options.index;
|
|
337
|
+
if (!Array.isArray(handles)) return;
|
|
338
|
+
for (var i = 0, n = handles.length; i < n; i++) {
|
|
339
|
+
if (i !== index) handles[i].hide();
|
|
340
|
+
}
|
|
341
|
+
this.focus();
|
|
342
|
+
this.eventData(evt, {
|
|
343
|
+
sourceAnchor: linkView.sourceAnchor.clone(),
|
|
344
|
+
targetAnchor: linkView.targetAnchor.clone(),
|
|
345
|
+
sourceAnchorDef: util.clone(model.prop(['source', 'anchor'])),
|
|
346
|
+
targetAnchorDef: util.clone(model.prop(['target', 'anchor'])),
|
|
347
|
+
originalVertices: util.cloneDeep(model.vertices()),
|
|
348
|
+
firstHandleShifted: false
|
|
349
|
+
});
|
|
350
|
+
model.startBatch('segment-move', { ui: true, tool: this.cid });
|
|
351
|
+
if (!options.stopPropagation) linkView.notifyPointerdown(...paper.getPointerArgs(evt));
|
|
352
|
+
},
|
|
353
|
+
onHandleChangeEnd: function(_handle, evt) {
|
|
354
|
+
const { options, relatedView: linkView }= this;
|
|
355
|
+
const { paper, model } = linkView;
|
|
356
|
+
if (options.redundancyRemoval) {
|
|
357
|
+
linkView.removeRedundantLinearVertices({ ui: true, tool: this.cid });
|
|
358
|
+
}
|
|
359
|
+
const normalizedEvent = util.normalizeEvent(evt);
|
|
360
|
+
const coords = paper.snapToGrid(normalizedEvent.clientX, normalizedEvent.clientY);
|
|
361
|
+
this.render();
|
|
362
|
+
this.blur();
|
|
363
|
+
model.stopBatch('segment-move', { ui: true, tool: this.cid });
|
|
364
|
+
if (!options.stopPropagation) linkView.notifyPointerup(normalizedEvent, coords.x, coords.y);
|
|
365
|
+
linkView.checkMouseleave(normalizedEvent);
|
|
366
|
+
},
|
|
367
|
+
updateHandle: function(handle, vertex, nextVertex, offset) {
|
|
368
|
+
var vertical = Math.abs(vertex.x - nextVertex.x) < this.precision;
|
|
369
|
+
var horizontal = Math.abs(vertex.y - nextVertex.y) < this.precision;
|
|
370
|
+
if (vertical || horizontal) {
|
|
371
|
+
var segmentLine = new g.Line(vertex, nextVertex);
|
|
372
|
+
var length = segmentLine.length();
|
|
373
|
+
if (length < this.options.segmentLengthThreshold) {
|
|
374
|
+
handle.hide();
|
|
375
|
+
} else {
|
|
376
|
+
var position = segmentLine.midpoint();
|
|
377
|
+
var axis = (vertical) ? 'x' : 'y';
|
|
378
|
+
position[axis] += offset || 0;
|
|
379
|
+
var angle = segmentLine.vector().vectorAngle(new g.Point(1, 0));
|
|
380
|
+
handle.position(position.x, position.y, angle, this.relatedView);
|
|
381
|
+
handle.show();
|
|
382
|
+
handle.options.axis = axis;
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
handle.hide();
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
onRemove: function() {
|
|
389
|
+
this.resetHandles();
|
|
390
|
+
}
|
|
391
|
+
}, {
|
|
392
|
+
SegmentHandle: SegmentHandle // keep as class property
|
|
393
|
+
});
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import * as g from '../g/index.mjs';
|
|
2
|
+
import * as util from '../util/index.mjs';
|
|
3
|
+
import * as mvc from '../mvc/index.mjs';
|
|
4
|
+
import { ToolView } from '../dia/ToolView.mjs';
|
|
5
|
+
import V from '../V/index.mjs';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// Vertex Handles
|
|
9
|
+
var VertexHandle = mvc.View.extend({
|
|
10
|
+
tagName: 'circle',
|
|
11
|
+
svgElement: true,
|
|
12
|
+
className: 'marker-vertex',
|
|
13
|
+
events: {
|
|
14
|
+
mousedown: 'onPointerDown',
|
|
15
|
+
touchstart: 'onPointerDown',
|
|
16
|
+
dblclick: 'onDoubleClick',
|
|
17
|
+
dbltap: 'onDoubleClick'
|
|
18
|
+
},
|
|
19
|
+
documentEvents: {
|
|
20
|
+
mousemove: 'onPointerMove',
|
|
21
|
+
touchmove: 'onPointerMove',
|
|
22
|
+
mouseup: 'onPointerUp',
|
|
23
|
+
touchend: 'onPointerUp',
|
|
24
|
+
touchcancel: 'onPointerUp'
|
|
25
|
+
},
|
|
26
|
+
attributes: {
|
|
27
|
+
'r': 6,
|
|
28
|
+
'fill': '#33334F',
|
|
29
|
+
'stroke': '#FFFFFF',
|
|
30
|
+
'stroke-width': 2,
|
|
31
|
+
'cursor': 'move'
|
|
32
|
+
},
|
|
33
|
+
position: function(x, y) {
|
|
34
|
+
const { vel, options } = this;
|
|
35
|
+
const { scale } = options;
|
|
36
|
+
let matrix = V.createSVGMatrix().translate(x, y);
|
|
37
|
+
if (scale) matrix = matrix.scale(scale);
|
|
38
|
+
vel.transform(matrix, { absolute: true });
|
|
39
|
+
},
|
|
40
|
+
onPointerDown: function(evt) {
|
|
41
|
+
if (this.options.guard(evt)) return;
|
|
42
|
+
evt.stopPropagation();
|
|
43
|
+
evt.preventDefault();
|
|
44
|
+
this.options.paper.undelegateEvents();
|
|
45
|
+
this.delegateDocumentEvents(null, evt.data);
|
|
46
|
+
this.trigger('will-change', this, evt);
|
|
47
|
+
},
|
|
48
|
+
onPointerMove: function(evt) {
|
|
49
|
+
this.trigger('changing', this, evt);
|
|
50
|
+
},
|
|
51
|
+
onDoubleClick: function(evt) {
|
|
52
|
+
this.trigger('remove', this, evt);
|
|
53
|
+
},
|
|
54
|
+
onPointerUp: function(evt) {
|
|
55
|
+
this.trigger('changed', this, evt);
|
|
56
|
+
this.undelegateDocumentEvents();
|
|
57
|
+
this.options.paper.delegateEvents();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export const Vertices = ToolView.extend({
|
|
62
|
+
name: 'vertices',
|
|
63
|
+
options: {
|
|
64
|
+
handleClass: VertexHandle,
|
|
65
|
+
snapRadius: 20,
|
|
66
|
+
redundancyRemoval: true,
|
|
67
|
+
vertexAdding: true,
|
|
68
|
+
stopPropagation: true,
|
|
69
|
+
scale: null
|
|
70
|
+
},
|
|
71
|
+
children: [{
|
|
72
|
+
tagName: 'path',
|
|
73
|
+
selector: 'connection',
|
|
74
|
+
className: 'joint-vertices-path',
|
|
75
|
+
attributes: {
|
|
76
|
+
'fill': 'none',
|
|
77
|
+
'stroke': 'transparent',
|
|
78
|
+
'stroke-width': 10,
|
|
79
|
+
'cursor': 'cell'
|
|
80
|
+
}
|
|
81
|
+
}],
|
|
82
|
+
handles: null,
|
|
83
|
+
events: {
|
|
84
|
+
'mousedown .joint-vertices-path': 'onPathPointerDown',
|
|
85
|
+
'touchstart .joint-vertices-path': 'onPathPointerDown'
|
|
86
|
+
},
|
|
87
|
+
onRender: function() {
|
|
88
|
+
if (this.options.vertexAdding) {
|
|
89
|
+
this.renderChildren();
|
|
90
|
+
this.updatePath();
|
|
91
|
+
}
|
|
92
|
+
this.resetHandles();
|
|
93
|
+
this.renderHandles();
|
|
94
|
+
return this;
|
|
95
|
+
},
|
|
96
|
+
update: function() {
|
|
97
|
+
var relatedView = this.relatedView;
|
|
98
|
+
var vertices = relatedView.model.vertices();
|
|
99
|
+
if (vertices.length === this.handles.length) {
|
|
100
|
+
this.updateHandles();
|
|
101
|
+
} else {
|
|
102
|
+
this.resetHandles();
|
|
103
|
+
this.renderHandles();
|
|
104
|
+
}
|
|
105
|
+
if (this.options.vertexAdding) {
|
|
106
|
+
this.updatePath();
|
|
107
|
+
}
|
|
108
|
+
return this;
|
|
109
|
+
},
|
|
110
|
+
resetHandles: function() {
|
|
111
|
+
var handles = this.handles;
|
|
112
|
+
this.handles = [];
|
|
113
|
+
this.stopListening();
|
|
114
|
+
if (!Array.isArray(handles)) return;
|
|
115
|
+
for (var i = 0, n = handles.length; i < n; i++) {
|
|
116
|
+
handles[i].remove();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
renderHandles: function() {
|
|
120
|
+
var relatedView = this.relatedView;
|
|
121
|
+
var vertices = relatedView.model.vertices();
|
|
122
|
+
for (var i = 0, n = vertices.length; i < n; i++) {
|
|
123
|
+
var vertex = vertices[i];
|
|
124
|
+
var handle = new (this.options.handleClass)({
|
|
125
|
+
index: i,
|
|
126
|
+
paper: this.paper,
|
|
127
|
+
scale: this.options.scale,
|
|
128
|
+
guard: evt => this.guard(evt)
|
|
129
|
+
});
|
|
130
|
+
handle.render();
|
|
131
|
+
handle.position(vertex.x, vertex.y);
|
|
132
|
+
this.simulateRelatedView(handle.el);
|
|
133
|
+
handle.vel.appendTo(this.el);
|
|
134
|
+
this.handles.push(handle);
|
|
135
|
+
this.startHandleListening(handle);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
updateHandles: function() {
|
|
139
|
+
var relatedView = this.relatedView;
|
|
140
|
+
var vertices = relatedView.model.vertices();
|
|
141
|
+
for (var i = 0, n = vertices.length; i < n; i++) {
|
|
142
|
+
var vertex = vertices[i];
|
|
143
|
+
var handle = this.handles[i];
|
|
144
|
+
if (!handle) return;
|
|
145
|
+
handle.position(vertex.x, vertex.y);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
updatePath: function() {
|
|
149
|
+
var connection = this.childNodes.connection;
|
|
150
|
+
if (connection) connection.setAttribute('d', this.relatedView.getSerializedConnection());
|
|
151
|
+
},
|
|
152
|
+
startHandleListening: function(handle) {
|
|
153
|
+
const { vertexRemoving = true, vertexMoving = true } = this.options;
|
|
154
|
+
if (vertexMoving) {
|
|
155
|
+
this.listenTo(handle, 'will-change', this.onHandleWillChange);
|
|
156
|
+
this.listenTo(handle, 'changing', this.onHandleChanging);
|
|
157
|
+
this.listenTo(handle, 'changed', this.onHandleChanged);
|
|
158
|
+
}
|
|
159
|
+
if (vertexRemoving) {
|
|
160
|
+
this.listenTo(handle, 'remove', this.onHandleRemove);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
getNeighborPoints: function(index) {
|
|
164
|
+
var linkView = this.relatedView;
|
|
165
|
+
var vertices = linkView.model.vertices();
|
|
166
|
+
var prev = (index > 0) ? vertices[index - 1] : linkView.sourceAnchor;
|
|
167
|
+
var next = (index < vertices.length - 1) ? vertices[index + 1] : linkView.targetAnchor;
|
|
168
|
+
return {
|
|
169
|
+
prev: new g.Point(prev),
|
|
170
|
+
next: new g.Point(next)
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
onHandleWillChange: function(_handle, evt) {
|
|
174
|
+
this.focus();
|
|
175
|
+
const { relatedView, options } = this;
|
|
176
|
+
relatedView.model.startBatch('vertex-move', { ui: true, tool: this.cid });
|
|
177
|
+
if (!options.stopPropagation) relatedView.notifyPointerdown(...relatedView.paper.getPointerArgs(evt));
|
|
178
|
+
},
|
|
179
|
+
onHandleChanging: function(handle, evt) {
|
|
180
|
+
const { options, relatedView: linkView } = this;
|
|
181
|
+
var index = handle.options.index;
|
|
182
|
+
var [normalizedEvent, x, y] = linkView.paper.getPointerArgs(evt);
|
|
183
|
+
var vertex = { x, y };
|
|
184
|
+
this.snapVertex(vertex, index);
|
|
185
|
+
linkView.model.vertex(index, vertex, { ui: true, tool: this.cid });
|
|
186
|
+
handle.position(vertex.x, vertex.y);
|
|
187
|
+
if (!options.stopPropagation) linkView.notifyPointermove(normalizedEvent, x, y);
|
|
188
|
+
},
|
|
189
|
+
onHandleChanged: function(_handle, evt) {
|
|
190
|
+
const { options, relatedView: linkView } = this;
|
|
191
|
+
if (options.vertexAdding) this.updatePath();
|
|
192
|
+
if (!options.redundancyRemoval) {
|
|
193
|
+
linkView.checkMouseleave(util.normalizeEvent(evt));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
var verticesRemoved = linkView.removeRedundantLinearVertices({ ui: true, tool: this.cid });
|
|
197
|
+
if (verticesRemoved) this.render();
|
|
198
|
+
this.blur();
|
|
199
|
+
linkView.model.stopBatch('vertex-move', { ui: true, tool: this.cid });
|
|
200
|
+
if (this.eventData(evt).vertexAdded) {
|
|
201
|
+
linkView.model.stopBatch('vertex-add', { ui: true, tool: this.cid });
|
|
202
|
+
}
|
|
203
|
+
var [normalizedEvt, x, y] = linkView.paper.getPointerArgs(evt);
|
|
204
|
+
if (!options.stopPropagation) linkView.notifyPointerup(normalizedEvt, x, y);
|
|
205
|
+
linkView.checkMouseleave(normalizedEvt);
|
|
206
|
+
},
|
|
207
|
+
snapVertex: function(vertex, index) {
|
|
208
|
+
var snapRadius = this.options.snapRadius;
|
|
209
|
+
if (snapRadius > 0) {
|
|
210
|
+
var neighbors = this.getNeighborPoints(index);
|
|
211
|
+
var prev = neighbors.prev;
|
|
212
|
+
var next = neighbors.next;
|
|
213
|
+
if (Math.abs(vertex.x - prev.x) < snapRadius) {
|
|
214
|
+
vertex.x = prev.x;
|
|
215
|
+
} else if (Math.abs(vertex.x - next.x) < snapRadius) {
|
|
216
|
+
vertex.x = next.x;
|
|
217
|
+
}
|
|
218
|
+
if (Math.abs(vertex.y - prev.y) < snapRadius) {
|
|
219
|
+
vertex.y = neighbors.prev.y;
|
|
220
|
+
} else if (Math.abs(vertex.y - next.y) < snapRadius) {
|
|
221
|
+
vertex.y = next.y;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
onHandleRemove: function(handle, evt) {
|
|
226
|
+
var index = handle.options.index;
|
|
227
|
+
var linkView = this.relatedView;
|
|
228
|
+
linkView.model.removeVertex(index, { ui: true });
|
|
229
|
+
if (this.options.vertexAdding) this.updatePath();
|
|
230
|
+
linkView.checkMouseleave(util.normalizeEvent(evt));
|
|
231
|
+
},
|
|
232
|
+
onPathPointerDown: function(evt) {
|
|
233
|
+
if (this.guard(evt)) return;
|
|
234
|
+
evt.stopPropagation();
|
|
235
|
+
evt.preventDefault();
|
|
236
|
+
var normalizedEvent = util.normalizeEvent(evt);
|
|
237
|
+
var vertex = this.paper.snapToGrid(normalizedEvent.clientX, normalizedEvent.clientY).toJSON();
|
|
238
|
+
var relatedView = this.relatedView;
|
|
239
|
+
relatedView.model.startBatch('vertex-add', { ui: true, tool: this.cid });
|
|
240
|
+
var index = relatedView.getVertexIndex(vertex.x, vertex.y);
|
|
241
|
+
this.snapVertex(vertex, index);
|
|
242
|
+
relatedView.model.insertVertex(index, vertex, { ui: true, tool: this.cid });
|
|
243
|
+
this.update();
|
|
244
|
+
var handle = this.handles[index];
|
|
245
|
+
this.eventData(normalizedEvent, { vertexAdded: true });
|
|
246
|
+
handle.onPointerDown(normalizedEvent);
|
|
247
|
+
},
|
|
248
|
+
onRemove: function() {
|
|
249
|
+
this.resetHandles();
|
|
250
|
+
}
|
|
251
|
+
}, {
|
|
252
|
+
VertexHandle: VertexHandle // keep as class property
|
|
253
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as connectionStrategies from '../connectionStrategies/index.mjs';
|
|
2
|
+
|
|
3
|
+
export function getViewBBox(view, useModelGeometry) {
|
|
4
|
+
const { model } = view;
|
|
5
|
+
if (useModelGeometry) return model.getBBox();
|
|
6
|
+
return (model.isLink()) ? view.getConnection().bbox() : view.getNodeUnrotatedBBox(view.el);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getAnchor(coords, view, magnet) {
|
|
10
|
+
// take advantage of an existing logic inside of the
|
|
11
|
+
// pin relative connection strategy
|
|
12
|
+
var end = connectionStrategies.pinRelative.call(
|
|
13
|
+
this.paper,
|
|
14
|
+
{},
|
|
15
|
+
view,
|
|
16
|
+
magnet,
|
|
17
|
+
coords,
|
|
18
|
+
this.model
|
|
19
|
+
);
|
|
20
|
+
return end.anchor;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function snapAnchor(coords, view, magnet, type, relatedView, toolView) {
|
|
24
|
+
var snapRadius = toolView.options.snapRadius;
|
|
25
|
+
var isSource = (type === 'source');
|
|
26
|
+
var refIndex = (isSource ? 0 : -1);
|
|
27
|
+
var ref = this.model.vertex(refIndex) || this.getEndAnchor(isSource ? 'target' : 'source');
|
|
28
|
+
if (ref) {
|
|
29
|
+
if (Math.abs(ref.x - coords.x) < snapRadius) coords.x = ref.x;
|
|
30
|
+
if (Math.abs(ref.y - coords.y) < snapRadius) coords.y = ref.y;
|
|
31
|
+
}
|
|
32
|
+
return coords;
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './Vertices.mjs';
|
|
2
|
+
export * from './Segments.mjs';
|
|
3
|
+
export * from './Arrowhead.mjs';
|
|
4
|
+
export * from './Boundary.mjs';
|
|
5
|
+
export * from './Anchor.mjs';
|
|
6
|
+
export * from './Button.mjs';
|
|
7
|
+
export * from './Connect.mjs';
|
|
8
|
+
export * from './HoverConnect.mjs';
|