@joint/core 4.1.3 → 4.2.0-alpha.1
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/README.md +4 -2
- package/dist/geometry.js +129 -124
- package/dist/geometry.min.js +4 -3
- package/dist/joint.d.ts +352 -160
- package/dist/joint.js +3654 -2191
- package/dist/joint.min.js +4 -3
- package/dist/joint.nowrap.js +3653 -2188
- package/dist/joint.nowrap.min.js +4 -3
- package/dist/vectorizer.js +489 -279
- package/dist/vectorizer.min.js +4 -3
- package/dist/version.mjs +1 -1
- package/package.json +33 -27
- package/src/V/create.mjs +51 -0
- package/src/V/index.mjs +89 -159
- package/src/V/namespace.mjs +9 -0
- package/src/V/transform.mjs +183 -0
- package/src/V/traverse.mjs +16 -0
- package/src/alg/Deque.mjs +126 -0
- package/src/anchors/index.mjs +140 -33
- package/src/cellTools/Boundary.mjs +15 -13
- package/src/cellTools/Button.mjs +7 -5
- package/src/cellTools/Control.mjs +38 -15
- package/src/cellTools/HoverConnect.mjs +5 -1
- package/src/cellTools/helpers.mjs +44 -3
- package/src/config/index.mjs +8 -0
- package/src/connectionPoints/index.mjs +24 -9
- package/src/connectionStrategies/index.mjs +1 -1
- package/src/connectors/jumpover.mjs +1 -1
- package/src/dia/Cell.mjs +32 -12
- package/src/dia/CellView.mjs +53 -38
- package/src/dia/Element.mjs +81 -35
- package/src/dia/ElementView.mjs +2 -1
- package/src/dia/HighlighterView.mjs +54 -11
- package/src/dia/LinkView.mjs +118 -98
- package/src/dia/Paper.mjs +831 -231
- package/src/dia/PaperLayer.mjs +9 -2
- package/src/dia/ToolView.mjs +4 -0
- package/src/dia/ToolsView.mjs +12 -3
- package/src/dia/attributes/text.mjs +16 -5
- package/src/dia/layers/GridLayer.mjs +5 -0
- package/src/dia/ports.mjs +344 -111
- package/src/elementTools/HoverConnect.mjs +14 -8
- package/src/env/index.mjs +7 -4
- package/src/g/rect.mjs +7 -0
- package/src/highlighters/stroke.mjs +1 -1
- package/src/layout/ports/port.mjs +30 -15
- package/src/layout/ports/portLabel.mjs +1 -1
- package/src/linkAnchors/index.mjs +2 -2
- package/src/linkTools/Anchor.mjs +2 -2
- package/src/linkTools/Vertices.mjs +4 -6
- package/src/mvc/View.mjs +4 -0
- package/src/mvc/ViewBase.mjs +1 -1
- package/src/util/util.mjs +1 -1
- package/src/util/utilHelpers.mjs +2 -0
- package/types/geometry.d.ts +65 -59
- package/types/joint.d.ts +278 -102
- package/types/vectorizer.d.ts +11 -1
- package/src/V/annotation.mjs +0 -0
package/src/V/create.mjs
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as ns from './namespace.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @constant {boolean}
|
|
5
|
+
* @description Indicates the environment supports SVG.
|
|
6
|
+
*/
|
|
7
|
+
export const isSVGSupported = typeof window === 'object' && !!window.SVGAngle;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @constant {string}
|
|
11
|
+
* @description The version of the SVG document.
|
|
12
|
+
*/
|
|
13
|
+
export const SVG_VERSION = '1.1';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @constant {SVGSVGElement}
|
|
17
|
+
* @description The detached SVG document for various internal purposes.
|
|
18
|
+
* e.g. SVGMatrix has no constructor, so the only way to create it is
|
|
19
|
+
* to create an SVG document and then call `createSVGMatrix()`.
|
|
20
|
+
*/
|
|
21
|
+
export const internalSVGDocument = isSVGSupported
|
|
22
|
+
? createSVGDocument()
|
|
23
|
+
: null;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @constant {SVGGElement}
|
|
27
|
+
* @description The detached SVG group element for various internal purposes.
|
|
28
|
+
*/
|
|
29
|
+
export const internalSVGGroup = isSVGSupported
|
|
30
|
+
? createSVGElement('g')
|
|
31
|
+
: null;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @returns {SVGSVGElement}
|
|
35
|
+
* @description Creates an SVG document.
|
|
36
|
+
*/
|
|
37
|
+
export function createSVGDocument() {
|
|
38
|
+
const svg = createSVGElement('svg');
|
|
39
|
+
svg.setAttributeNS(ns.xmlns, 'xmlns:xlink', ns.xlink);
|
|
40
|
+
svg.setAttribute('version', SVG_VERSION);
|
|
41
|
+
return svg;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} name
|
|
46
|
+
* @returns {SVGElement}
|
|
47
|
+
* @description Creates an SVG element with the given name.
|
|
48
|
+
*/
|
|
49
|
+
export function createSVGElement(name) {
|
|
50
|
+
return document.createElementNS(ns.svg, name);
|
|
51
|
+
}
|
package/src/V/index.mjs
CHANGED
|
@@ -5,13 +5,20 @@
|
|
|
5
5
|
// The only Vectorizer dependency is the Geometry library.
|
|
6
6
|
|
|
7
7
|
import * as g from '../g/index.mjs';
|
|
8
|
+
import * as ns from './namespace.mjs';
|
|
9
|
+
import { isSVGSupported, internalSVGDocument, SVG_VERSION, createSVGDocument, createSVGElement } from './create.mjs';
|
|
10
|
+
import {
|
|
11
|
+
createIdentityMatrix, createMatrix, getNodeMatrix, isSVGMatrix,
|
|
12
|
+
getRelativeTransformation, getRelativeTransformationSafe,
|
|
13
|
+
matrixToTransformString, createMatrixFromTransformString,
|
|
14
|
+
transformNode, replaceTransformNode,
|
|
15
|
+
} from './transform.mjs';
|
|
16
|
+
import { getCommonAncestor } from './traverse.mjs';
|
|
8
17
|
|
|
9
18
|
const V = (function() {
|
|
10
19
|
|
|
11
|
-
var hasSvg = typeof window === 'object' && !!window.SVGAngle;
|
|
12
|
-
|
|
13
20
|
// SVG support is required.
|
|
14
|
-
if (!
|
|
21
|
+
if (!isSVGSupported) {
|
|
15
22
|
|
|
16
23
|
// Return a function that throws an error when it is used.
|
|
17
24
|
return function() {
|
|
@@ -19,17 +26,6 @@ const V = (function() {
|
|
|
19
26
|
};
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
// XML namespaces.
|
|
23
|
-
var ns = {
|
|
24
|
-
svg: 'http://www.w3.org/2000/svg',
|
|
25
|
-
xmlns: 'http://www.w3.org/2000/xmlns/',
|
|
26
|
-
xml: 'http://www.w3.org/XML/1998/namespace',
|
|
27
|
-
xlink: 'http://www.w3.org/1999/xlink',
|
|
28
|
-
xhtml: 'http://www.w3.org/1999/xhtml'
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
var SVGVersion = '1.1';
|
|
32
|
-
|
|
33
29
|
// Declare shorthands to the most used math functions.
|
|
34
30
|
var math = Math;
|
|
35
31
|
var PI = math.PI;
|
|
@@ -92,7 +88,7 @@ const V = (function() {
|
|
|
92
88
|
|
|
93
89
|
} else {
|
|
94
90
|
|
|
95
|
-
el =
|
|
91
|
+
el = createSVGElement(el);
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
V.ensureId(el);
|
|
@@ -122,40 +118,48 @@ const V = (function() {
|
|
|
122
118
|
});
|
|
123
119
|
|
|
124
120
|
/**
|
|
125
|
-
*
|
|
126
|
-
* @
|
|
121
|
+
* Calculates the transformation matrix from this element to the target element.
|
|
122
|
+
* @param {SVGElement|V} target - The target element.
|
|
123
|
+
* @param {Object} [opt] - Options object for transformation calculation.
|
|
124
|
+
* @param {boolean} [opt.safe] - Use a safe traversal method to compute the matrix.
|
|
125
|
+
* @returns {DOMMatrix} The transformation matrix from this element to the target element.
|
|
127
126
|
*/
|
|
128
|
-
VPrototype.getTransformToElement = function(target) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
|
|
127
|
+
VPrototype.getTransformToElement = function(target, opt) {
|
|
128
|
+
const node = this.node;
|
|
129
|
+
const targetNode = V.toNode(target);
|
|
130
|
+
let m;
|
|
131
|
+
if (V.isSVGGraphicsElement(targetNode) && V.isSVGGraphicsElement(node)) {
|
|
132
|
+
if (opt && opt.safe) {
|
|
133
|
+
// Use the traversal method to get the transformation matrix.
|
|
134
|
+
m = getRelativeTransformationSafe(node, targetNode);
|
|
135
|
+
} else {
|
|
136
|
+
m = getRelativeTransformation(node, targetNode);
|
|
135
137
|
}
|
|
136
138
|
}
|
|
137
|
-
|
|
138
|
-
return V.createSVGMatrix();
|
|
139
|
+
return m || createIdentityMatrix();
|
|
139
140
|
};
|
|
140
141
|
|
|
142
|
+
|
|
141
143
|
/**
|
|
142
144
|
* @param {SVGMatrix} matrix
|
|
143
145
|
* @param {Object=} opt
|
|
144
146
|
* @returns {Vectorizer|SVGMatrix} Setter / Getter
|
|
145
147
|
*/
|
|
146
148
|
VPrototype.transform = function(matrix, opt) {
|
|
149
|
+
const node = this.node;
|
|
147
150
|
|
|
148
|
-
|
|
151
|
+
// Getter
|
|
149
152
|
if (V.isUndefined(matrix)) {
|
|
150
|
-
return
|
|
153
|
+
return getNodeMatrix(node) || createIdentityMatrix();
|
|
151
154
|
}
|
|
152
155
|
|
|
156
|
+
// Setter
|
|
153
157
|
if (opt && opt.absolute) {
|
|
154
|
-
|
|
158
|
+
replaceTransformNode(node, matrix);
|
|
159
|
+
} else {
|
|
160
|
+
transformNode(node, matrix);
|
|
155
161
|
}
|
|
156
162
|
|
|
157
|
-
var svgTransform = V.createSVGTransform(matrix);
|
|
158
|
-
node.transform.baseVal.appendItem(svgTransform);
|
|
159
163
|
return this;
|
|
160
164
|
};
|
|
161
165
|
|
|
@@ -250,7 +254,7 @@ const V = (function() {
|
|
|
250
254
|
|
|
251
255
|
box = node.getBBox();
|
|
252
256
|
|
|
253
|
-
} catch
|
|
257
|
+
} catch {
|
|
254
258
|
|
|
255
259
|
// Fallback for IE.
|
|
256
260
|
box = {
|
|
@@ -303,7 +307,7 @@ const V = (function() {
|
|
|
303
307
|
if (!options.recursive) {
|
|
304
308
|
try {
|
|
305
309
|
outputBBox = node.getBBox();
|
|
306
|
-
} catch
|
|
310
|
+
} catch {
|
|
307
311
|
// Fallback for IE.
|
|
308
312
|
outputBBox = {
|
|
309
313
|
x: node.clientLeft,
|
|
@@ -484,10 +488,19 @@ const V = (function() {
|
|
|
484
488
|
|
|
485
489
|
if (content && typeof content !== 'string') throw new Error('Vectorizer: text() expects the first argument to be a string.');
|
|
486
490
|
|
|
487
|
-
// Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
|
|
488
|
-
// IE would otherwise collapse all spaces into one.
|
|
489
|
-
content = V.sanitizeText(content);
|
|
490
491
|
opt || (opt = {});
|
|
492
|
+
|
|
493
|
+
// Backwards-compatibility: if no content was provided, treat it as an
|
|
494
|
+
// empty string so that subsequent string operations (e.g. split) do
|
|
495
|
+
// not throw and behaviour matches the previous implementation that
|
|
496
|
+
// always sanitised the input.
|
|
497
|
+
if (content == null) content = '';
|
|
498
|
+
|
|
499
|
+
if (opt.useNoBreakSpace) {
|
|
500
|
+
// Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
|
|
501
|
+
// IE would otherwise collapse all spaces into one.
|
|
502
|
+
content = V.sanitizeText(content);
|
|
503
|
+
}
|
|
491
504
|
// Should we allow the text to be selected?
|
|
492
505
|
var displayEmpty = opt.displayEmpty;
|
|
493
506
|
// End of Line character
|
|
@@ -924,9 +937,9 @@ const V = (function() {
|
|
|
924
937
|
var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
|
|
925
938
|
var globalToLocalMatrix = this.getTransformToElement(svg).inverse();
|
|
926
939
|
|
|
927
|
-
} catch
|
|
940
|
+
} catch {
|
|
928
941
|
// IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
|
|
929
|
-
// We have to make do with the original
|
|
942
|
+
// We have to make do with the original coordinates.
|
|
930
943
|
return p;
|
|
931
944
|
}
|
|
932
945
|
|
|
@@ -986,7 +999,7 @@ const V = (function() {
|
|
|
986
999
|
translateToOrigin.matrix.multiply(
|
|
987
1000
|
ctm.scale(scale.sx, scale.sy)))));
|
|
988
1001
|
|
|
989
|
-
this.attr('transform',
|
|
1002
|
+
this.attr('transform', matrixToTransformString(transform.matrix));
|
|
990
1003
|
|
|
991
1004
|
return this;
|
|
992
1005
|
};
|
|
@@ -1004,7 +1017,7 @@ const V = (function() {
|
|
|
1004
1017
|
this.append(animateMotion);
|
|
1005
1018
|
try {
|
|
1006
1019
|
animateMotion.node.beginElement();
|
|
1007
|
-
} catch
|
|
1020
|
+
} catch {
|
|
1008
1021
|
// Fallback for IE 9.
|
|
1009
1022
|
// Run the animation programmatically if FakeSmile (`http://leunen.me/fakesmile/`) present
|
|
1010
1023
|
if (document.documentElement.getAttribute('smiling') === 'fake') {
|
|
@@ -1287,15 +1300,12 @@ const V = (function() {
|
|
|
1287
1300
|
V.createSvgDocument = function(content) {
|
|
1288
1301
|
|
|
1289
1302
|
if (content) {
|
|
1290
|
-
const XMLString = `<svg xmlns="${ns.svg}" xmlns:xlink="${ns.xlink}" version="${
|
|
1303
|
+
const XMLString = `<svg xmlns="${ns.svg}" xmlns:xlink="${ns.xlink}" version="${SVG_VERSION}">${content}</svg>`;
|
|
1291
1304
|
const { documentElement } = V.parseXML(XMLString, { async: false });
|
|
1292
1305
|
return documentElement;
|
|
1293
1306
|
}
|
|
1294
1307
|
|
|
1295
|
-
|
|
1296
|
-
svg.setAttributeNS(ns.xmlns, 'xmlns:xlink', ns.xlink);
|
|
1297
|
-
svg.setAttribute('version', SVGVersion);
|
|
1298
|
-
return svg;
|
|
1308
|
+
return createSVGDocument();
|
|
1299
1309
|
};
|
|
1300
1310
|
|
|
1301
1311
|
V.createSVGStyle = function(stylesheet) {
|
|
@@ -1334,6 +1344,9 @@ const V = (function() {
|
|
|
1334
1344
|
// also exposed so that the programmer can use it in case he needs to. This is useful e.g. in tests
|
|
1335
1345
|
// when you want to compare the actual DOM text content without having to add the unicode character in
|
|
1336
1346
|
// the place of all spaces.
|
|
1347
|
+
/**
|
|
1348
|
+
* @deprecated Use regular spaces and rely on xml:space="preserve" instead.
|
|
1349
|
+
*/
|
|
1337
1350
|
V.sanitizeText = function(text) {
|
|
1338
1351
|
|
|
1339
1352
|
return (text || '').replace(/ /g, '\u00A0');
|
|
@@ -1370,7 +1383,7 @@ const V = (function() {
|
|
|
1370
1383
|
}
|
|
1371
1384
|
|
|
1372
1385
|
xml = parser.parseFromString(data, 'text/xml');
|
|
1373
|
-
} catch
|
|
1386
|
+
} catch {
|
|
1374
1387
|
xml = undefined;
|
|
1375
1388
|
}
|
|
1376
1389
|
|
|
@@ -1389,6 +1402,7 @@ const V = (function() {
|
|
|
1389
1402
|
// List of attributes for which not to split camel case words.
|
|
1390
1403
|
// It contains known SVG attribute names and may be extended with user-defined attribute names.
|
|
1391
1404
|
[
|
|
1405
|
+
'attributeName',
|
|
1392
1406
|
'baseFrequency',
|
|
1393
1407
|
'baseProfile',
|
|
1394
1408
|
'clipPathUnits',
|
|
@@ -1426,6 +1440,7 @@ const V = (function() {
|
|
|
1426
1440
|
'refY',
|
|
1427
1441
|
'requiredExtensions',
|
|
1428
1442
|
'requiredFeatures',
|
|
1443
|
+
'repeatCount',
|
|
1429
1444
|
'specularConstant',
|
|
1430
1445
|
'specularExponent',
|
|
1431
1446
|
'spreadMethod',
|
|
@@ -1442,7 +1457,7 @@ const V = (function() {
|
|
|
1442
1457
|
'viewTarget', // deprecated
|
|
1443
1458
|
'xChannelSelector',
|
|
1444
1459
|
'yChannelSelector',
|
|
1445
|
-
'zoomAndPan' // deprecated
|
|
1460
|
+
'zoomAndPan', // deprecated
|
|
1446
1461
|
].forEach((name) => _attributeNames[name] = name);
|
|
1447
1462
|
|
|
1448
1463
|
_attributeNames['xlinkShow'] = 'xlink:show';
|
|
@@ -1511,108 +1526,22 @@ const V = (function() {
|
|
|
1511
1526
|
// ReDoS mitigation: Use an anchor at the beginning of the match
|
|
1512
1527
|
// ReDoS mitigation: Avoid backtracking (uses `[^()]+` instead of `.*?`)
|
|
1513
1528
|
// ReDoS mitigation: Don't match initial `(` inside repeated part
|
|
1514
|
-
// The following regex needs to use /g (= cannot use capturing groups)
|
|
1515
|
-
V.transformRegex = /\b\w+\([^()]+\)/g;
|
|
1516
1529
|
// The following regexes need to use capturing groups (= cannot use /g)
|
|
1517
1530
|
V.transformFunctionRegex = /\b(\w+)\(([^()]+)\)/;
|
|
1518
1531
|
V.transformTranslateRegex = /\btranslate\(([^()]+)\)/;
|
|
1519
1532
|
V.transformRotateRegex = /\brotate\(([^()]+)\)/;
|
|
1520
1533
|
V.transformScaleRegex = /\bscale\(([^()]+)\)/;
|
|
1521
1534
|
|
|
1522
|
-
V.transformStringToMatrix = function(transform) {
|
|
1523
|
-
|
|
1524
|
-
// Initialize result matrix as identity matrix
|
|
1525
|
-
let transformationMatrix = V.createSVGMatrix();
|
|
1526
|
-
|
|
1527
|
-
// Note: Multiple transform functions are allowed in `transform` string
|
|
1528
|
-
// `match()` returns `null` if none found
|
|
1529
|
-
const transformMatches = transform && transform.match(V.transformRegex);
|
|
1530
|
-
if (!transformMatches) {
|
|
1531
|
-
// Return identity matrix
|
|
1532
|
-
return transformationMatrix;
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
const numMatches = transformMatches.length;
|
|
1536
|
-
for (let i = 0; i < numMatches; i++) {
|
|
1537
|
-
|
|
1538
|
-
const transformMatch = transformMatches[i];
|
|
1539
|
-
// Use same regex as above, but with capturing groups
|
|
1540
|
-
// `match()` returns values of capturing groups as `[1]`, `[2]`
|
|
1541
|
-
const transformFunctionMatch = transformMatch.match(V.transformFunctionRegex);
|
|
1542
|
-
if (transformFunctionMatch) {
|
|
1543
|
-
|
|
1544
|
-
let sx, sy, tx, ty, angle;
|
|
1545
|
-
let ctm = V.createSVGMatrix();
|
|
1546
|
-
const transformFunction = transformFunctionMatch[1].toLowerCase();
|
|
1547
|
-
const args = transformFunctionMatch[2].split(V.transformSeparatorRegex);
|
|
1548
|
-
switch (transformFunction) {
|
|
1549
|
-
|
|
1550
|
-
case 'scale':
|
|
1551
|
-
sx = parseFloat(args[0]);
|
|
1552
|
-
sy = (args[1] === undefined) ? sx : parseFloat(args[1]);
|
|
1553
|
-
ctm = ctm.scaleNonUniform(sx, sy);
|
|
1554
|
-
break;
|
|
1555
|
-
|
|
1556
|
-
case 'translate':
|
|
1557
|
-
tx = parseFloat(args[0]);
|
|
1558
|
-
ty = parseFloat(args[1]);
|
|
1559
|
-
ctm = ctm.translate(tx, ty);
|
|
1560
|
-
break;
|
|
1561
|
-
|
|
1562
|
-
case 'rotate':
|
|
1563
|
-
angle = parseFloat(args[0]);
|
|
1564
|
-
tx = parseFloat(args[1]) || 0;
|
|
1565
|
-
ty = parseFloat(args[2]) || 0;
|
|
1566
|
-
if (tx !== 0 || ty !== 0) {
|
|
1567
|
-
ctm = ctm.translate(tx, ty).rotate(angle).translate(-tx, -ty);
|
|
1568
|
-
} else {
|
|
1569
|
-
ctm = ctm.rotate(angle);
|
|
1570
|
-
}
|
|
1571
|
-
break;
|
|
1572
|
-
|
|
1573
|
-
case 'skewx':
|
|
1574
|
-
angle = parseFloat(args[0]);
|
|
1575
|
-
ctm = ctm.skewX(angle);
|
|
1576
|
-
break;
|
|
1577
|
-
|
|
1578
|
-
case 'skewy':
|
|
1579
|
-
angle = parseFloat(args[0]);
|
|
1580
|
-
ctm = ctm.skewY(angle);
|
|
1581
|
-
break;
|
|
1582
|
-
|
|
1583
|
-
case 'matrix':
|
|
1584
|
-
ctm.a = parseFloat(args[0]);
|
|
1585
|
-
ctm.b = parseFloat(args[1]);
|
|
1586
|
-
ctm.c = parseFloat(args[2]);
|
|
1587
|
-
ctm.d = parseFloat(args[3]);
|
|
1588
|
-
ctm.e = parseFloat(args[4]);
|
|
1589
|
-
ctm.f = parseFloat(args[5]);
|
|
1590
|
-
break;
|
|
1591
|
-
|
|
1592
|
-
default:
|
|
1593
|
-
continue;
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
// Multiply current transformation into result matrix
|
|
1597
|
-
transformationMatrix = transformationMatrix.multiply(ctm);
|
|
1598
|
-
}
|
|
1599
1535
|
|
|
1536
|
+
V.transformStringToMatrix = function(transform) {
|
|
1537
|
+
let matrix;
|
|
1538
|
+
if (V.isString(transform)) {
|
|
1539
|
+
matrix = createMatrixFromTransformString(transform);
|
|
1600
1540
|
}
|
|
1601
|
-
return
|
|
1541
|
+
return matrix || createIdentityMatrix();
|
|
1602
1542
|
};
|
|
1603
1543
|
|
|
1604
|
-
V.matrixToTransformString =
|
|
1605
|
-
matrix || (matrix = true);
|
|
1606
|
-
|
|
1607
|
-
return 'matrix(' +
|
|
1608
|
-
(matrix.a !== undefined ? matrix.a : 1) + ',' +
|
|
1609
|
-
(matrix.b !== undefined ? matrix.b : 0) + ',' +
|
|
1610
|
-
(matrix.c !== undefined ? matrix.c : 0) + ',' +
|
|
1611
|
-
(matrix.d !== undefined ? matrix.d : 1) + ',' +
|
|
1612
|
-
(matrix.e !== undefined ? matrix.e : 0) + ',' +
|
|
1613
|
-
(matrix.f !== undefined ? matrix.f : 0) +
|
|
1614
|
-
')';
|
|
1615
|
-
};
|
|
1544
|
+
V.matrixToTransformString = matrixToTransformString;
|
|
1616
1545
|
|
|
1617
1546
|
V.parseTransformString = function(transform) {
|
|
1618
1547
|
|
|
@@ -1780,35 +1709,25 @@ const V = (function() {
|
|
|
1780
1709
|
return node instanceof SVGElement && typeof node.getScreenCTM === 'function';
|
|
1781
1710
|
};
|
|
1782
1711
|
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
V.createSVGMatrix = function(matrix) {
|
|
1786
|
-
|
|
1787
|
-
var svgMatrix = svgDocument.createSVGMatrix();
|
|
1788
|
-
for (var component in matrix) {
|
|
1789
|
-
svgMatrix[component] = matrix[component];
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
return svgMatrix;
|
|
1793
|
-
};
|
|
1712
|
+
V.createSVGMatrix = createMatrix;
|
|
1794
1713
|
|
|
1795
1714
|
V.createSVGTransform = function(matrix) {
|
|
1796
1715
|
|
|
1797
1716
|
if (!V.isUndefined(matrix)) {
|
|
1798
1717
|
|
|
1799
|
-
if (!(matrix
|
|
1800
|
-
matrix =
|
|
1718
|
+
if (!isSVGMatrix(matrix)) {
|
|
1719
|
+
matrix = createMatrix(matrix);
|
|
1801
1720
|
}
|
|
1802
1721
|
|
|
1803
|
-
return
|
|
1722
|
+
return internalSVGDocument.createSVGTransformFromMatrix(matrix);
|
|
1804
1723
|
}
|
|
1805
1724
|
|
|
1806
|
-
return
|
|
1725
|
+
return internalSVGDocument.createSVGTransform();
|
|
1807
1726
|
};
|
|
1808
1727
|
|
|
1809
1728
|
V.createSVGPoint = function(x, y) {
|
|
1810
1729
|
|
|
1811
|
-
var p =
|
|
1730
|
+
var p = internalSVGDocument.createSVGPoint();
|
|
1812
1731
|
p.x = x;
|
|
1813
1732
|
p.y = y;
|
|
1814
1733
|
return p;
|
|
@@ -1816,7 +1735,7 @@ const V = (function() {
|
|
|
1816
1735
|
|
|
1817
1736
|
V.transformRect = function(r, matrix) {
|
|
1818
1737
|
|
|
1819
|
-
var p =
|
|
1738
|
+
var p = internalSVGDocument.createSVGPoint();
|
|
1820
1739
|
|
|
1821
1740
|
p.x = r.x;
|
|
1822
1741
|
p.y = r.y;
|
|
@@ -2083,8 +2002,8 @@ const V = (function() {
|
|
|
2083
2002
|
|
|
2084
2003
|
line = V(line);
|
|
2085
2004
|
var d = [
|
|
2086
|
-
'M', line.attr('x1'), line.attr('y1'),
|
|
2087
|
-
'L', line.attr('x2'), line.attr('y2')
|
|
2005
|
+
'M', line.attr('x1') || '0', line.attr('y1') || '0',
|
|
2006
|
+
'L', line.attr('x2') || '0', line.attr('y2') || '0'
|
|
2088
2007
|
].join(' ');
|
|
2089
2008
|
return d;
|
|
2090
2009
|
};
|
|
@@ -2635,7 +2554,18 @@ const V = (function() {
|
|
|
2635
2554
|
};
|
|
2636
2555
|
})();
|
|
2637
2556
|
|
|
2638
|
-
|
|
2557
|
+
/**
|
|
2558
|
+
*
|
|
2559
|
+
* @param {SVGElement|V} node1
|
|
2560
|
+
* @param {SVGElement|V} node2
|
|
2561
|
+
* @returns {SVGElement|null}
|
|
2562
|
+
*/
|
|
2563
|
+
V.getCommonAncestor = function(node1, node2) {
|
|
2564
|
+
if (!node1 || !node2) return null;
|
|
2565
|
+
return getCommonAncestor(V.toNode(node1), V.toNode(node2));
|
|
2566
|
+
};
|
|
2567
|
+
|
|
2568
|
+
V.namespace = { ...ns };
|
|
2639
2569
|
|
|
2640
2570
|
V.g = g;
|
|
2641
2571
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const svg = 'http://www.w3.org/2000/svg';
|
|
2
|
+
|
|
3
|
+
export const xmlns = 'http://www.w3.org/2000/xmlns/';
|
|
4
|
+
|
|
5
|
+
export const xml = 'http://www.w3.org/XML/1998/namespace';
|
|
6
|
+
|
|
7
|
+
export const xlink = 'http://www.w3.org/1999/xlink';
|
|
8
|
+
|
|
9
|
+
export const xhtml = 'http://www.w3.org/1999/xhtml';
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { internalSVGDocument, internalSVGGroup } from './create.mjs';
|
|
2
|
+
import { getCommonAncestor } from './traverse.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @returns {SVGMatrix}
|
|
6
|
+
* @description Creates an identity matrix.
|
|
7
|
+
*/
|
|
8
|
+
export function createIdentityMatrix() {
|
|
9
|
+
return internalSVGDocument.createSVGMatrix();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {Partial<SVGMatrix>} matrixInit
|
|
14
|
+
* @returns {SVGMatrix}
|
|
15
|
+
* @description Creates a new SVGMatrix object.
|
|
16
|
+
* If no matrix is provided, it returns the identity matrix.
|
|
17
|
+
* If a matrix like object is provided, it sets the matrix values.
|
|
18
|
+
*/
|
|
19
|
+
export function createMatrix(matrixInit = {}) {
|
|
20
|
+
const matrix = internalSVGDocument.createSVGMatrix();
|
|
21
|
+
if (!matrixInit) return matrix;
|
|
22
|
+
if ('a' in matrixInit) matrix.a = matrixInit.a;
|
|
23
|
+
if ('b' in matrixInit) matrix.b = matrixInit.b;
|
|
24
|
+
if ('c' in matrixInit) matrix.c = matrixInit.c;
|
|
25
|
+
if ('d' in matrixInit) matrix.d = matrixInit.d;
|
|
26
|
+
if ('e' in matrixInit) matrix.e = matrixInit.e;
|
|
27
|
+
if ('f' in matrixInit) matrix.f = matrixInit.f;
|
|
28
|
+
return matrix;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @returns {SVGTransform}
|
|
33
|
+
* @description Creates a new SVGTransform object.
|
|
34
|
+
*/
|
|
35
|
+
export function createSVGTransform() {
|
|
36
|
+
return internalSVGDocument.createSVGTransform();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {SVGElement} node
|
|
41
|
+
* @returns {SVGMatrix|null}
|
|
42
|
+
* @description Returns the transformation matrix of the given node.
|
|
43
|
+
* If the node has no transformation, it returns null.
|
|
44
|
+
*/
|
|
45
|
+
export function getNodeMatrix(node) {
|
|
46
|
+
const consolidatedTransformation = node.transform.baseVal.consolidate();
|
|
47
|
+
return consolidatedTransformation ? consolidatedTransformation.matrix : null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {string} transformString
|
|
52
|
+
* @returns {SVGMatrix}
|
|
53
|
+
* @description Creates a matrix from the given transform string.
|
|
54
|
+
*/
|
|
55
|
+
export function createMatrixFromTransformString(transformString) {
|
|
56
|
+
internalSVGGroup.setAttribute('transform', transformString);
|
|
57
|
+
return getNodeMatrix(internalSVGGroup);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {SVGElement} node
|
|
62
|
+
* @param {Partial<SVGMatrix>} matrixInit
|
|
63
|
+
* @param {boolean} override
|
|
64
|
+
* @description Sets the transformation matrix of the given node.
|
|
65
|
+
* We don't use `node.transform.baseVal` here (@see `transformNode`)
|
|
66
|
+
* for the following reasons:
|
|
67
|
+
* - Performance: while Chrome performs slightly better, Firefox
|
|
68
|
+
* and Safari are significantly slower
|
|
69
|
+
* https://www.measurethat.net/Benchmarks/Show/34447/1/overriding-svg-transform-attribute
|
|
70
|
+
* - Limited support: JSDOM does not support `node.transform.baseVal`
|
|
71
|
+
*/
|
|
72
|
+
export function replaceTransformNode(node, matrixInit) {
|
|
73
|
+
node.setAttribute('transform', matrixToTransformString(matrixInit));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {SVGElement} node
|
|
78
|
+
* @param {Partial<SVGMatrix>} matrixInit
|
|
79
|
+
* @description Applies a transformation matrix to the given node.
|
|
80
|
+
* If the node already has a transformation, it appends the new transformation.
|
|
81
|
+
* If the node has no transformation, it creates a new one.
|
|
82
|
+
*/
|
|
83
|
+
export function transformNode(node, matrixInit) {
|
|
84
|
+
const transform = createSVGTransform();
|
|
85
|
+
const matrix = isSVGMatrix(matrixInit) ? matrixInit : createMatrix(matrixInit);
|
|
86
|
+
transform.setMatrix(matrix);
|
|
87
|
+
node.transform.baseVal.appendItem(transform);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const MATRIX_TYPE = '[object SVGMatrix]';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {any} obj
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
* @description Checks if the given object is an SVGMatrix.
|
|
96
|
+
*/
|
|
97
|
+
export function isSVGMatrix(obj) {
|
|
98
|
+
return Object.prototype.toString.call(obj) === MATRIX_TYPE;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {Partial<SVGMatrix>} matrixInit
|
|
103
|
+
* @returns {string}
|
|
104
|
+
* @description Converts a matrix to a transform string.
|
|
105
|
+
* If no matrix is provided, it returns the identity matrix string.
|
|
106
|
+
*/
|
|
107
|
+
export function matrixToTransformString(matrixInit = {}) {
|
|
108
|
+
const { a = 1, b = 0, c = 0, d = 1, e = 0, f = 0 } = matrixInit;
|
|
109
|
+
return `matrix(${a},${b},${c},${d},${e},${f})`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
*
|
|
114
|
+
* @param {SVGElement} a
|
|
115
|
+
* @param {SVGElement} b
|
|
116
|
+
* @returns {SVGMatrix|null}
|
|
117
|
+
* @description Finds the transformation matrix from `a` to `b`.
|
|
118
|
+
* It requires that both elements to be visible (in the render tree)
|
|
119
|
+
* in order to calculate the correct transformation matrix.
|
|
120
|
+
*/
|
|
121
|
+
export function getRelativeTransformation(a, b) {
|
|
122
|
+
// Different SVG elements, no transformation possible
|
|
123
|
+
// Note: SVGSVGElement has no `ownerSVGElement`
|
|
124
|
+
if ((a.ownerSVGElement || a) !== (b.ownerSVGElement || b)) return null;
|
|
125
|
+
// Get the transformation matrix from `a` to `b`.
|
|
126
|
+
const am = b.getScreenCTM();
|
|
127
|
+
if (!am) return null;
|
|
128
|
+
const bm = a.getScreenCTM();
|
|
129
|
+
if (!bm) return null;
|
|
130
|
+
return am.inverse().multiply(bm);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {SVGElement} a
|
|
135
|
+
* @param {SVGElement} b
|
|
136
|
+
* @returns {SVGMatrix|null}
|
|
137
|
+
* @description Finds the transformation matrix from `a` to `b`.
|
|
138
|
+
* A safe way to calculate the transformation matrix between two elements.
|
|
139
|
+
* It does not require the elements to be visible (in the render tree).
|
|
140
|
+
*/
|
|
141
|
+
export function getRelativeTransformationSafe(a, b) {
|
|
142
|
+
if (a === b) {
|
|
143
|
+
// No transformation needed
|
|
144
|
+
return createIdentityMatrix();
|
|
145
|
+
}
|
|
146
|
+
const position = a.compareDocumentPosition(b);
|
|
147
|
+
if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
|
|
148
|
+
// `b` is a descendant of `a`
|
|
149
|
+
return getLinealTransformation(a, b).inverse();
|
|
150
|
+
} else if (position & Node.DOCUMENT_POSITION_CONTAINS) {
|
|
151
|
+
// `a` is a descendant of `b`
|
|
152
|
+
return getLinealTransformation(b, a);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const c = getCommonAncestor(a, b);
|
|
156
|
+
if (!c) {
|
|
157
|
+
// No common ancestor
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const mca = getLinealTransformation(c, a);
|
|
162
|
+
const mcb = getLinealTransformation(c, b);
|
|
163
|
+
return mcb.inverse().multiply(mca);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {SVGElement} descendant
|
|
168
|
+
* @param {SVGElement} ancestor
|
|
169
|
+
* @returns {SVGMatrix}
|
|
170
|
+
* @description Finds the transformation matrix between the `ancestor` and `descendant`.
|
|
171
|
+
*/
|
|
172
|
+
function getLinealTransformation(ancestor, descendant) {
|
|
173
|
+
const transformations = [];
|
|
174
|
+
let n = descendant;
|
|
175
|
+
while (n && n.nodeType === Node.ELEMENT_NODE && n !== ancestor) {
|
|
176
|
+
const nm = getNodeMatrix(n);
|
|
177
|
+
if (nm) {
|
|
178
|
+
transformations.unshift(nm);
|
|
179
|
+
}
|
|
180
|
+
n = n.parentNode;
|
|
181
|
+
}
|
|
182
|
+
return transformations.reduce((m, t) => m.multiply(t), createIdentityMatrix());
|
|
183
|
+
}
|