@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,148 @@
|
|
|
1
|
+
import { Point } from '../../g/index.mjs';
|
|
2
|
+
import { isPercentage } from '../../util/util.mjs';
|
|
3
|
+
|
|
4
|
+
function positionWrapper(axis, dimension, origin) {
|
|
5
|
+
return function(value, refBBox) {
|
|
6
|
+
var valuePercentage = isPercentage(value);
|
|
7
|
+
value = parseFloat(value);
|
|
8
|
+
if (valuePercentage) {
|
|
9
|
+
value /= 100;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var delta;
|
|
13
|
+
if (isFinite(value)) {
|
|
14
|
+
var refOrigin = refBBox[origin]();
|
|
15
|
+
if (valuePercentage || value > 0 && value < 1) {
|
|
16
|
+
delta = refOrigin[axis] + refBBox[dimension] * value;
|
|
17
|
+
} else {
|
|
18
|
+
delta = refOrigin[axis] + value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
var point = Point();
|
|
23
|
+
point[axis] = delta || 0;
|
|
24
|
+
return point;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function setWrapper(attrName, dimension) {
|
|
29
|
+
return function(value, refBBox) {
|
|
30
|
+
var isValuePercentage = isPercentage(value);
|
|
31
|
+
value = parseFloat(value);
|
|
32
|
+
if (isValuePercentage) {
|
|
33
|
+
value /= 100;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var attrs = {};
|
|
37
|
+
if (isFinite(value)) {
|
|
38
|
+
var attrValue = (isValuePercentage || value >= 0 && value <= 1)
|
|
39
|
+
? value * refBBox[dimension]
|
|
40
|
+
: Math.max(value + refBBox[dimension], 0);
|
|
41
|
+
attrs[attrName] = attrValue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return attrs;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const legacyAttributesNS = {
|
|
49
|
+
|
|
50
|
+
// if `refX` is in [0, 1] then `refX` is a fraction of bounding box width
|
|
51
|
+
// if `refX` is < 0 then `refX`'s absolute values is the right coordinate of the bounding box
|
|
52
|
+
// otherwise, `refX` is the left coordinate of the bounding box
|
|
53
|
+
'ref-x': {
|
|
54
|
+
position: positionWrapper('x', 'width', 'origin')
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
'ref-y': {
|
|
58
|
+
position: positionWrapper('y', 'height', 'origin')
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// `ref-dx` and `ref-dy` define the offset of the sub-element relative to the right and/or bottom
|
|
62
|
+
// coordinate of the reference element.
|
|
63
|
+
|
|
64
|
+
'ref-dx': {
|
|
65
|
+
position: positionWrapper('x', 'width', 'corner')
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
'ref-dy': {
|
|
69
|
+
position: positionWrapper('y', 'height', 'corner')
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// 'ref-width'/'ref-height' defines the width/height of the sub-element relatively to
|
|
73
|
+
// the reference element size
|
|
74
|
+
// val in 0..1 ref-width = 0.75 sets the width to 75% of the ref. el. width
|
|
75
|
+
// val < 0 || val > 1 ref-height = -20 sets the height to the ref. el. height shorter by 20
|
|
76
|
+
|
|
77
|
+
'ref-width': {
|
|
78
|
+
set: setWrapper('width', 'width')
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
'ref-height': {
|
|
82
|
+
set: setWrapper('height', 'height')
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
'ref-rx': {
|
|
86
|
+
set: setWrapper('rx', 'width')
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
'ref-ry': {
|
|
90
|
+
set: setWrapper('ry', 'height')
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
'ref-cx': {
|
|
94
|
+
set: setWrapper('cx', 'width')
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
'ref-cy': {
|
|
98
|
+
set: setWrapper('cy', 'height')
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
'ref-r-inscribed': {
|
|
102
|
+
set: (function(attrName) {
|
|
103
|
+
var widthFn = setWrapper(attrName, 'width');
|
|
104
|
+
var heightFn = setWrapper(attrName, 'height');
|
|
105
|
+
return function(value, refBBox) {
|
|
106
|
+
var fn = (refBBox.height > refBBox.width) ? widthFn : heightFn;
|
|
107
|
+
return fn(value, refBBox);
|
|
108
|
+
};
|
|
109
|
+
})('r')
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
'ref-r-circumscribed': {
|
|
113
|
+
set: function(value, refBBox) {
|
|
114
|
+
var isValuePercentage = isPercentage(value);
|
|
115
|
+
value = parseFloat(value);
|
|
116
|
+
if (isValuePercentage) {
|
|
117
|
+
value /= 100;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var diagonalLength = Math.sqrt((refBBox.height * refBBox.height) + (refBBox.width * refBBox.width));
|
|
121
|
+
|
|
122
|
+
var rValue;
|
|
123
|
+
if (isFinite(value)) {
|
|
124
|
+
if (isValuePercentage || value >= 0 && value <= 1) rValue = value * diagonalLength;
|
|
125
|
+
else rValue = Math.max(value + diagonalLength, 0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { r: rValue };
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// NOTE: refX & refY are SVG attributes that define the reference point of the marker.
|
|
134
|
+
// That's why we need to define both variants: `refX` and `ref-x` (and `refY` and `ref-y`).
|
|
135
|
+
legacyAttributesNS['refX'] = legacyAttributesNS['ref-x'];
|
|
136
|
+
legacyAttributesNS['refY'] = legacyAttributesNS['ref-y'];
|
|
137
|
+
|
|
138
|
+
// This allows to combine both absolute and relative positioning
|
|
139
|
+
// refX: 50%, refX2: 20
|
|
140
|
+
legacyAttributesNS['ref-x2'] = legacyAttributesNS['ref-x'];
|
|
141
|
+
legacyAttributesNS['ref-y2'] = legacyAttributesNS['ref-y'];
|
|
142
|
+
legacyAttributesNS['ref-width2'] = legacyAttributesNS['ref-width'];
|
|
143
|
+
legacyAttributesNS['ref-height2'] = legacyAttributesNS['ref-height'];
|
|
144
|
+
|
|
145
|
+
// Aliases
|
|
146
|
+
legacyAttributesNS['ref-r'] = legacyAttributesNS['ref-r-inscribed'];
|
|
147
|
+
|
|
148
|
+
export default legacyAttributesNS;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
// Offset attributes require the cell view to be rendered before they can be applied
|
|
3
|
+
// (they must be appended to the DOM).
|
|
4
|
+
|
|
5
|
+
import { Point } from '../../g/index.mjs';
|
|
6
|
+
import { isPercentage } from '../../util/util.mjs';
|
|
7
|
+
|
|
8
|
+
function offsetWrapper(axis, dimension, corner) {
|
|
9
|
+
return function(value, nodeBBox) {
|
|
10
|
+
var delta;
|
|
11
|
+
if (value === 'middle') {
|
|
12
|
+
delta = nodeBBox[dimension] / 2;
|
|
13
|
+
} else if (value === corner) {
|
|
14
|
+
delta = nodeBBox[dimension];
|
|
15
|
+
} else if (isFinite(value)) {
|
|
16
|
+
// TODO: or not to do a breaking change?
|
|
17
|
+
delta = (value > -1 && value < 1) ? (-nodeBBox[dimension] * value) : -value;
|
|
18
|
+
} else if (isPercentage(value)) {
|
|
19
|
+
delta = nodeBBox[dimension] * parseFloat(value) / 100;
|
|
20
|
+
} else {
|
|
21
|
+
delta = 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var point = new Point();
|
|
25
|
+
point[axis] = -(nodeBBox[axis] + delta);
|
|
26
|
+
return point;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const offsetAttributesNS = {
|
|
31
|
+
|
|
32
|
+
// `x-alignment` when set to `middle` causes centering of the sub-element around its new x coordinate.
|
|
33
|
+
// `x-alignment` when set to `right` uses the x coordinate as referenced to the right of the bbox.
|
|
34
|
+
'x-alignment': {
|
|
35
|
+
offset: offsetWrapper('x', 'width', 'right')
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// `y-alignment` when set to `middle` causes centering of the sub-element around its new y coordinate.
|
|
39
|
+
// `y-alignment` when set to `bottom` uses the y coordinate as referenced to the bottom of the bbox.
|
|
40
|
+
'y-alignment': {
|
|
41
|
+
offset: offsetWrapper('y', 'height', 'bottom')
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
'reset-offset': {
|
|
45
|
+
offset: function(val, nodeBBox) {
|
|
46
|
+
return (val)
|
|
47
|
+
? { x: -nodeBBox.x, y: -nodeBBox.y }
|
|
48
|
+
: { x: 0, y: 0 };
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default offsetAttributesNS;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isPlainObject } from '../../util/util.mjs';
|
|
2
|
+
|
|
3
|
+
const validPropertiesList = ['checked', 'selected', 'disabled', 'readOnly', 'contentEditable', 'value', 'indeterminate'];
|
|
4
|
+
|
|
5
|
+
const validProperties = validPropertiesList.reduce((acc, key) => {
|
|
6
|
+
acc[key] = true;
|
|
7
|
+
return acc;
|
|
8
|
+
}, {});
|
|
9
|
+
|
|
10
|
+
const props = {
|
|
11
|
+
qualify: function(properties) {
|
|
12
|
+
return isPlainObject(properties);
|
|
13
|
+
},
|
|
14
|
+
set: function(properties, _, node) {
|
|
15
|
+
Object.keys(properties).forEach(function(key) {
|
|
16
|
+
if (validProperties[key] && key in node) {
|
|
17
|
+
const value = properties[key];
|
|
18
|
+
if (node.tagName === 'SELECT' && Array.isArray(value)) {
|
|
19
|
+
Array.from(node.options).forEach(function(option, index) {
|
|
20
|
+
option.selected = value.includes(option.value);
|
|
21
|
+
});
|
|
22
|
+
} else {
|
|
23
|
+
node[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default props;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Path, Polyline } from '../../g/index.mjs';
|
|
2
|
+
import $ from '../../mvc/Dom/index.mjs';
|
|
3
|
+
import V from '../../V/index.mjs';
|
|
4
|
+
|
|
5
|
+
function shapeWrapper(shapeConstructor, opt) {
|
|
6
|
+
var cacheName = 'joint-shape';
|
|
7
|
+
var resetOffset = opt && opt.resetOffset;
|
|
8
|
+
return function(value, refBBox, node) {
|
|
9
|
+
var cache = $.data.get(node, cacheName);
|
|
10
|
+
if (!cache || cache.value !== value) {
|
|
11
|
+
// only recalculate if value has changed
|
|
12
|
+
var cachedShape = shapeConstructor(value);
|
|
13
|
+
cache = {
|
|
14
|
+
value: value,
|
|
15
|
+
shape: cachedShape,
|
|
16
|
+
shapeBBox: cachedShape.bbox()
|
|
17
|
+
};
|
|
18
|
+
$.data.set(node, cacheName, cache);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var shape = cache.shape.clone();
|
|
22
|
+
var shapeBBox = cache.shapeBBox.clone();
|
|
23
|
+
var shapeOrigin = shapeBBox.origin();
|
|
24
|
+
var refOrigin = refBBox.origin();
|
|
25
|
+
|
|
26
|
+
shapeBBox.x = refOrigin.x;
|
|
27
|
+
shapeBBox.y = refOrigin.y;
|
|
28
|
+
|
|
29
|
+
var fitScale = refBBox.maxRectScaleToFit(shapeBBox, refOrigin);
|
|
30
|
+
// `maxRectScaleToFit` can give Infinity if width or height is 0
|
|
31
|
+
var sx = (shapeBBox.width === 0 || refBBox.width === 0) ? 1 : fitScale.sx;
|
|
32
|
+
var sy = (shapeBBox.height === 0 || refBBox.height === 0) ? 1 : fitScale.sy;
|
|
33
|
+
|
|
34
|
+
shape.scale(sx, sy, shapeOrigin);
|
|
35
|
+
if (resetOffset) {
|
|
36
|
+
shape.translate(-shapeOrigin.x, -shapeOrigin.y);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return shape;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// `d` attribute for SVGPaths
|
|
44
|
+
function dWrapper(opt) {
|
|
45
|
+
function pathConstructor(value) {
|
|
46
|
+
return new Path(V.normalizePathData(value));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var shape = shapeWrapper(pathConstructor, opt);
|
|
50
|
+
return function(value, refBBox, node) {
|
|
51
|
+
var path = shape(value, refBBox, node);
|
|
52
|
+
return {
|
|
53
|
+
d: path.serialize()
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// `points` attribute for SVGPolylines and SVGPolygons
|
|
59
|
+
function pointsWrapper(opt) {
|
|
60
|
+
var shape = shapeWrapper(Polyline, opt);
|
|
61
|
+
return function(value, refBBox, node) {
|
|
62
|
+
var polyline = shape(value, refBBox, node);
|
|
63
|
+
return {
|
|
64
|
+
points: polyline.serialize()
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const shapeAttributesNS = {
|
|
70
|
+
|
|
71
|
+
'ref-d-reset-offset': {
|
|
72
|
+
set: dWrapper({ resetOffset: true })
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
'ref-d-keep-offset': {
|
|
76
|
+
set: dWrapper({ resetOffset: false })
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
'ref-points-reset-offset': {
|
|
80
|
+
set: pointsWrapper({ resetOffset: true })
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
'ref-points-keep-offset': {
|
|
84
|
+
set: pointsWrapper({ resetOffset: false })
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Aliases
|
|
89
|
+
shapeAttributesNS['ref-d'] = shapeAttributesNS['ref-d-reset-offset'];
|
|
90
|
+
shapeAttributesNS['ref-points'] = shapeAttributesNS['ref-points-reset-offset'];
|
|
91
|
+
|
|
92
|
+
export default shapeAttributesNS;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { assign, isPlainObject, isObject, isPercentage, breakText } from '../../util/util.mjs';
|
|
2
|
+
import { isCalcAttribute, evalCalcAttribute } from './calc.mjs';
|
|
3
|
+
import $ from '../../mvc/Dom/index.mjs';
|
|
4
|
+
import V from '../../V/index.mjs';
|
|
5
|
+
|
|
6
|
+
function isTextInUse(_value, _node, attrs) {
|
|
7
|
+
return (attrs.text !== undefined);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const textAttributesNS = {
|
|
11
|
+
|
|
12
|
+
'line-height': {
|
|
13
|
+
qualify: isTextInUse
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
'text-vertical-anchor': {
|
|
17
|
+
qualify: isTextInUse
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
'text-path': {
|
|
21
|
+
qualify: isTextInUse
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
'annotations': {
|
|
25
|
+
qualify: isTextInUse
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
'eol': {
|
|
29
|
+
qualify: isTextInUse
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
'display-empty': {
|
|
33
|
+
qualify: isTextInUse
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'text': {
|
|
37
|
+
qualify: function(_text, _node, attrs) {
|
|
38
|
+
const textWrap = attrs['text-wrap'];
|
|
39
|
+
return !textWrap || !isPlainObject(textWrap);
|
|
40
|
+
},
|
|
41
|
+
set: function(text, refBBox, node, attrs) {
|
|
42
|
+
const cacheName = 'joint-text';
|
|
43
|
+
const cache = $.data.get(node, cacheName);
|
|
44
|
+
const lineHeight = attrs['line-height'];
|
|
45
|
+
const textVerticalAnchor = attrs['text-vertical-anchor'];
|
|
46
|
+
const displayEmpty = attrs['display-empty'];
|
|
47
|
+
const fontSize = attrs['font-size'];
|
|
48
|
+
const annotations = attrs.annotations;
|
|
49
|
+
const eol = attrs.eol;
|
|
50
|
+
const x = attrs.x;
|
|
51
|
+
let textPath = attrs['text-path'];
|
|
52
|
+
// Update the text only if there was a change in the string
|
|
53
|
+
// or any of its attributes.
|
|
54
|
+
const textHash = JSON.stringify([text, lineHeight, annotations, textVerticalAnchor, eol, displayEmpty, textPath, x, fontSize]);
|
|
55
|
+
if (cache === undefined || cache !== textHash) {
|
|
56
|
+
// Chrome bug:
|
|
57
|
+
// <tspan> positions defined as `em` are not updated
|
|
58
|
+
// when container `font-size` change.
|
|
59
|
+
if (fontSize) node.setAttribute('font-size', fontSize);
|
|
60
|
+
// Text Along Path Selector
|
|
61
|
+
if (isObject(textPath)) {
|
|
62
|
+
const pathSelector = textPath.selector;
|
|
63
|
+
if (typeof pathSelector === 'string') {
|
|
64
|
+
const pathNode = this.findNode(pathSelector);
|
|
65
|
+
if (pathNode instanceof SVGPathElement) {
|
|
66
|
+
textPath = assign({ 'xlink:href': '#' + pathNode.id }, textPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
V(node).text('' + text, {
|
|
71
|
+
lineHeight,
|
|
72
|
+
annotations,
|
|
73
|
+
textPath,
|
|
74
|
+
x,
|
|
75
|
+
textVerticalAnchor,
|
|
76
|
+
eol,
|
|
77
|
+
displayEmpty
|
|
78
|
+
});
|
|
79
|
+
$.data.set(node, cacheName, textHash);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
'text-wrap': {
|
|
85
|
+
qualify: isPlainObject,
|
|
86
|
+
set: function(value, refBBox, node, attrs) {
|
|
87
|
+
var size = {};
|
|
88
|
+
// option `width`
|
|
89
|
+
var width = value.width || 0;
|
|
90
|
+
if (isPercentage(width)) {
|
|
91
|
+
size.width = refBBox.width * parseFloat(width) / 100;
|
|
92
|
+
} else if (isCalcAttribute(width)) {
|
|
93
|
+
size.width = Number(evalCalcAttribute(width, refBBox));
|
|
94
|
+
} else {
|
|
95
|
+
if (value.width === null) {
|
|
96
|
+
// breakText() requires width to be specified.
|
|
97
|
+
size.width = Infinity;
|
|
98
|
+
} else if (width <= 0) {
|
|
99
|
+
size.width = refBBox.width + width;
|
|
100
|
+
} else {
|
|
101
|
+
size.width = width;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// option `height`
|
|
105
|
+
var height = value.height || 0;
|
|
106
|
+
if (isPercentage(height)) {
|
|
107
|
+
size.height = refBBox.height * parseFloat(height) / 100;
|
|
108
|
+
} else if (isCalcAttribute(height)) {
|
|
109
|
+
size.height = Number(evalCalcAttribute(height, refBBox));
|
|
110
|
+
} else {
|
|
111
|
+
if (value.height === null) {
|
|
112
|
+
// if height is not specified breakText() does not
|
|
113
|
+
// restrict the height of the text.
|
|
114
|
+
} else if (height <= 0) {
|
|
115
|
+
size.height = refBBox.height + height;
|
|
116
|
+
} else {
|
|
117
|
+
size.height = height;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// option `text`
|
|
121
|
+
var wrappedText;
|
|
122
|
+
var text = value.text;
|
|
123
|
+
if (text === undefined) text = attrs.text;
|
|
124
|
+
if (text !== undefined) {
|
|
125
|
+
const breakTextFn = value.breakText || breakText;
|
|
126
|
+
wrappedText = breakTextFn('' + text, size, {
|
|
127
|
+
'font-weight': attrs['font-weight'],
|
|
128
|
+
'font-size': attrs['font-size'],
|
|
129
|
+
'font-family': attrs['font-family'],
|
|
130
|
+
'lineHeight': attrs['line-height'],
|
|
131
|
+
'letter-spacing': attrs['letter-spacing']
|
|
132
|
+
}, {
|
|
133
|
+
// Provide an existing SVG Document here
|
|
134
|
+
// instead of creating a temporary one over again.
|
|
135
|
+
svgDocument: this.paper.svg,
|
|
136
|
+
ellipsis: value.ellipsis,
|
|
137
|
+
hyphen: value.hyphen,
|
|
138
|
+
separator: value.separator,
|
|
139
|
+
maxLineCount: value.maxLineCount,
|
|
140
|
+
preserveSpaces: value.preserveSpaces
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
wrappedText = '';
|
|
144
|
+
}
|
|
145
|
+
textAttributesNS.text.set.call(this, wrappedText, refBBox, node, attrs);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
'title': {
|
|
150
|
+
qualify: function(title, node) {
|
|
151
|
+
// HTMLElement title is specified via an attribute (i.e. not an element)
|
|
152
|
+
return node instanceof SVGElement;
|
|
153
|
+
},
|
|
154
|
+
set: function(title, refBBox, node) {
|
|
155
|
+
var cacheName = 'joint-title';
|
|
156
|
+
var cache = $.data.get(node, cacheName);
|
|
157
|
+
if (cache === undefined || cache !== title) {
|
|
158
|
+
$.data.set(node, cacheName, title);
|
|
159
|
+
if (node.tagName === 'title') {
|
|
160
|
+
// The target node is a <title> element.
|
|
161
|
+
node.textContent = title;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Generally <title> element should be the first child element of its parent.
|
|
165
|
+
var firstChild = node.firstElementChild;
|
|
166
|
+
if (firstChild && firstChild.tagName === 'title') {
|
|
167
|
+
// Update an existing title
|
|
168
|
+
firstChild.textContent = title;
|
|
169
|
+
} else {
|
|
170
|
+
// Create a new title
|
|
171
|
+
var titleNode = document.createElementNS(node.namespaceURI, 'title');
|
|
172
|
+
titleNode.textContent = title;
|
|
173
|
+
node.insertBefore(titleNode, firstChild);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export default textAttributesNS;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './Graph.mjs';
|
|
2
|
+
export * from './attributes/index.mjs';
|
|
3
|
+
export * from './PaperLayer.mjs';
|
|
4
|
+
export * from './Cell.mjs';
|
|
5
|
+
export * from './CellView.mjs';
|
|
6
|
+
export * from './Element.mjs';
|
|
7
|
+
export * from './ElementView.mjs';
|
|
8
|
+
export * from './Link.mjs';
|
|
9
|
+
export * from './LinkView.mjs';
|
|
10
|
+
export * from './Paper.mjs';
|
|
11
|
+
export * from './ToolView.mjs';
|
|
12
|
+
export * from './ToolsView.mjs';
|
|
13
|
+
export * from './HighlighterView.mjs';
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { PaperLayer } from '../PaperLayer.mjs';
|
|
2
|
+
import {
|
|
3
|
+
isFunction,
|
|
4
|
+
isString,
|
|
5
|
+
defaults,
|
|
6
|
+
omit,
|
|
7
|
+
assign,
|
|
8
|
+
merge,
|
|
9
|
+
} from '../../util/index.mjs';
|
|
10
|
+
import V from '../../V/index.mjs';
|
|
11
|
+
|
|
12
|
+
export const GridLayer = PaperLayer.extend({
|
|
13
|
+
|
|
14
|
+
style: {
|
|
15
|
+
'pointer-events': 'none'
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
_gridCache: null,
|
|
19
|
+
_gridSettings: null,
|
|
20
|
+
|
|
21
|
+
init() {
|
|
22
|
+
PaperLayer.prototype.init.apply(this, arguments);
|
|
23
|
+
const { options: { paper }} = this;
|
|
24
|
+
this._gridCache = null;
|
|
25
|
+
this._gridSettings = [];
|
|
26
|
+
this.listenTo(paper, 'transform resize', this.updateGrid);
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
setGrid(drawGrid) {
|
|
30
|
+
this._gridSettings = this.getGridSettings(drawGrid);
|
|
31
|
+
this.renderGrid();
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
getGridSettings(drawGrid) {
|
|
35
|
+
const gridSettings = [];
|
|
36
|
+
if (drawGrid) {
|
|
37
|
+
const optionsList = Array.isArray(drawGrid) ? drawGrid : [drawGrid || {}];
|
|
38
|
+
optionsList.forEach((item) => {
|
|
39
|
+
gridSettings.push(...this._resolveDrawGridOption(item));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return gridSettings;
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
removeGrid() {
|
|
46
|
+
const { _gridCache: grid } = this;
|
|
47
|
+
if (!grid) return;
|
|
48
|
+
grid.root.remove();
|
|
49
|
+
this._gridCache = null;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
renderGrid() {
|
|
53
|
+
|
|
54
|
+
const { options: { paper }} = this;
|
|
55
|
+
const { _gridSettings: gridSettings } = this;
|
|
56
|
+
|
|
57
|
+
this.removeGrid();
|
|
58
|
+
|
|
59
|
+
if (gridSettings.length === 0) return;
|
|
60
|
+
|
|
61
|
+
const gridSize = paper.options.drawGridSize || paper.options.gridSize;
|
|
62
|
+
if (gridSize <= 1) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const refs = this._getGridRefs();
|
|
67
|
+
|
|
68
|
+
gridSettings.forEach((gridLayerSetting, index) => {
|
|
69
|
+
|
|
70
|
+
const id = 'pattern_' + index;
|
|
71
|
+
const options = merge({}, gridLayerSetting);
|
|
72
|
+
const { scaleFactor = 1 } = options;
|
|
73
|
+
options.width = gridSize * scaleFactor || 1;
|
|
74
|
+
options.height = gridSize * scaleFactor || 1;
|
|
75
|
+
|
|
76
|
+
let vPattern;
|
|
77
|
+
if (!refs.exist(id)) {
|
|
78
|
+
vPattern = V('pattern', { id: id, patternUnits: 'userSpaceOnUse' }, V(options.markup));
|
|
79
|
+
refs.add(id, vPattern);
|
|
80
|
+
} else {
|
|
81
|
+
vPattern = refs.get(id);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isFunction(options.render)) {
|
|
85
|
+
options.render(vPattern.node.firstChild, options, paper);
|
|
86
|
+
}
|
|
87
|
+
vPattern.attr({
|
|
88
|
+
width: options.width,
|
|
89
|
+
height: options.height
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
refs.root.appendTo(this.el);
|
|
94
|
+
this.updateGrid();
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
updateGrid() {
|
|
98
|
+
|
|
99
|
+
const { _gridCache: grid, _gridSettings: gridSettings, options: { paper }} = this;
|
|
100
|
+
if (!grid) return;
|
|
101
|
+
const { root: vSvg, patterns } = grid;
|
|
102
|
+
const { x, y, width, height } = paper.getArea();
|
|
103
|
+
vSvg.attr({ x, y, width, height });
|
|
104
|
+
for (const patternId in patterns) {
|
|
105
|
+
const vPattern = patterns[patternId];
|
|
106
|
+
vPattern.attr({ x: -x, y: -y });
|
|
107
|
+
}
|
|
108
|
+
gridSettings.forEach((options, index) => {
|
|
109
|
+
if (isFunction(options.update)) {
|
|
110
|
+
const vPattern = patterns['pattern_' + index];
|
|
111
|
+
options.update(vPattern.node.firstChild, options, paper);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
_getGridRefs() {
|
|
117
|
+
let { _gridCache: grid } = this;
|
|
118
|
+
if (grid) return grid;
|
|
119
|
+
const defsVEl = V('defs');
|
|
120
|
+
const svgVEl = V('svg', { width: '100%', height: '100%' }, [defsVEl]);
|
|
121
|
+
grid = this._gridCache = {
|
|
122
|
+
root: svgVEl,
|
|
123
|
+
patterns: {},
|
|
124
|
+
add: function(id, patternVEl) {
|
|
125
|
+
const rectVEl = V('rect', { width: '100%', height: '100%', fill: `url(#${id})` });
|
|
126
|
+
defsVEl.append(patternVEl);
|
|
127
|
+
svgVEl.append(rectVEl);
|
|
128
|
+
this.patterns[id] = patternVEl;
|
|
129
|
+
},
|
|
130
|
+
get: function(id) {
|
|
131
|
+
return this.patterns[id];
|
|
132
|
+
},
|
|
133
|
+
exist: function(id) {
|
|
134
|
+
return this.patterns[id] !== undefined;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
return grid;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
_resolveDrawGridOption(opt) {
|
|
141
|
+
|
|
142
|
+
var namespace = this.options.patterns;
|
|
143
|
+
if (isString(opt) && Array.isArray(namespace[opt])) {
|
|
144
|
+
return namespace[opt].map(function(item) {
|
|
145
|
+
return assign({}, item);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var options = opt || { args: [{}] };
|
|
150
|
+
var isArray = Array.isArray(options);
|
|
151
|
+
var name = options.name;
|
|
152
|
+
|
|
153
|
+
if (!isArray && !name && !options.markup) {
|
|
154
|
+
name = 'dot';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (name && Array.isArray(namespace[name])) {
|
|
158
|
+
var pattern = namespace[name].map(function(item) {
|
|
159
|
+
return assign({}, item);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
var args = Array.isArray(options.args) ? options.args : [options.args || {}];
|
|
163
|
+
|
|
164
|
+
defaults(args[0], omit(opt, 'args'));
|
|
165
|
+
for (var i = 0; i < args.length; i++) {
|
|
166
|
+
if (pattern[i]) {
|
|
167
|
+
assign(pattern[i], args[i]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return pattern;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return isArray ? options : [options];
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
});
|