@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,220 @@
|
|
|
1
|
+
import V from '../V/index.mjs';
|
|
2
|
+
import { HighlighterView } from '../dia/HighlighterView.mjs';
|
|
3
|
+
|
|
4
|
+
const MASK_CLIP = 20;
|
|
5
|
+
|
|
6
|
+
function forEachDescendant(vel, fn) {
|
|
7
|
+
const descendants = vel.children();
|
|
8
|
+
while (descendants.length > 0) {
|
|
9
|
+
const descendant = descendants.shift();
|
|
10
|
+
if (fn(descendant)) {
|
|
11
|
+
descendants.push(...descendant.children());
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const mask = HighlighterView.extend({
|
|
17
|
+
|
|
18
|
+
tagName: 'rect',
|
|
19
|
+
className: 'highlight-mask',
|
|
20
|
+
attributes: {
|
|
21
|
+
'pointer-events': 'none'
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
options: {
|
|
25
|
+
padding: 3,
|
|
26
|
+
maskClip: MASK_CLIP,
|
|
27
|
+
deep: false,
|
|
28
|
+
attrs: {
|
|
29
|
+
'stroke': '#FEB663',
|
|
30
|
+
'stroke-width': 3,
|
|
31
|
+
'stroke-linecap': 'butt',
|
|
32
|
+
'stroke-linejoin': 'miter',
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
VISIBLE: 'white',
|
|
37
|
+
INVISIBLE: 'black',
|
|
38
|
+
|
|
39
|
+
MASK_ROOT_ATTRIBUTE_BLACKLIST: [
|
|
40
|
+
'marker-start',
|
|
41
|
+
'marker-end',
|
|
42
|
+
'marker-mid',
|
|
43
|
+
'transform',
|
|
44
|
+
'stroke-dasharray',
|
|
45
|
+
'class',
|
|
46
|
+
],
|
|
47
|
+
|
|
48
|
+
MASK_CHILD_ATTRIBUTE_BLACKLIST: [
|
|
49
|
+
'stroke',
|
|
50
|
+
'fill',
|
|
51
|
+
'stroke-width',
|
|
52
|
+
'stroke-opacity',
|
|
53
|
+
'stroke-dasharray',
|
|
54
|
+
'fill-opacity',
|
|
55
|
+
'marker-start',
|
|
56
|
+
'marker-end',
|
|
57
|
+
'marker-mid',
|
|
58
|
+
'class',
|
|
59
|
+
],
|
|
60
|
+
|
|
61
|
+
// TODO: change the list to a function callback
|
|
62
|
+
MASK_REPLACE_TAGS: [
|
|
63
|
+
'FOREIGNOBJECT',
|
|
64
|
+
'IMAGE',
|
|
65
|
+
'USE',
|
|
66
|
+
'TEXT',
|
|
67
|
+
'TSPAN',
|
|
68
|
+
'TEXTPATH'
|
|
69
|
+
],
|
|
70
|
+
|
|
71
|
+
// TODO: change the list to a function callback
|
|
72
|
+
MASK_REMOVE_TAGS: [
|
|
73
|
+
'TEXT',
|
|
74
|
+
'TSPAN',
|
|
75
|
+
'TEXTPATH'
|
|
76
|
+
],
|
|
77
|
+
|
|
78
|
+
transformMaskChild(cellView, childEl) {
|
|
79
|
+
const {
|
|
80
|
+
MASK_CHILD_ATTRIBUTE_BLACKLIST,
|
|
81
|
+
MASK_REPLACE_TAGS,
|
|
82
|
+
MASK_REMOVE_TAGS
|
|
83
|
+
} = this;
|
|
84
|
+
const childTagName = childEl.tagName();
|
|
85
|
+
// Do not include the element in the mask's image
|
|
86
|
+
if (!V.isSVGGraphicsElement(childEl) || MASK_REMOVE_TAGS.includes(childTagName)) {
|
|
87
|
+
childEl.remove();
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
// Replace the element with a rectangle
|
|
91
|
+
if (MASK_REPLACE_TAGS.includes(childTagName)) {
|
|
92
|
+
// Note: clone() method does not change the children ids
|
|
93
|
+
const originalChild = cellView.vel.findOne(`#${childEl.id}`);
|
|
94
|
+
if (originalChild) {
|
|
95
|
+
const { node: originalNode } = originalChild;
|
|
96
|
+
let childBBox = cellView.getNodeBoundingRect(originalNode);
|
|
97
|
+
if (cellView.model.isElement()) {
|
|
98
|
+
childBBox = V.transformRect(childBBox, cellView.getNodeMatrix(originalNode));
|
|
99
|
+
}
|
|
100
|
+
const replacement = V('rect', childBBox.toJSON());
|
|
101
|
+
const { x: ox, y: oy } = childBBox.center();
|
|
102
|
+
const { angle, cx = ox, cy = oy } = originalChild.rotate();
|
|
103
|
+
if (angle) replacement.rotate(angle, cx, cy);
|
|
104
|
+
// Note: it's not important to keep the same sibling index since all subnodes are filled
|
|
105
|
+
childEl.parent().append(replacement);
|
|
106
|
+
}
|
|
107
|
+
childEl.remove();
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
// Keep the element, but clean it from certain attributes
|
|
111
|
+
MASK_CHILD_ATTRIBUTE_BLACKLIST.forEach(attrName => {
|
|
112
|
+
if (attrName === 'fill' && childEl.attr('fill') === 'none') return;
|
|
113
|
+
childEl.removeAttr(attrName);
|
|
114
|
+
});
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
transformMaskRoot(_cellView, rootEl) {
|
|
119
|
+
const { MASK_ROOT_ATTRIBUTE_BLACKLIST } = this;
|
|
120
|
+
MASK_ROOT_ATTRIBUTE_BLACKLIST.forEach(attrName => {
|
|
121
|
+
rootEl.removeAttr(attrName);
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
getMaskShape(cellView, vel) {
|
|
126
|
+
const { options, MASK_REPLACE_TAGS } = this;
|
|
127
|
+
const { deep } = options;
|
|
128
|
+
const tagName = vel.tagName();
|
|
129
|
+
let maskRoot;
|
|
130
|
+
if (tagName === 'G') {
|
|
131
|
+
if (!deep) return null;
|
|
132
|
+
maskRoot = vel.clone();
|
|
133
|
+
forEachDescendant(maskRoot, maskChild => this.transformMaskChild(cellView, maskChild));
|
|
134
|
+
} else {
|
|
135
|
+
if (MASK_REPLACE_TAGS.includes(tagName)) return null;
|
|
136
|
+
maskRoot = vel.clone();
|
|
137
|
+
}
|
|
138
|
+
this.transformMaskRoot(cellView, maskRoot);
|
|
139
|
+
return maskRoot;
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
getMaskId() {
|
|
143
|
+
return `highlight-mask-${this.cid}`;
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
getMask(cellView, vNode) {
|
|
147
|
+
|
|
148
|
+
const { VISIBLE, INVISIBLE, options } = this;
|
|
149
|
+
const { padding, attrs } = options;
|
|
150
|
+
// support both `strokeWidth` and `stroke-width` attribute names
|
|
151
|
+
const strokeWidth = parseFloat(V('g').attr(attrs).attr('stroke-width'));
|
|
152
|
+
const hasNodeFill = vNode.attr('fill') !== 'none';
|
|
153
|
+
let magnetStrokeWidth = parseFloat(vNode.attr('stroke-width'));
|
|
154
|
+
if (isNaN(magnetStrokeWidth)) magnetStrokeWidth = 1;
|
|
155
|
+
// stroke of the invisible shape
|
|
156
|
+
const minStrokeWidth = magnetStrokeWidth + padding * 2;
|
|
157
|
+
// stroke of the visible shape
|
|
158
|
+
const maxStrokeWidth = minStrokeWidth + strokeWidth * 2;
|
|
159
|
+
let maskEl = this.getMaskShape(cellView, vNode);
|
|
160
|
+
if (!maskEl) {
|
|
161
|
+
const nodeBBox = cellView.getNodeBoundingRect(vNode.node);
|
|
162
|
+
// Make sure the rect is visible
|
|
163
|
+
nodeBBox.inflate(nodeBBox.width ? 0 : 0.5, nodeBBox.height ? 0 : 0.5);
|
|
164
|
+
maskEl = V('rect', nodeBBox.toJSON());
|
|
165
|
+
}
|
|
166
|
+
maskEl.attr(attrs);
|
|
167
|
+
return V('mask', {
|
|
168
|
+
'id': this.getMaskId()
|
|
169
|
+
}).append([
|
|
170
|
+
maskEl.clone().attr({
|
|
171
|
+
'fill': hasNodeFill ? VISIBLE : 'none',
|
|
172
|
+
'stroke': VISIBLE,
|
|
173
|
+
'stroke-width': maxStrokeWidth
|
|
174
|
+
}),
|
|
175
|
+
maskEl.clone().attr({
|
|
176
|
+
'fill': hasNodeFill ? INVISIBLE : 'none',
|
|
177
|
+
'stroke': INVISIBLE,
|
|
178
|
+
'stroke-width': minStrokeWidth
|
|
179
|
+
})
|
|
180
|
+
]);
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
removeMask(paper) {
|
|
184
|
+
const maskNode = paper.svg.getElementById(this.getMaskId());
|
|
185
|
+
if (maskNode) {
|
|
186
|
+
paper.defs.removeChild(maskNode);
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
addMask(paper, maskEl) {
|
|
191
|
+
paper.defs.appendChild(maskEl.node);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
highlight(cellView, node) {
|
|
195
|
+
const { options, vel } = this;
|
|
196
|
+
const { padding, attrs, maskClip = MASK_CLIP, layer } = options;
|
|
197
|
+
const color = ('stroke' in attrs) ? attrs['stroke'] : '#000000';
|
|
198
|
+
if (!layer && node === cellView.el) {
|
|
199
|
+
// If the highlighter is appended to the cellView
|
|
200
|
+
// and we measure the size of the cellView wrapping group
|
|
201
|
+
// it's necessary to remove the highlighter first
|
|
202
|
+
vel.remove();
|
|
203
|
+
}
|
|
204
|
+
const highlighterBBox = cellView.getNodeBoundingRect(node).inflate(padding + maskClip);
|
|
205
|
+
const highlightMatrix = this.getNodeMatrix(cellView, node);
|
|
206
|
+
const maskEl = this.getMask(cellView, V(node));
|
|
207
|
+
this.addMask(cellView.paper, maskEl);
|
|
208
|
+
vel.attr(highlighterBBox.toJSON());
|
|
209
|
+
vel.attr({
|
|
210
|
+
'transform': V.matrixToTransformString(highlightMatrix),
|
|
211
|
+
'mask': `url(#${maskEl.id})`,
|
|
212
|
+
'fill': color
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
unhighlight(cellView) {
|
|
217
|
+
this.removeMask(cellView.paper);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { HighlighterView } from '../dia/HighlighterView.mjs';
|
|
2
|
+
|
|
3
|
+
export const opacity = HighlighterView.extend({
|
|
4
|
+
|
|
5
|
+
UPDATABLE: false,
|
|
6
|
+
MOUNTABLE: false,
|
|
7
|
+
|
|
8
|
+
highlight: function(_cellView, node) {
|
|
9
|
+
const { alphaValue = 0.3 } = this.options;
|
|
10
|
+
node.style.opacity = alphaValue;
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
unhighlight: function(_cellView, node) {
|
|
14
|
+
node.style.opacity = '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { assign } from '../util/index.mjs';
|
|
2
|
+
import V from '../V/index.mjs';
|
|
3
|
+
import { HighlighterView } from '../dia/HighlighterView.mjs';
|
|
4
|
+
|
|
5
|
+
export const stroke = HighlighterView.extend({
|
|
6
|
+
|
|
7
|
+
tagName: 'path',
|
|
8
|
+
className: 'highlight-stroke',
|
|
9
|
+
attributes: {
|
|
10
|
+
'pointer-events': 'none',
|
|
11
|
+
'fill': 'none'
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
options: {
|
|
15
|
+
padding: 3,
|
|
16
|
+
rx: 0,
|
|
17
|
+
ry: 0,
|
|
18
|
+
useFirstSubpath: false,
|
|
19
|
+
attrs: {
|
|
20
|
+
'stroke-width': 3,
|
|
21
|
+
'stroke': '#FEB663'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
getPathData(cellView, node) {
|
|
26
|
+
const { options } = this;
|
|
27
|
+
const { useFirstSubpath } = options;
|
|
28
|
+
let d;
|
|
29
|
+
try {
|
|
30
|
+
const vNode = V(node);
|
|
31
|
+
d = vNode.convertToPathData().trim();
|
|
32
|
+
if (vNode.tagName() === 'PATH' && useFirstSubpath) {
|
|
33
|
+
const secondSubpathIndex = d.search(/.M/i) + 1;
|
|
34
|
+
if (secondSubpathIndex > 0) {
|
|
35
|
+
d = d.substr(0, secondSubpathIndex);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Failed to get path data from magnet element.
|
|
40
|
+
// Draw a rectangle around the node instead.
|
|
41
|
+
const nodeBBox = cellView.getNodeBoundingRect(node);
|
|
42
|
+
d = V.rectToPath(assign({}, options, nodeBBox.toJSON()));
|
|
43
|
+
}
|
|
44
|
+
return d;
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
highlightConnection(cellView) {
|
|
48
|
+
this.vel.attr('d', cellView.getSerializedConnection());
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
highlightNode(cellView, node) {
|
|
52
|
+
const { vel, options } = this;
|
|
53
|
+
const { padding, layer } = options;
|
|
54
|
+
let highlightMatrix = this.getNodeMatrix(cellView, node);
|
|
55
|
+
// Add padding to the highlight element.
|
|
56
|
+
if (padding) {
|
|
57
|
+
if (!layer && node === cellView.el) {
|
|
58
|
+
// If the highlighter is appended to the cellView
|
|
59
|
+
// and we measure the size of the cellView wrapping group
|
|
60
|
+
// it's necessary to remove the highlighter first
|
|
61
|
+
vel.remove();
|
|
62
|
+
}
|
|
63
|
+
let nodeBBox = cellView.getNodeBoundingRect(node);
|
|
64
|
+
const cx = nodeBBox.x + (nodeBBox.width / 2);
|
|
65
|
+
const cy = nodeBBox.y + (nodeBBox.height / 2);
|
|
66
|
+
nodeBBox = V.transformRect(nodeBBox, highlightMatrix);
|
|
67
|
+
const width = Math.max(nodeBBox.width, 1);
|
|
68
|
+
const height = Math.max(nodeBBox.height, 1);
|
|
69
|
+
const sx = (width + padding) / width;
|
|
70
|
+
const sy = (height + padding) / height;
|
|
71
|
+
const paddingMatrix = V.createSVGMatrix({
|
|
72
|
+
a: sx,
|
|
73
|
+
b: 0,
|
|
74
|
+
c: 0,
|
|
75
|
+
d: sy,
|
|
76
|
+
e: cx - sx * cx,
|
|
77
|
+
f: cy - sy * cy
|
|
78
|
+
});
|
|
79
|
+
highlightMatrix = highlightMatrix.multiply(paddingMatrix);
|
|
80
|
+
}
|
|
81
|
+
vel.attr({
|
|
82
|
+
'd': this.getPathData(cellView, node),
|
|
83
|
+
'transform': V.matrixToTransformString(highlightMatrix)
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
highlight(cellView, node) {
|
|
88
|
+
const { vel, options } = this;
|
|
89
|
+
vel.attr(options.attrs);
|
|
90
|
+
if (options.nonScalingStroke) {
|
|
91
|
+
vel.attr('vector-effect', 'non-scaling-stroke');
|
|
92
|
+
}
|
|
93
|
+
if (cellView.isNodeConnection(node)) {
|
|
94
|
+
this.highlightConnection(cellView);
|
|
95
|
+
} else {
|
|
96
|
+
this.highlightNode(cellView, node);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { evalCalcAttribute, isCalcAttribute } from '../../dia/attributes/calc.mjs';
|
|
2
|
+
import * as g from '../../g/index.mjs';
|
|
3
|
+
import * as util from '../../util/index.mjs';
|
|
4
|
+
|
|
5
|
+
function portTransformAttrs(point, angle, opt) {
|
|
6
|
+
|
|
7
|
+
var trans = point.toJSON();
|
|
8
|
+
|
|
9
|
+
trans.angle = angle || 0;
|
|
10
|
+
|
|
11
|
+
return util.defaults({}, opt, trans);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function lineLayout(ports, p1, p2, elBBox) {
|
|
15
|
+
return ports.map(function(port, index, ports) {
|
|
16
|
+
var p = this.pointAt(((index + 0.5) / ports.length));
|
|
17
|
+
// `dx`,`dy` per port offset option
|
|
18
|
+
if (port.dx || port.dy) {
|
|
19
|
+
p.offset(port.dx || 0, port.dy || 0);
|
|
20
|
+
}
|
|
21
|
+
return portTransformAttrs(p.round(), 0, argTransform(elBBox, port));
|
|
22
|
+
}, g.line(p1, p2));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ellipseLayout(ports, elBBox, startAngle, stepFn) {
|
|
26
|
+
|
|
27
|
+
var center = elBBox.center();
|
|
28
|
+
var ratio = elBBox.width / elBBox.height;
|
|
29
|
+
var p1 = elBBox.topMiddle();
|
|
30
|
+
|
|
31
|
+
var ellipse = g.Ellipse.fromRect(elBBox);
|
|
32
|
+
|
|
33
|
+
return ports.map(function(port, index, ports) {
|
|
34
|
+
|
|
35
|
+
var angle = startAngle + stepFn(index, ports.length);
|
|
36
|
+
var p2 = p1.clone()
|
|
37
|
+
.rotate(center, -angle)
|
|
38
|
+
.scale(ratio, 1, center);
|
|
39
|
+
|
|
40
|
+
var theta = port.compensateRotation ? -ellipse.tangentTheta(p2) : 0;
|
|
41
|
+
|
|
42
|
+
// `dx`,`dy` per port offset option
|
|
43
|
+
if (port.dx || port.dy) {
|
|
44
|
+
p2.offset(port.dx || 0, port.dy || 0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// `dr` delta radius option
|
|
48
|
+
if (port.dr) {
|
|
49
|
+
p2.move(center, port.dr);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return portTransformAttrs(p2.round(), theta, argTransform(elBBox, port));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
function argTransform(bbox, args) {
|
|
58
|
+
let { x, y, angle } = args;
|
|
59
|
+
if (util.isPercentage(x)) {
|
|
60
|
+
x = parseFloat(x) / 100 * bbox.width;
|
|
61
|
+
} else if (isCalcAttribute(x)) {
|
|
62
|
+
x = Number(evalCalcAttribute(x, bbox));
|
|
63
|
+
}
|
|
64
|
+
if (util.isPercentage(y)) {
|
|
65
|
+
y = parseFloat(y) / 100 * bbox.height;
|
|
66
|
+
} else if (isCalcAttribute(y)) {
|
|
67
|
+
y = Number(evalCalcAttribute(y, bbox));
|
|
68
|
+
}
|
|
69
|
+
return { x, y, angle };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Creates a point stored in arguments
|
|
73
|
+
function argPoint(bbox, args) {
|
|
74
|
+
const { x, y } = argTransform(bbox, args);
|
|
75
|
+
return new g.Point(x || 0, y || 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {Array<Object>} ports
|
|
81
|
+
* @param {g.Rect} elBBox
|
|
82
|
+
* @param {Object=} opt opt Group options
|
|
83
|
+
* @returns {Array<g.Point>}
|
|
84
|
+
*/
|
|
85
|
+
export const absolute = function(ports, elBBox) {
|
|
86
|
+
return ports.map(port => {
|
|
87
|
+
const transformation = argPoint(elBBox, port).round().toJSON();
|
|
88
|
+
transformation.angle = port.angle || 0;
|
|
89
|
+
return transformation;
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Array<Object>} ports
|
|
95
|
+
* @param {g.Rect} elBBox
|
|
96
|
+
* @param {Object=} opt opt Group options
|
|
97
|
+
* @returns {Array<g.Point>}
|
|
98
|
+
*/
|
|
99
|
+
export const fn = function(ports, elBBox, opt) {
|
|
100
|
+
return opt.fn(ports, elBBox, opt);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param {Array<Object>} ports
|
|
105
|
+
* @param {g.Rect} elBBox
|
|
106
|
+
* @param {Object=} opt opt Group options
|
|
107
|
+
* @returns {Array<g.Point>}
|
|
108
|
+
*/
|
|
109
|
+
export const line = function(ports, elBBox, opt) {
|
|
110
|
+
|
|
111
|
+
var start = argPoint(elBBox, opt.start || elBBox.origin());
|
|
112
|
+
var end = argPoint(elBBox, opt.end || elBBox.corner());
|
|
113
|
+
|
|
114
|
+
return lineLayout(ports, start, end, elBBox);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {Array<Object>} ports
|
|
119
|
+
* @param {g.Rect} elBBox
|
|
120
|
+
* @param {Object=} opt opt Group options
|
|
121
|
+
* @returns {Array<g.Point>}
|
|
122
|
+
*/
|
|
123
|
+
export const left = function(ports, elBBox, opt) {
|
|
124
|
+
return lineLayout(ports, elBBox.origin(), elBBox.bottomLeft(), elBBox);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @param {Array<Object>} ports
|
|
129
|
+
* @param {g.Rect} elBBox
|
|
130
|
+
* @param {Object=} opt opt Group options
|
|
131
|
+
* @returns {Array<g.Point>}
|
|
132
|
+
*/
|
|
133
|
+
export const right = function(ports, elBBox, opt) {
|
|
134
|
+
return lineLayout(ports, elBBox.topRight(), elBBox.corner(), elBBox);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {Array<Object>} ports
|
|
139
|
+
* @param {g.Rect} elBBox
|
|
140
|
+
* @param {Object=} opt opt Group options
|
|
141
|
+
* @returns {Array<g.Point>}
|
|
142
|
+
*/
|
|
143
|
+
export const top = function(ports, elBBox, opt) {
|
|
144
|
+
return lineLayout(ports, elBBox.origin(), elBBox.topRight(), elBBox);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @param {Array<Object>} ports
|
|
149
|
+
* @param {g.Rect} elBBox
|
|
150
|
+
* @param {Object=} opt opt Group options
|
|
151
|
+
* @returns {Array<g.Point>}
|
|
152
|
+
*/
|
|
153
|
+
export const bottom = function(ports, elBBox, opt) {
|
|
154
|
+
return lineLayout(ports, elBBox.bottomLeft(), elBBox.corner(), elBBox);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param {Array<Object>} ports
|
|
159
|
+
* @param {g.Rect} elBBox
|
|
160
|
+
* @param {Object=} opt Group options
|
|
161
|
+
* @returns {Array<g.Point>}
|
|
162
|
+
*/
|
|
163
|
+
export const ellipseSpread = function(ports, elBBox, opt) {
|
|
164
|
+
|
|
165
|
+
var startAngle = opt.startAngle || 0;
|
|
166
|
+
var stepAngle = opt.step || 360 / ports.length;
|
|
167
|
+
|
|
168
|
+
return ellipseLayout(ports, elBBox, startAngle, function(index) {
|
|
169
|
+
return index * stepAngle;
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {Array<Object>} ports
|
|
175
|
+
* @param {g.Rect} elBBox
|
|
176
|
+
* @param {Object=} opt Group options
|
|
177
|
+
* @returns {Array<g.Point>}
|
|
178
|
+
*/
|
|
179
|
+
export const ellipse = function(ports, elBBox, opt) {
|
|
180
|
+
|
|
181
|
+
var startAngle = opt.startAngle || 0;
|
|
182
|
+
var stepAngle = opt.step || 20;
|
|
183
|
+
|
|
184
|
+
return ellipseLayout(ports, elBBox, startAngle, function(index, count) {
|
|
185
|
+
return (index + 0.5 - count / 2) * stepAngle;
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
|