@joint/core 4.1.2 → 4.2.0-alpha.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/README.md +1 -1
- package/dist/geometry.js +128 -123
- package/dist/geometry.min.js +2 -2
- package/dist/joint.d.ts +79 -16
- package/dist/joint.js +2249 -1730
- package/dist/joint.min.js +2 -2
- package/dist/joint.nowrap.js +2248 -1727
- package/dist/joint.nowrap.min.js +2 -2
- package/dist/vectorizer.js +469 -272
- package/dist/vectorizer.min.js +2 -2
- package/dist/version.mjs +1 -1
- package/package.json +28 -22
- package/src/V/create.mjs +51 -0
- package/src/V/index.mjs +69 -154
- package/src/V/namespace.mjs +9 -0
- package/src/V/transform.mjs +183 -0
- package/src/V/traverse.mjs +16 -0
- package/src/anchors/index.mjs +140 -33
- package/src/cellTools/Boundary.mjs +1 -1
- package/src/cellTools/Control.mjs +1 -1
- 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 +6 -2
- package/src/dia/CellView.mjs +47 -39
- package/src/dia/Element.mjs +79 -35
- package/src/dia/ElementView.mjs +9 -3
- package/src/dia/HighlighterView.mjs +32 -11
- package/src/dia/Paper.mjs +134 -22
- package/src/dia/PaperLayer.mjs +9 -2
- package/src/dia/attributes/text.mjs +12 -3
- package/src/dia/layers/GridLayer.mjs +5 -0
- package/src/dia/ports.mjs +152 -39
- package/src/env/index.mjs +1 -1
- package/src/g/rect.mjs +7 -0
- package/src/highlighters/stroke.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/Dom/methods.mjs +2 -2
- package/src/util/util.mjs +1 -1
- package/src/util/utilHelpers.mjs +2 -0
- package/types/geometry.d.ts +2 -0
- package/types/joint.d.ts +81 -20
- 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);
|
|
@@ -125,37 +121,42 @@ const V = (function() {
|
|
|
125
121
|
* @param {SVGGElement} toElem
|
|
126
122
|
* @returns {SVGMatrix}
|
|
127
123
|
*/
|
|
128
|
-
VPrototype.getTransformToElement = function(target) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
|
|
124
|
+
VPrototype.getTransformToElement = function(target, opt) {
|
|
125
|
+
const node = this.node;
|
|
126
|
+
const targetNode = V.toNode(target);
|
|
127
|
+
let m;
|
|
128
|
+
if (V.isSVGGraphicsElement(targetNode) && V.isSVGGraphicsElement(node)) {
|
|
129
|
+
if (opt && opt.safe) {
|
|
130
|
+
// Use the traversal method to get the transformation matrix.
|
|
131
|
+
m = getRelativeTransformationSafe(node, targetNode);
|
|
132
|
+
} else {
|
|
133
|
+
m = getRelativeTransformation(node, targetNode);
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
|
-
|
|
138
|
-
return V.createSVGMatrix();
|
|
136
|
+
return m || createIdentityMatrix();
|
|
139
137
|
};
|
|
140
138
|
|
|
139
|
+
|
|
141
140
|
/**
|
|
142
141
|
* @param {SVGMatrix} matrix
|
|
143
142
|
* @param {Object=} opt
|
|
144
143
|
* @returns {Vectorizer|SVGMatrix} Setter / Getter
|
|
145
144
|
*/
|
|
146
145
|
VPrototype.transform = function(matrix, opt) {
|
|
146
|
+
const node = this.node;
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
// Getter
|
|
149
149
|
if (V.isUndefined(matrix)) {
|
|
150
|
-
return
|
|
150
|
+
return getNodeMatrix(node) || createIdentityMatrix();
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
// Setter
|
|
153
154
|
if (opt && opt.absolute) {
|
|
154
|
-
|
|
155
|
+
replaceTransformNode(node, matrix);
|
|
156
|
+
} else {
|
|
157
|
+
transformNode(node, matrix);
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
var svgTransform = V.createSVGTransform(matrix);
|
|
158
|
-
node.transform.baseVal.appendItem(svgTransform);
|
|
159
160
|
return this;
|
|
160
161
|
};
|
|
161
162
|
|
|
@@ -250,7 +251,7 @@ const V = (function() {
|
|
|
250
251
|
|
|
251
252
|
box = node.getBBox();
|
|
252
253
|
|
|
253
|
-
} catch
|
|
254
|
+
} catch {
|
|
254
255
|
|
|
255
256
|
// Fallback for IE.
|
|
256
257
|
box = {
|
|
@@ -303,7 +304,7 @@ const V = (function() {
|
|
|
303
304
|
if (!options.recursive) {
|
|
304
305
|
try {
|
|
305
306
|
outputBBox = node.getBBox();
|
|
306
|
-
} catch
|
|
307
|
+
} catch {
|
|
307
308
|
// Fallback for IE.
|
|
308
309
|
outputBBox = {
|
|
309
310
|
x: node.clientLeft,
|
|
@@ -924,9 +925,9 @@ const V = (function() {
|
|
|
924
925
|
var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
|
|
925
926
|
var globalToLocalMatrix = this.getTransformToElement(svg).inverse();
|
|
926
927
|
|
|
927
|
-
} catch
|
|
928
|
+
} catch {
|
|
928
929
|
// IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
|
|
929
|
-
// We have to make do with the original
|
|
930
|
+
// We have to make do with the original coordinates.
|
|
930
931
|
return p;
|
|
931
932
|
}
|
|
932
933
|
|
|
@@ -986,7 +987,7 @@ const V = (function() {
|
|
|
986
987
|
translateToOrigin.matrix.multiply(
|
|
987
988
|
ctm.scale(scale.sx, scale.sy)))));
|
|
988
989
|
|
|
989
|
-
this.attr('transform',
|
|
990
|
+
this.attr('transform', matrixToTransformString(transform.matrix));
|
|
990
991
|
|
|
991
992
|
return this;
|
|
992
993
|
};
|
|
@@ -1004,7 +1005,7 @@ const V = (function() {
|
|
|
1004
1005
|
this.append(animateMotion);
|
|
1005
1006
|
try {
|
|
1006
1007
|
animateMotion.node.beginElement();
|
|
1007
|
-
} catch
|
|
1008
|
+
} catch {
|
|
1008
1009
|
// Fallback for IE 9.
|
|
1009
1010
|
// Run the animation programmatically if FakeSmile (`http://leunen.me/fakesmile/`) present
|
|
1010
1011
|
if (document.documentElement.getAttribute('smiling') === 'fake') {
|
|
@@ -1287,15 +1288,12 @@ const V = (function() {
|
|
|
1287
1288
|
V.createSvgDocument = function(content) {
|
|
1288
1289
|
|
|
1289
1290
|
if (content) {
|
|
1290
|
-
const XMLString = `<svg xmlns="${ns.svg}" xmlns:xlink="${ns.xlink}" version="${
|
|
1291
|
+
const XMLString = `<svg xmlns="${ns.svg}" xmlns:xlink="${ns.xlink}" version="${SVG_VERSION}">${content}</svg>`;
|
|
1291
1292
|
const { documentElement } = V.parseXML(XMLString, { async: false });
|
|
1292
1293
|
return documentElement;
|
|
1293
1294
|
}
|
|
1294
1295
|
|
|
1295
|
-
|
|
1296
|
-
svg.setAttributeNS(ns.xmlns, 'xmlns:xlink', ns.xlink);
|
|
1297
|
-
svg.setAttribute('version', SVGVersion);
|
|
1298
|
-
return svg;
|
|
1296
|
+
return createSVGDocument();
|
|
1299
1297
|
};
|
|
1300
1298
|
|
|
1301
1299
|
V.createSVGStyle = function(stylesheet) {
|
|
@@ -1370,7 +1368,7 @@ const V = (function() {
|
|
|
1370
1368
|
}
|
|
1371
1369
|
|
|
1372
1370
|
xml = parser.parseFromString(data, 'text/xml');
|
|
1373
|
-
} catch
|
|
1371
|
+
} catch {
|
|
1374
1372
|
xml = undefined;
|
|
1375
1373
|
}
|
|
1376
1374
|
|
|
@@ -1389,6 +1387,7 @@ const V = (function() {
|
|
|
1389
1387
|
// List of attributes for which not to split camel case words.
|
|
1390
1388
|
// It contains known SVG attribute names and may be extended with user-defined attribute names.
|
|
1391
1389
|
[
|
|
1390
|
+
'attributeName',
|
|
1392
1391
|
'baseFrequency',
|
|
1393
1392
|
'baseProfile',
|
|
1394
1393
|
'clipPathUnits',
|
|
@@ -1426,6 +1425,7 @@ const V = (function() {
|
|
|
1426
1425
|
'refY',
|
|
1427
1426
|
'requiredExtensions',
|
|
1428
1427
|
'requiredFeatures',
|
|
1428
|
+
'repeatCount',
|
|
1429
1429
|
'specularConstant',
|
|
1430
1430
|
'specularExponent',
|
|
1431
1431
|
'spreadMethod',
|
|
@@ -1442,7 +1442,7 @@ const V = (function() {
|
|
|
1442
1442
|
'viewTarget', // deprecated
|
|
1443
1443
|
'xChannelSelector',
|
|
1444
1444
|
'yChannelSelector',
|
|
1445
|
-
'zoomAndPan' // deprecated
|
|
1445
|
+
'zoomAndPan', // deprecated
|
|
1446
1446
|
].forEach((name) => _attributeNames[name] = name);
|
|
1447
1447
|
|
|
1448
1448
|
_attributeNames['xlinkShow'] = 'xlink:show';
|
|
@@ -1511,108 +1511,22 @@ const V = (function() {
|
|
|
1511
1511
|
// ReDoS mitigation: Use an anchor at the beginning of the match
|
|
1512
1512
|
// ReDoS mitigation: Avoid backtracking (uses `[^()]+` instead of `.*?`)
|
|
1513
1513
|
// 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
1514
|
// The following regexes need to use capturing groups (= cannot use /g)
|
|
1517
1515
|
V.transformFunctionRegex = /\b(\w+)\(([^()]+)\)/;
|
|
1518
1516
|
V.transformTranslateRegex = /\btranslate\(([^()]+)\)/;
|
|
1519
1517
|
V.transformRotateRegex = /\brotate\(([^()]+)\)/;
|
|
1520
1518
|
V.transformScaleRegex = /\bscale\(([^()]+)\)/;
|
|
1521
1519
|
|
|
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
1520
|
|
|
1521
|
+
V.transformStringToMatrix = function(transform) {
|
|
1522
|
+
let matrix;
|
|
1523
|
+
if (V.isString(transform)) {
|
|
1524
|
+
matrix = createMatrixFromTransformString(transform);
|
|
1600
1525
|
}
|
|
1601
|
-
return
|
|
1526
|
+
return matrix || createIdentityMatrix();
|
|
1602
1527
|
};
|
|
1603
1528
|
|
|
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
|
-
};
|
|
1529
|
+
V.matrixToTransformString = matrixToTransformString;
|
|
1616
1530
|
|
|
1617
1531
|
V.parseTransformString = function(transform) {
|
|
1618
1532
|
|
|
@@ -1780,35 +1694,25 @@ const V = (function() {
|
|
|
1780
1694
|
return node instanceof SVGElement && typeof node.getScreenCTM === 'function';
|
|
1781
1695
|
};
|
|
1782
1696
|
|
|
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
|
-
};
|
|
1697
|
+
V.createSVGMatrix = createMatrix;
|
|
1794
1698
|
|
|
1795
1699
|
V.createSVGTransform = function(matrix) {
|
|
1796
1700
|
|
|
1797
1701
|
if (!V.isUndefined(matrix)) {
|
|
1798
1702
|
|
|
1799
|
-
if (!(matrix
|
|
1800
|
-
matrix =
|
|
1703
|
+
if (!isSVGMatrix(matrix)) {
|
|
1704
|
+
matrix = createMatrix(matrix);
|
|
1801
1705
|
}
|
|
1802
1706
|
|
|
1803
|
-
return
|
|
1707
|
+
return internalSVGDocument.createSVGTransformFromMatrix(matrix);
|
|
1804
1708
|
}
|
|
1805
1709
|
|
|
1806
|
-
return
|
|
1710
|
+
return internalSVGDocument.createSVGTransform();
|
|
1807
1711
|
};
|
|
1808
1712
|
|
|
1809
1713
|
V.createSVGPoint = function(x, y) {
|
|
1810
1714
|
|
|
1811
|
-
var p =
|
|
1715
|
+
var p = internalSVGDocument.createSVGPoint();
|
|
1812
1716
|
p.x = x;
|
|
1813
1717
|
p.y = y;
|
|
1814
1718
|
return p;
|
|
@@ -1816,7 +1720,7 @@ const V = (function() {
|
|
|
1816
1720
|
|
|
1817
1721
|
V.transformRect = function(r, matrix) {
|
|
1818
1722
|
|
|
1819
|
-
var p =
|
|
1723
|
+
var p = internalSVGDocument.createSVGPoint();
|
|
1820
1724
|
|
|
1821
1725
|
p.x = r.x;
|
|
1822
1726
|
p.y = r.y;
|
|
@@ -2083,8 +1987,8 @@ const V = (function() {
|
|
|
2083
1987
|
|
|
2084
1988
|
line = V(line);
|
|
2085
1989
|
var d = [
|
|
2086
|
-
'M', line.attr('x1'), line.attr('y1'),
|
|
2087
|
-
'L', line.attr('x2'), line.attr('y2')
|
|
1990
|
+
'M', line.attr('x1') || '0', line.attr('y1') || '0',
|
|
1991
|
+
'L', line.attr('x2') || '0', line.attr('y2') || '0'
|
|
2088
1992
|
].join(' ');
|
|
2089
1993
|
return d;
|
|
2090
1994
|
};
|
|
@@ -2635,7 +2539,18 @@ const V = (function() {
|
|
|
2635
2539
|
};
|
|
2636
2540
|
})();
|
|
2637
2541
|
|
|
2638
|
-
|
|
2542
|
+
/**
|
|
2543
|
+
*
|
|
2544
|
+
* @param {SVGElement|V} node1
|
|
2545
|
+
* @param {SVGElement|V} node2
|
|
2546
|
+
* @returns {SVGElement|null}
|
|
2547
|
+
*/
|
|
2548
|
+
V.getCommonAncestor = function(node1, node2) {
|
|
2549
|
+
if (!node1 || !node2) return null;
|
|
2550
|
+
return getCommonAncestor(V.toNode(node1), V.toNode(node2));
|
|
2551
|
+
};
|
|
2552
|
+
|
|
2553
|
+
V.namespace = { ...ns };
|
|
2639
2554
|
|
|
2640
2555
|
V.g = g;
|
|
2641
2556
|
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {SVGElement} node1
|
|
3
|
+
* @param {SVGElement} node2
|
|
4
|
+
* @returns {SVGElement|null}
|
|
5
|
+
* @description Finds the common ancestor node of two nodes.
|
|
6
|
+
*/
|
|
7
|
+
export function getCommonAncestor(node1, node2) {
|
|
8
|
+
// Find the common ancestor node of two nodes.
|
|
9
|
+
let parent = node1;
|
|
10
|
+
do {
|
|
11
|
+
if (parent.contains(node2)) return parent;
|
|
12
|
+
parent = parent.parentNode;
|
|
13
|
+
} while (parent);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|