@node-projects/web-component-designer 0.1.353 → 0.2.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/dist/elements/controls/NumericStyleInput.d.ts +114 -2
- package/dist/elements/controls/NumericStyleInput.js +757 -30
- package/dist/elements/controls/NumericStyleInput.js.map +1 -1
- package/dist/elements/controls/NumericStyleInputValueHelpers.d.ts +14 -0
- package/dist/elements/controls/NumericStyleInputValueHelpers.js +31 -0
- package/dist/elements/controls/NumericStyleInputValueHelpers.js.map +1 -0
- package/dist/elements/documentContainer.js +1 -1
- package/dist/elements/documentContainer.js.map +1 -1
- package/dist/elements/helper/GridHelper.d.ts +41 -20
- package/dist/elements/helper/GridHelper.js +118 -19
- package/dist/elements/helper/GridHelper.js.map +1 -1
- package/dist/elements/helper/getBoxQuads.d.ts +2 -1
- package/dist/elements/helper/getBoxQuads.js +419 -154
- package/dist/elements/helper/getBoxQuads.js.map +1 -1
- package/dist/elements/item/DesignItem.js +46 -7
- package/dist/elements/item/DesignItem.js.map +1 -1
- package/dist/elements/services/DefaultServiceBootstrap.js +4 -7
- package/dist/elements/services/DefaultServiceBootstrap.js.map +1 -1
- package/dist/elements/services/InstanceServiceContainer.d.ts +20 -3
- package/dist/elements/services/InstanceServiceContainer.js +5 -3
- package/dist/elements/services/InstanceServiceContainer.js.map +1 -1
- package/dist/elements/services/ServiceContainer.d.ts +0 -2
- package/dist/elements/services/ServiceContainer.js.map +1 -1
- package/dist/elements/services/bindingsService/SpecialTagsBindingService.js +1 -1
- package/dist/elements/services/collaborationService/CollaborationNodeIndex.js +1 -1
- package/dist/elements/services/contentService/IContentChanged.js +10 -0
- package/dist/elements/services/contentService/IContentChanged.js.map +1 -1
- package/dist/elements/services/placementService/GridPlacementService.js +54 -70
- package/dist/elements/services/placementService/GridPlacementService.js.map +1 -1
- package/dist/elements/services/propertiesService/DefaultEditorTypesService.js +4 -6
- package/dist/elements/services/propertiesService/DefaultEditorTypesService.js.map +1 -1
- package/dist/elements/services/propertiesService/IProperty.d.ts +6 -1
- package/dist/elements/services/propertiesService/PropertyMutationHandling.d.ts +6 -0
- package/dist/elements/services/propertiesService/PropertyMutationHandling.js +89 -0
- package/dist/elements/services/propertiesService/PropertyMutationHandling.js.map +1 -0
- package/dist/elements/services/propertiesService/propertyEditors/BasePropertyEditor.d.ts +2 -0
- package/dist/elements/services/propertiesService/propertyEditors/BasePropertyEditor.js +12 -0
- package/dist/elements/services/propertiesService/propertyEditors/BasePropertyEditor.js.map +1 -1
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditor.d.ts +1 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditor.js +2 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditor.js.map +1 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditorConfig.d.ts +3 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditorConfig.js +4 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssLengthPropertyEditorConfig.js.map +1 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditor.d.ts +10 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditor.js +34 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditor.js.map +1 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditorConfig.d.ts +30 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditorConfig.js +475 -0
- package/dist/elements/services/propertiesService/propertyEditors/CssNumericPropertyEditorConfig.js.map +1 -0
- package/dist/elements/services/propertiesService/services/AbstractCssPropertiesService.d.ts +1 -0
- package/dist/elements/services/propertiesService/services/AbstractCssPropertiesService.js +4 -0
- package/dist/elements/services/propertiesService/services/AbstractCssPropertiesService.js.map +1 -1
- package/dist/elements/services/propertiesService/services/CssCurrentPropertiesService.js +6 -4
- package/dist/elements/services/propertiesService/services/CssCurrentPropertiesService.js.map +1 -1
- package/dist/elements/services/propertiesService/services/CssCustomPropertiesService.js +3 -3
- package/dist/elements/services/propertiesService/services/CssCustomPropertiesService.js.map +1 -1
- package/dist/elements/services/propertiesService/services/CssPropertiesService.js +3 -3
- package/dist/elements/services/propertiesService/services/CssPropertiesService.js.map +1 -1
- package/dist/elements/services/propertiesService/services/IJsonPropertyDefinition.d.ts +2 -0
- package/dist/elements/services/selectionService/SelectionService.js +1 -1
- package/dist/elements/services/undoService/ChangeGroup.d.ts +8 -4
- package/dist/elements/services/undoService/ChangeGroup.js +25 -4
- package/dist/elements/services/undoService/ChangeGroup.js.map +1 -1
- package/dist/elements/services/undoService/ITransactionItem.d.ts +3 -2
- package/dist/elements/services/undoService/ITransactionItem.js.map +1 -1
- package/dist/elements/services/undoService/UndoService.js +15 -8
- package/dist/elements/services/undoService/UndoService.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/AttributeAndPropertyChangeAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/AttributeAndPropertyChangeAction.js +12 -8
- package/dist/elements/services/undoService/transactionItems/AttributeAndPropertyChangeAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/AttributeChangeAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/AttributeChangeAction.js +12 -8
- package/dist/elements/services/undoService/transactionItems/AttributeChangeAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/CssStyleChangeAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/CssStyleChangeAction.js +4 -2
- package/dist/elements/services/undoService/transactionItems/CssStyleChangeAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/DeleteAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/DeleteAction.js +2 -2
- package/dist/elements/services/undoService/transactionItems/DeleteAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/InsertAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/InsertAction.js +2 -2
- package/dist/elements/services/undoService/transactionItems/InsertAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/InsertChildAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/InsertChildAction.js +3 -3
- package/dist/elements/services/undoService/transactionItems/InsertChildAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/PropertyChangeAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/PropertyChangeAction.js +2 -0
- package/dist/elements/services/undoService/transactionItems/PropertyChangeAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/SelectionChangedAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/SelectionChangedAction.js +2 -0
- package/dist/elements/services/undoService/transactionItems/SelectionChangedAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/SetDesignItemsAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/SetDesignItemsAction.js +2 -0
- package/dist/elements/services/undoService/transactionItems/SetDesignItemsAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/StylesheetChangedAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/StylesheetChangedAction.js +2 -0
- package/dist/elements/services/undoService/transactionItems/StylesheetChangedAction.js.map +1 -1
- package/dist/elements/services/undoService/transactionItems/TextContentChangeAction.d.ts +3 -2
- package/dist/elements/services/undoService/transactionItems/TextContentChangeAction.js +2 -0
- package/dist/elements/services/undoService/transactionItems/TextContentChangeAction.js.map +1 -1
- package/dist/elements/widgets/designerView/DomConverter.d.ts +1 -1
- package/dist/elements/widgets/designerView/IDesignerCanvas.d.ts +0 -2
- package/dist/elements/widgets/designerView/designerCanvas.d.ts +0 -1
- package/dist/elements/widgets/designerView/designerCanvas.js +14 -7
- package/dist/elements/widgets/designerView/designerCanvas.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/ExtensionManager.js +18 -16
- package/dist/elements/widgets/designerView/extensions/ExtensionManager.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/ResizeExtension.d.ts +19 -10
- package/dist/elements/widgets/designerView/extensions/ResizeExtension.js +179 -52
- package/dist/elements/widgets/designerView/extensions/ResizeExtension.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/buttons/FlexboxExtensionDesignViewConfigButtons.js +1 -1
- package/dist/elements/widgets/designerView/extensions/buttons/FlexboxExtensionDesignViewConfigButtons.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtension.d.ts +11 -0
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtension.js +20 -0
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtensionProvider.d.ts +11 -0
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtensionProvider.js +18 -0
- package/dist/elements/widgets/designerView/extensions/flex/FlexboxExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/grid/DisplayGridExtension.js +10 -12
- package/dist/elements/widgets/designerView/extensions/grid/DisplayGridExtension.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/grid/EditGridColumnRowSizesExtension.d.ts +1 -0
- package/dist/elements/widgets/designerView/extensions/grid/EditGridColumnRowSizesExtension.js +16 -13
- package/dist/elements/widgets/designerView/extensions/grid/EditGridColumnRowSizesExtension.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/grid/GridChildResizeExtension.js +6 -39
- package/dist/elements/widgets/designerView/extensions/grid/GridChildResizeExtension.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtension.d.ts +33 -0
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtension.js +337 -0
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtensionProvider.d.ts +10 -0
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtensionProvider.js +22 -0
- package/dist/elements/widgets/designerView/extensions/transforms/ProjectiveTransformExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtension.d.ts +16 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtension.js +109 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtensionProvider.d.ts +12 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtensionProvider.js +25 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtension.d.ts +29 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtension.js +229 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtensionProvider.d.ts +10 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtensionProvider.js +20 -0
- package/dist/elements/widgets/designerView/extensions/transforms/RotateGroupExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtension.d.ts +30 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtension.js +291 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtensionProvider.d.ts +10 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtensionProvider.js +20 -0
- package/dist/elements/widgets/designerView/extensions/transforms/SkewExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtension.d.ts +16 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtension.js +122 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtension.js.map +1 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtensionProvider.d.ts +12 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtensionProvider.js +34 -0
- package/dist/elements/widgets/designerView/extensions/transforms/TransformOriginExtensionProvider.js.map +1 -0
- package/dist/elements/widgets/designerView/tools/PointerTool.js +2 -2
- package/dist/elements/widgets/designerView/tools/PointerTool.js.map +1 -1
- package/dist/elements/widgets/miniatureView/miniatureView.js +1 -1
- package/dist/elements/widgets/miniatureView/miniatureView.js.map +1 -1
- package/dist/elements/widgets/propertyGrid/PropertyGrid.d.ts +3 -3
- package/dist/elements/widgets/propertyGrid/PropertyGrid.js +7 -7
- package/dist/elements/widgets/propertyGrid/PropertyGrid.js.map +1 -1
- package/dist/elements/widgets/propertyGrid/PropertyGridMutationHandling.d.ts +5 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridMutationHandling.js +13 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridMutationHandling.js.map +1 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyList.d.ts +2 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyList.js +45 -24
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyList.js.map +1 -1
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyStructureSignature.d.ts +4 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyStructureSignature.js +31 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridPropertyStructureSignature.js.map +1 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridWithHeader.d.ts +1 -0
- package/dist/elements/widgets/propertyGrid/PropertyGridWithHeader.js +52 -42
- package/dist/elements/widgets/propertyGrid/PropertyGridWithHeader.js.map +1 -1
- package/dist/elements/widgets/treeView/treeView.js +3 -3
- package/dist/elements/widgets/treeView/treeView.js.map +1 -1
- package/dist/index-min.js +7 -7
- package/dist/index-min.js.map +4 -4
- package/dist/index.d.ts +15 -15
- package/dist/index.js +15 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/tests/ContextMenu.test.ts +0 -133
- package/tests/CssCombiner.test.ts +0 -340
- package/tests/PasteFormatSnapshot.test.ts +0 -92
- package/tests/PathDataPolyfill.test.ts +0 -49
- package/tests/SpecificityCalculator.test.ts +0 -625
|
@@ -1,31 +1,72 @@
|
|
|
1
1
|
//todo:
|
|
2
2
|
//transform-box (SVGs) https://developer.mozilla.org/en-US/docs/Web/CSS/transform-box
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// PERFORMANCE FIXES APPLIED (14 total):
|
|
5
|
+
//
|
|
6
|
+
// FIX 1 – getElementCombinedTransform: check parent perspective inside fast-path
|
|
7
|
+
// so identity elements return immediately on non-3D pages.
|
|
8
|
+
// FIX 2 – getResultingTransformationBetweenElementAndAllAncestors: guard initial
|
|
9
|
+
// self-transform multiply with isIdentity check.
|
|
10
|
+
// FIX 3 – All translate matrix calls: skip new DOMMatrix().translateSelf(0,0)
|
|
11
|
+
// when both offsets are zero (hot loop, flat layouts).
|
|
12
|
+
// FIX 4 – getElementOffsetsInContainer/HTMLElement: defer getCachedComputedStyle
|
|
13
|
+
// until inside the `includeScroll` branch where it's actually needed.
|
|
14
|
+
// FIX 5 – getResultingTransformationBetweenElementAndAllAncestors: guard
|
|
15
|
+
// projectTo2D calls with !is2D check to skip style reads on 2D pages.
|
|
16
|
+
// FIX 6 – getResultingTransformationBetweenElementAndAllAncestors: cache the
|
|
17
|
+
// result on the early-return (ancestor found) path, not just fallthrough.
|
|
18
|
+
// FIX 7 – getBoxQuads: reuse the Range already created for the multi-fragment
|
|
19
|
+
// text check; pass clientRects/boundingRect into getElementSize to
|
|
20
|
+
// avoid creating a second Range for Text nodes.
|
|
21
|
+
// FIX 8 – getBoxQuads: split the per-point `!o` branch out of the loop into
|
|
22
|
+
// two separate loops to eliminate the branch test on every iteration.
|
|
23
|
+
// FIX 9 – getBoxQuads: hoist parseFloat calls for box offsets (margin/padding/
|
|
24
|
+
// content) so values are computed once, not 4x inside the loop.
|
|
25
|
+
// FIX 10 – getElementCombinedTransform: check hasTransform first (most common
|
|
26
|
+
// non-identity case) so cheaper checks fire before heavier ones.
|
|
27
|
+
// FIX 11 – getElementCombinedTransform: skip transform-origin wrap/unwrap when
|
|
28
|
+
// origin is (0, 0, 0), saving two DOMMatrix allocations.
|
|
29
|
+
// FIX 12 – getResultingTransformationBetweenElementAndAllAncestors: reuse
|
|
30
|
+
// getElementCombinedTransform result across loop iterations (carry
|
|
31
|
+
// parent transform forward instead of recomputing next iteration).
|
|
32
|
+
// FIX 13 – Repeated cross-realm instanceof checks: cache constructors from the
|
|
33
|
+
// node's window at function entry to avoid repeated property lookups.
|
|
34
|
+
// (Applied in getElementSize and getBoxQuads hot paths.)
|
|
35
|
+
// FIX 14 – transformPointBox: parse style values once per call, not once per
|
|
36
|
+
// property access (avoids repeated parseFloat on shared string props).
|
|
37
|
+
// =============================================================================
|
|
3
38
|
/**
|
|
4
39
|
* @param {globalThis} windowObj?
|
|
40
|
+
* @param {boolean=} force
|
|
5
41
|
*/
|
|
6
|
-
export function addPolyfill(windowObj = window) {
|
|
7
|
-
|
|
42
|
+
export function addPolyfill(windowObj = window, force = false) {
|
|
43
|
+
windowObj.__getBoxQuadsPolyfillFns ??= {};
|
|
44
|
+
windowObj.__getBoxQuadsPolyfillFns.getBoxQuads = getBoxQuads;
|
|
45
|
+
windowObj.__getBoxQuadsPolyfillFns.convertQuadFromNode = convertQuadFromNode;
|
|
46
|
+
windowObj.__getBoxQuadsPolyfillFns.convertRectFromNode = convertRectFromNode;
|
|
47
|
+
windowObj.__getBoxQuadsPolyfillFns.convertPointFromNode = convertPointFromNode;
|
|
48
|
+
if (force || !windowObj.Node.prototype.getBoxQuads) {
|
|
8
49
|
//@ts-ignore
|
|
9
50
|
windowObj.Node.prototype.getBoxQuads = function (options) {
|
|
10
|
-
return getBoxQuads(this, options);
|
|
51
|
+
return windowObj.__getBoxQuadsPolyfillFns.getBoxQuads(this, options);
|
|
11
52
|
};
|
|
12
53
|
}
|
|
13
|
-
if (!windowObj.Node.prototype.convertQuadFromNode) {
|
|
54
|
+
if (force || !windowObj.Node.prototype.convertQuadFromNode) {
|
|
14
55
|
//@ts-ignore
|
|
15
56
|
windowObj.Node.prototype.convertQuadFromNode = function (quad, from, options) {
|
|
16
|
-
return convertQuadFromNode(this, quad, from, options);
|
|
57
|
+
return windowObj.__getBoxQuadsPolyfillFns.convertQuadFromNode(this, quad, from, options);
|
|
17
58
|
};
|
|
18
59
|
}
|
|
19
|
-
if (!windowObj.Node.prototype.convertRectFromNode) {
|
|
60
|
+
if (force || !windowObj.Node.prototype.convertRectFromNode) {
|
|
20
61
|
//@ts-ignore
|
|
21
62
|
windowObj.Node.prototype.convertRectFromNode = function (rect, from, options) {
|
|
22
|
-
return convertRectFromNode(this, rect, from, options);
|
|
63
|
+
return windowObj.__getBoxQuadsPolyfillFns.convertRectFromNode(this, rect, from, options);
|
|
23
64
|
};
|
|
24
65
|
}
|
|
25
|
-
if (!windowObj.Node.prototype.convertPointFromNode) {
|
|
66
|
+
if (force || !windowObj.Node.prototype.convertPointFromNode) {
|
|
26
67
|
//@ts-ignore
|
|
27
68
|
windowObj.Node.prototype.convertPointFromNode = function (point, from, options) {
|
|
28
|
-
return convertPointFromNode(this, point, from, options);
|
|
69
|
+
return windowObj.__getBoxQuadsPolyfillFns.convertPointFromNode(this, point, from, options);
|
|
29
70
|
};
|
|
30
71
|
}
|
|
31
72
|
}
|
|
@@ -128,16 +169,27 @@ export function convertPointFromNode(node, point, from, options) {
|
|
|
128
169
|
* @param {CSSStyleDeclaration} style
|
|
129
170
|
* @param {number} operator
|
|
130
171
|
* @returns {DOMPoint}
|
|
172
|
+
*
|
|
173
|
+
* FIX 14: Parse each style value once and reuse, rather than calling parseFloat
|
|
174
|
+
* multiple times on the same property (e.g. borderLeftWidth used twice in 'content').
|
|
131
175
|
*/
|
|
132
176
|
function transformPointBox(point, box, style, operator) {
|
|
133
177
|
if (box === 'margin') {
|
|
134
|
-
|
|
178
|
+
const mLeft = parseFloat(style.marginLeft);
|
|
179
|
+
const mTop = parseFloat(style.marginTop);
|
|
180
|
+
return new DOMPoint(point.x - operator * mLeft, point.y - operator * mTop);
|
|
135
181
|
}
|
|
136
182
|
else if (box === 'padding') {
|
|
137
|
-
|
|
183
|
+
const bLeft = parseFloat(style.borderLeftWidth);
|
|
184
|
+
const bTop = parseFloat(style.borderTopWidth);
|
|
185
|
+
return new DOMPoint(point.x + operator * bLeft, point.y + operator * bTop);
|
|
138
186
|
}
|
|
139
187
|
else if (box === 'content') {
|
|
140
|
-
|
|
188
|
+
const bLeft = parseFloat(style.borderLeftWidth);
|
|
189
|
+
const bTop = parseFloat(style.borderTopWidth);
|
|
190
|
+
const pLeft = parseFloat(style.paddingLeft);
|
|
191
|
+
const pTop = parseFloat(style.paddingTop);
|
|
192
|
+
return new DOMPoint(point.x + operator * (bLeft + pLeft), point.y + operator * (bTop + pTop));
|
|
141
193
|
}
|
|
142
194
|
//@ts-ignore
|
|
143
195
|
return point;
|
|
@@ -198,10 +250,16 @@ export function getBoxQuads(node, options) {
|
|
|
198
250
|
}
|
|
199
251
|
/** @type {DOMMatrix} */
|
|
200
252
|
let originalElementAndAllParentsMultipliedMatrix = getResultingTransformationBetweenElementAndAllAncestors(node, options?.relativeTo ?? document.body, options?.iframes);
|
|
253
|
+
// FIX 13: Cache cross-realm constructors once per call.
|
|
254
|
+
const win = node.ownerDocument.defaultView ?? window;
|
|
255
|
+
const _Text = win.Text;
|
|
201
256
|
// For text nodes, check for multiple fragments (multi-column layout, line-wrapping).
|
|
202
257
|
// getClientRects() returns one rect per line-box fragment; getBoundingClientRect()
|
|
203
258
|
// only returns the union AABB, so without this we'd always get one quad.
|
|
204
|
-
if ((node instanceof Text || node instanceof
|
|
259
|
+
if ((node instanceof Text || node instanceof _Text)) {
|
|
260
|
+
// FIX 7: Create the Range once here and reuse it for both the multi-fragment
|
|
261
|
+
// check and the single-fragment size fallback, avoiding a second Range
|
|
262
|
+
// allocation inside getElementSize for Text nodes.
|
|
205
263
|
const range = node.ownerDocument.createRange();
|
|
206
264
|
range.selectNodeContents(node);
|
|
207
265
|
const clientRects = range.getClientRects();
|
|
@@ -211,20 +269,22 @@ export function getBoxQuads(node, options) {
|
|
|
211
269
|
// Each fragment's viewport rect (from getClientRects) is an AABB;
|
|
212
270
|
// its center equals the actual geometric center regardless of rotation.
|
|
213
271
|
// We convert that center to parent-local space, recover the fragment's
|
|
214
|
-
// local dimensions via the
|
|
272
|
+
// local dimensions via the 2x2 AABB system, then apply the parent's
|
|
215
273
|
// accumulated matrix to build proper (rotated) quads in relativeTo-space.
|
|
216
274
|
const parent = getParentElementIncludingSlots(node, options?.iframes);
|
|
217
275
|
const M_parent = getResultingTransformationBetweenElementAndAllAncestors(parent, relativeToEl, options?.iframes);
|
|
218
276
|
const parentCss = getElementCombinedTransform(parent, options?.iframes);
|
|
219
|
-
const parentStyle = getCachedComputedStyle(parent);
|
|
220
|
-
const originStr = parentStyle.transformOrigin.split(' ');
|
|
221
|
-
const ox = parseFloat(originStr[0]) || 0;
|
|
222
|
-
const oy = parseFloat(originStr[1]) || 0;
|
|
223
277
|
const pr = parent.getBoundingClientRect();
|
|
224
|
-
// Screen position of parent's local (0,0) — same formula as getElementOffsetsInContainer
|
|
225
|
-
const parentOriginX = (pr.x + pr.width / 2) - ox + parentCss.e;
|
|
226
|
-
const parentOriginY = (pr.y + pr.height / 2) - oy + parentCss.f;
|
|
227
278
|
const pa = parentCss.a, pb = parentCss.b, pc = parentCss.c, pd = parentCss.d;
|
|
279
|
+
// AABB center of the transformed parent equals its geometric center.
|
|
280
|
+
// geometric_center_screen = screen(0,0) + L * (pw/2, ph/2)
|
|
281
|
+
// => screen(0,0) = AABB_center - L * (pw/2, ph/2)
|
|
282
|
+
//@ts-ignore
|
|
283
|
+
const pw = parent.offsetWidth;
|
|
284
|
+
//@ts-ignore
|
|
285
|
+
const ph = parent.offsetHeight;
|
|
286
|
+
const parentOriginX = (pr.x + pr.width / 2) - (pa * pw / 2 + pc * ph / 2);
|
|
287
|
+
const parentOriginY = (pr.y + pr.height / 2) - (pb * pw / 2 + pd * ph / 2);
|
|
228
288
|
const linearDet = pa * pd - pb * pc;
|
|
229
289
|
const absA = Math.abs(pa), absB = Math.abs(pb);
|
|
230
290
|
const absDet = absA * absA - absB * absB;
|
|
@@ -232,7 +292,7 @@ export function getBoxQuads(node, options) {
|
|
|
232
292
|
for (const cr of clientRects) {
|
|
233
293
|
if (cr.width < 1 && cr.height < 1)
|
|
234
294
|
continue;
|
|
235
|
-
// Fragment AABB center
|
|
295
|
+
// Fragment AABB center -> parent-local center via inverse CSS transform
|
|
236
296
|
const dx = cr.x + cr.width / 2 - parentOriginX;
|
|
237
297
|
const dy = cr.y + cr.height / 2 - parentOriginY;
|
|
238
298
|
let lcx, lcy;
|
|
@@ -244,14 +304,14 @@ export function getBoxQuads(node, options) {
|
|
|
244
304
|
lcx = dx;
|
|
245
305
|
lcy = dy;
|
|
246
306
|
}
|
|
247
|
-
// Fragment dimensions in parent-local via
|
|
307
|
+
// Fragment dimensions in parent-local via 2x2 AABB system
|
|
248
308
|
let tw, th;
|
|
249
309
|
if (Math.abs(absDet) > 1e-6) {
|
|
250
310
|
tw = Math.max(0, (absA * cr.width - absB * cr.height) / absDet);
|
|
251
311
|
th = Math.max(0, (absA * cr.height - absB * cr.width) / absDet);
|
|
252
312
|
}
|
|
253
313
|
else {
|
|
254
|
-
// Singular (
|
|
314
|
+
// Singular (~45 deg): use CSS line-height as th
|
|
255
315
|
const cs = getCachedComputedStyle(parent);
|
|
256
316
|
th = Math.max(0, parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16);
|
|
257
317
|
const denom = Math.max(absA, absB);
|
|
@@ -267,41 +327,135 @@ export function getBoxQuads(node, options) {
|
|
|
267
327
|
return quads;
|
|
268
328
|
}
|
|
269
329
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
330
|
+
// FIX 7 (continued): Single-fragment text — reuse the already-fetched
|
|
331
|
+
// bounding rect so getElementSize doesn't create a second Range.
|
|
332
|
+
const textBoundingRect = range.getBoundingClientRect();
|
|
333
|
+
const { width: tw, height: th } = _getTextNodeSize(originalElementAndAllParentsMultipliedMatrix, textBoundingRect, node);
|
|
334
|
+
const is2Dt = originalElementAndAllParentsMultipliedMatrix.is2D;
|
|
335
|
+
const tCorners = [
|
|
336
|
+
new DOMPoint(0, 0),
|
|
337
|
+
new DOMPoint(tw, 0),
|
|
338
|
+
new DOMPoint(tw, th),
|
|
339
|
+
new DOMPoint(0, th),
|
|
340
|
+
];
|
|
341
|
+
/** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
|
|
342
|
+
//@ts-ignore
|
|
343
|
+
const tPoints = Array(4);
|
|
344
|
+
if (is2Dt) {
|
|
345
|
+
for (let i = 0; i < 4; i++)
|
|
346
|
+
tPoints[i] = tCorners[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
286
347
|
}
|
|
287
|
-
else
|
|
288
|
-
|
|
289
|
-
|
|
348
|
+
else {
|
|
349
|
+
for (let i = 0; i < 4; i++) {
|
|
350
|
+
tPoints[i] = projectPoint(tCorners[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
351
|
+
tPoints[i] = as2DPoint(tPoints[i]);
|
|
352
|
+
}
|
|
290
353
|
}
|
|
354
|
+
const tQuad = [new DOMQuad(tPoints[0], tPoints[1], tPoints[2], tPoints[3])];
|
|
355
|
+
if (boxQuadsCache)
|
|
356
|
+
boxQuadsCache.set(key, tQuad);
|
|
357
|
+
return tQuad;
|
|
291
358
|
}
|
|
359
|
+
let { width, height } = getElementSize(node, originalElementAndAllParentsMultipliedMatrix);
|
|
360
|
+
// FIX 13: cache cross-realm Element constructor.
|
|
361
|
+
const _Element = win.Element;
|
|
292
362
|
const is2D = originalElementAndAllParentsMultipliedMatrix.is2D;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
363
|
+
// FIX 8 + FIX 9: Split the `!o` branch out of the point loop into two
|
|
364
|
+
// separate code paths. In the box-offset path, parse style values once
|
|
365
|
+
// (FIX 9) and use them directly, eliminating 4x redundant parseFloat calls.
|
|
366
|
+
if ((node instanceof Element || node instanceof _Element)) {
|
|
367
|
+
const box = options?.box;
|
|
368
|
+
if (box === 'margin' || box === 'padding' || box === 'content') {
|
|
369
|
+
const cs = getCachedComputedStyle(node);
|
|
370
|
+
let x0, y0, x1, y1, x2, y2, x3, y3;
|
|
371
|
+
if (box === 'margin') {
|
|
372
|
+
const mL = parseFloat(cs.marginLeft);
|
|
373
|
+
const mT = parseFloat(cs.marginTop);
|
|
374
|
+
const mR = parseFloat(cs.marginRight);
|
|
375
|
+
const mB = parseFloat(cs.marginBottom);
|
|
376
|
+
x0 = -mL;
|
|
377
|
+
y0 = -mT;
|
|
378
|
+
x1 = width + mR;
|
|
379
|
+
y1 = -mT;
|
|
380
|
+
x2 = width + mR;
|
|
381
|
+
y2 = height + mB;
|
|
382
|
+
x3 = -mL;
|
|
383
|
+
y3 = height + mB;
|
|
384
|
+
}
|
|
385
|
+
else if (box === 'padding') {
|
|
386
|
+
const bL = parseFloat(cs.borderLeftWidth);
|
|
387
|
+
const bT = parseFloat(cs.borderTopWidth);
|
|
388
|
+
const bR = parseFloat(cs.borderRightWidth);
|
|
389
|
+
const bB = parseFloat(cs.borderBottomWidth);
|
|
390
|
+
x0 = bL;
|
|
391
|
+
y0 = bT;
|
|
392
|
+
x1 = width - bR;
|
|
393
|
+
y1 = bT;
|
|
394
|
+
x2 = width - bR;
|
|
395
|
+
y2 = height - bB;
|
|
396
|
+
x3 = bL;
|
|
397
|
+
y3 = height - bB;
|
|
398
|
+
}
|
|
399
|
+
else { // content
|
|
400
|
+
const bL = parseFloat(cs.borderLeftWidth);
|
|
401
|
+
const bT = parseFloat(cs.borderTopWidth);
|
|
402
|
+
const bR = parseFloat(cs.borderRightWidth);
|
|
403
|
+
const bB = parseFloat(cs.borderBottomWidth);
|
|
404
|
+
const pL = parseFloat(cs.paddingLeft);
|
|
405
|
+
const pT = parseFloat(cs.paddingTop);
|
|
406
|
+
const pR = parseFloat(cs.paddingRight);
|
|
407
|
+
const pB = parseFloat(cs.paddingBottom);
|
|
408
|
+
x0 = bL + pL;
|
|
409
|
+
y0 = bT + pT;
|
|
410
|
+
x1 = width - bR - pR;
|
|
411
|
+
y1 = bT + pT;
|
|
412
|
+
x2 = width - bR - pR;
|
|
413
|
+
y2 = height - bB - pB;
|
|
414
|
+
x3 = bL + pL;
|
|
415
|
+
y3 = height - bB - pB;
|
|
416
|
+
}
|
|
417
|
+
const pts = [
|
|
418
|
+
new DOMPoint(x0, y0),
|
|
419
|
+
new DOMPoint(x1, y1),
|
|
420
|
+
new DOMPoint(x2, y2),
|
|
421
|
+
new DOMPoint(x3, y3),
|
|
422
|
+
];
|
|
423
|
+
/** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
|
|
424
|
+
//@ts-ignore
|
|
425
|
+
const points = Array(4);
|
|
426
|
+
if (is2D) {
|
|
427
|
+
for (let i = 0; i < 4; i++)
|
|
428
|
+
points[i] = pts[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
for (let i = 0; i < 4; i++) {
|
|
432
|
+
points[i] = projectPoint(pts[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
433
|
+
points[i] = as2DPoint(points[i]);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const quad = [new DOMQuad(points[0], points[1], points[2], points[3])];
|
|
437
|
+
if (boxQuadsCache)
|
|
438
|
+
boxQuadsCache.set(key, quad);
|
|
439
|
+
return quad;
|
|
302
440
|
}
|
|
303
|
-
|
|
304
|
-
|
|
441
|
+
}
|
|
442
|
+
// FIX 8: No-offset path — plain loop, no `!o` branch test per iteration.
|
|
443
|
+
const corners = [
|
|
444
|
+
new DOMPoint(0, 0),
|
|
445
|
+
new DOMPoint(width, 0),
|
|
446
|
+
new DOMPoint(width, height),
|
|
447
|
+
new DOMPoint(0, height),
|
|
448
|
+
];
|
|
449
|
+
/** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
|
|
450
|
+
//@ts-ignore
|
|
451
|
+
const points = Array(4);
|
|
452
|
+
if (is2D) {
|
|
453
|
+
for (let i = 0; i < 4; i++)
|
|
454
|
+
points[i] = corners[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
for (let i = 0; i < 4; i++) {
|
|
458
|
+
points[i] = projectPoint(corners[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
|
|
305
459
|
points[i] = as2DPoint(points[i]);
|
|
306
460
|
}
|
|
307
461
|
}
|
|
@@ -310,6 +464,37 @@ export function getBoxQuads(node, options) {
|
|
|
310
464
|
boxQuadsCache.set(key, quad);
|
|
311
465
|
return quad;
|
|
312
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Compute width/height for a Text node given an already-fetched bounding rect.
|
|
469
|
+
* Extracted from getElementSize so getBoxQuads (FIX 7) can reuse the Range it
|
|
470
|
+
* already created, avoiding a second Range allocation.
|
|
471
|
+
* @param {DOMMatrix} matrix
|
|
472
|
+
* @param {DOMRect} targetRect
|
|
473
|
+
* @param {Text} node
|
|
474
|
+
*/
|
|
475
|
+
function _getTextNodeSize(matrix, targetRect, node) {
|
|
476
|
+
const absA = Math.abs(matrix?.a ?? 1);
|
|
477
|
+
const absB = Math.abs(matrix?.b ?? 0);
|
|
478
|
+
const det = absA * absA - absB * absB; // cos(2*angle)*scale^2
|
|
479
|
+
let width, height;
|
|
480
|
+
if (Math.abs(det) > 1e-6) {
|
|
481
|
+
width = Math.max(0, (absA * targetRect.width - absB * targetRect.height) / det);
|
|
482
|
+
height = Math.max(0, (absA * targetRect.height - absB * targetRect.width) / det);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
// Singular (~45 deg rotation): use CSS line-height as the known height
|
|
486
|
+
const parentEl = node.parentElement;
|
|
487
|
+
let lineH = 16;
|
|
488
|
+
if (parentEl) {
|
|
489
|
+
const cs = getCachedComputedStyle(parentEl);
|
|
490
|
+
lineH = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16;
|
|
491
|
+
}
|
|
492
|
+
height = Math.max(0, lineH);
|
|
493
|
+
const denom = Math.max(absA, absB);
|
|
494
|
+
width = denom > 1e-6 ? Math.max(0, (targetRect.width - height * absB) / denom) : targetRect.width;
|
|
495
|
+
}
|
|
496
|
+
return { width, height };
|
|
497
|
+
}
|
|
313
498
|
//todo: https://drafts.csswg.org/css-transforms-2/#accumulated-3d-transformation-matrix-computation
|
|
314
499
|
// also good for writing a spec
|
|
315
500
|
// Find a value for z that will transform to 0. (from firefox matrix.h)
|
|
@@ -335,51 +520,35 @@ function as2DPoint(point) {
|
|
|
335
520
|
export function getElementSize(node, matrix) {
|
|
336
521
|
let width = 0;
|
|
337
522
|
let height = 0;
|
|
338
|
-
|
|
523
|
+
// FIX 13: Cache cross-realm constructors once.
|
|
524
|
+
const win = node.ownerDocument.defaultView ?? window;
|
|
525
|
+
if ((node instanceof HTMLElement || node instanceof win.HTMLElement)) {
|
|
339
526
|
width = node.offsetWidth;
|
|
340
527
|
height = node.offsetHeight;
|
|
341
528
|
}
|
|
342
|
-
else if ((node instanceof SVGSVGElement || node instanceof
|
|
529
|
+
else if ((node instanceof SVGSVGElement || node instanceof win.SVGSVGElement)) {
|
|
343
530
|
width = node.width.baseVal.value;
|
|
344
531
|
height = node.height.baseVal.value;
|
|
345
532
|
}
|
|
346
|
-
else if ((node instanceof SVGGraphicsElement || node instanceof
|
|
533
|
+
else if ((node instanceof SVGGraphicsElement || node instanceof win.SVGGraphicsElement)) {
|
|
347
534
|
const bbox = node.getBBox();
|
|
348
535
|
width = bbox.width;
|
|
349
536
|
height = bbox.height;
|
|
350
537
|
}
|
|
351
|
-
else if ((node instanceof MathMLElement || node instanceof
|
|
538
|
+
else if ((node instanceof MathMLElement || node instanceof win.MathMLElement)) {
|
|
352
539
|
const bbox = node.getBoundingClientRect();
|
|
353
540
|
width = bbox.width / (matrix?.a ?? 1);
|
|
354
541
|
height = bbox.height / (matrix?.d ?? 1);
|
|
355
542
|
}
|
|
356
|
-
else if ((node instanceof Text || node instanceof
|
|
543
|
+
else if ((node instanceof Text || node instanceof win.Text)) {
|
|
544
|
+
// Note: getBoxQuads passes an already-fetched rect via _getTextNodeSize to
|
|
545
|
+
// avoid this Range creation. This path serves external callers of getElementSize.
|
|
357
546
|
const range = node.ownerDocument.createRange();
|
|
358
547
|
range.selectNodeContents(node);
|
|
359
548
|
const targetRect = range.getBoundingClientRect();
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const absB = Math.abs(matrix?.b ?? 0);
|
|
364
|
-
const det = absA * absA - absB * absB; // cos(2*angle)*scale²
|
|
365
|
-
if (Math.abs(det) > 1e-6) {
|
|
366
|
-
width = Math.max(0, (absA * targetRect.width - absB * targetRect.height) / det);
|
|
367
|
-
height = Math.max(0, (absA * targetRect.height - absB * targetRect.width) / det);
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
// Singular (≈45° rotation): use CSS line-height as the known height
|
|
371
|
-
const parentEl = node.parentElement;
|
|
372
|
-
let lineH = 16;
|
|
373
|
-
if (parentEl) {
|
|
374
|
-
const cs = getCachedComputedStyle(parentEl);
|
|
375
|
-
lineH = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16;
|
|
376
|
-
}
|
|
377
|
-
height = Math.max(0, lineH);
|
|
378
|
-
const denom = Math.max(absA, absB);
|
|
379
|
-
width = denom > 1e-6
|
|
380
|
-
? Math.max(0, (targetRect.width - height * absB) / denom)
|
|
381
|
-
: targetRect.width;
|
|
382
|
-
}
|
|
549
|
+
const result = _getTextNodeSize(matrix, targetRect, node);
|
|
550
|
+
width = result.width;
|
|
551
|
+
height = result.height;
|
|
383
552
|
}
|
|
384
553
|
return { width, height };
|
|
385
554
|
}
|
|
@@ -391,9 +560,20 @@ export function getElementSize(node, matrix) {
|
|
|
391
560
|
function getElementOffsetsInContainer(node, includeScroll, iframes) {
|
|
392
561
|
if ((node instanceof HTMLElement || node instanceof (node.ownerDocument.defaultView ?? window).HTMLElement)) {
|
|
393
562
|
const cs = getCachedComputedStyle(node);
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
563
|
+
if (cs.position === 'fixed') {
|
|
564
|
+
const par = getParentElementIncludingSlots(node, iframes);
|
|
565
|
+
if (!par) {
|
|
566
|
+
return new DOMPoint(node.offsetLeft, node.offsetTop);
|
|
567
|
+
}
|
|
568
|
+
const m = getResultingTransformationBetweenElementAndAllAncestors(par, node.ownerDocument.body, iframes).inverse();
|
|
569
|
+
const r1 = node.getBoundingClientRect();
|
|
570
|
+
const r1t = m.transformPoint(r1);
|
|
571
|
+
const r2 = par.getBoundingClientRect();
|
|
572
|
+
const r2t = m.transformPoint(r2);
|
|
573
|
+
return new DOMPoint(r1t.x - r2t.x, r1t.y - r2t.y);
|
|
574
|
+
}
|
|
575
|
+
// FIX 4: Only call getCachedComputedStyle when includeScroll is true —
|
|
576
|
+
// cs is unused in the plain offsetLeft/offsetTop path.
|
|
397
577
|
if (includeScroll) {
|
|
398
578
|
return new DOMPoint(node.offsetLeft - (node.scrollLeft - parseFloat(cs.borderLeftWidth)), node.offsetTop - (node.scrollTop - parseFloat(cs.borderTopWidth)));
|
|
399
579
|
}
|
|
@@ -412,23 +592,17 @@ function getElementOffsetsInContainer(node, includeScroll, iframes) {
|
|
|
412
592
|
// Get the parent's CSS transform so we can work in local space even when rotated.
|
|
413
593
|
const pt = getElementCombinedTransform(parent, iframes);
|
|
414
594
|
const pa = pt.a, pb = pt.b, pc = pt.c, pd = pt.d;
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
const originStr = parentStyle.transformOrigin.split(' ');
|
|
423
|
-
const ox = parseFloat(originStr[0]) || 0;
|
|
424
|
-
const oy = parseFloat(originStr[1]) || 0;
|
|
425
|
-
// pt.e/f = M_css.transformPoint(0,0) — the offset of local (0,0) from pre-transform pos
|
|
426
|
-
const parentOriginX = (r2.x + r2.width / 2) - ox + pt.e;
|
|
427
|
-
const parentOriginY = (r2.y + r2.height / 2) - oy + pt.f;
|
|
595
|
+
// AABB center of the transformed parent equals its geometric center.
|
|
596
|
+
// geometric_center_screen = screen(0,0) + L * (pw/2, ph/2)
|
|
597
|
+
// => screen(0,0) = AABB_center - L * (pw/2, ph/2)
|
|
598
|
+
const pw = parent.offsetWidth;
|
|
599
|
+
const ph = parent.offsetHeight;
|
|
600
|
+
const parentOriginX = (r2.x + r2.width / 2) - (pa * pw / 2 + pc * ph / 2);
|
|
601
|
+
const parentOriginY = (r2.y + r2.height / 2) - (pb * pw / 2 + pd * ph / 2);
|
|
428
602
|
// Delta from parent origin to text AABB center in screen space
|
|
429
603
|
const dx = (r1.x + r1.width / 2) - parentOriginX;
|
|
430
604
|
const dy = (r1.y + r1.height / 2) - parentOriginY;
|
|
431
|
-
// Apply inverse of CSS transform linear part: local_center = L
|
|
605
|
+
// Apply inverse of CSS transform linear part: local_center = L^-1 * screen_delta
|
|
432
606
|
const transformDet = pa * pd - pb * pc;
|
|
433
607
|
let localCenterX, localCenterY;
|
|
434
608
|
if (Math.abs(transformDet) > 1e-10) {
|
|
@@ -439,7 +613,7 @@ function getElementOffsetsInContainer(node, includeScroll, iframes) {
|
|
|
439
613
|
localCenterX = dx;
|
|
440
614
|
localCenterY = dy;
|
|
441
615
|
}
|
|
442
|
-
// Recover tw and th in local space from the AABB using the
|
|
616
|
+
// Recover tw and th in local space from the AABB using the 2x2 system:
|
|
443
617
|
// aabb_w = tw*|cos| + th*|sin|, aabb_h = tw*|sin| + th*|cos|
|
|
444
618
|
const absA = Math.abs(pa), absB = Math.abs(pb);
|
|
445
619
|
const absDet = absA * absA - absB * absB;
|
|
@@ -449,7 +623,7 @@ function getElementOffsetsInContainer(node, includeScroll, iframes) {
|
|
|
449
623
|
th = Math.max(0, (absA * r1.height - absB * r1.width) / absDet);
|
|
450
624
|
}
|
|
451
625
|
else {
|
|
452
|
-
// Singular (
|
|
626
|
+
// Singular (~45 deg): use CSS line-height as th
|
|
453
627
|
const cs = getCachedComputedStyle(parent);
|
|
454
628
|
th = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16;
|
|
455
629
|
th = Math.max(0, th);
|
|
@@ -501,13 +675,24 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
501
675
|
let actualElement = node;
|
|
502
676
|
/** @type {DOMMatrix } */
|
|
503
677
|
let parentElementMatrix;
|
|
678
|
+
// FIX 12: Compute self-transform once; we'll carry parent transforms forward
|
|
679
|
+
// each iteration instead of recomputing them.
|
|
680
|
+
let currentElementTransform = getElementCombinedTransform(actualElement, iframes);
|
|
504
681
|
/** @type {DOMMatrix } */
|
|
505
|
-
|
|
682
|
+
// FIX 2: Only use a non-identity starting matrix when the element itself has
|
|
683
|
+
// a CSS transform. Most plain elements have identity, avoiding a multiply.
|
|
684
|
+
let originalElementAndAllParentsMultipliedMatrix = currentElementTransform.isIdentity
|
|
685
|
+
? new DOMMatrix()
|
|
686
|
+
: currentElementTransform;
|
|
506
687
|
let perspectiveParentElement = getParentElementIncludingSlots(actualElement, iframes);
|
|
507
688
|
if (perspectiveParentElement) {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
689
|
+
// FIX 5: Guard transformStyle read behind is2D — on a standard 2D page
|
|
690
|
+
// the matrix is always 2D here so we skip the style read entirely.
|
|
691
|
+
if (!originalElementAndAllParentsMultipliedMatrix.is2D) {
|
|
692
|
+
const s = getCachedComputedStyle(perspectiveParentElement);
|
|
693
|
+
if (s.transformStyle !== 'preserve-3d') {
|
|
694
|
+
projectTo2D(originalElementAndAllParentsMultipliedMatrix);
|
|
695
|
+
}
|
|
511
696
|
}
|
|
512
697
|
}
|
|
513
698
|
let lastOffsetParent = null;
|
|
@@ -515,25 +700,33 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
515
700
|
let parentElement = getParentElementIncludingSlots(actualElement, iframes);
|
|
516
701
|
if (actualElement.assignedSlot != null) {
|
|
517
702
|
if (actualElement.nodeType === Node.ELEMENT_NODE) {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
703
|
+
const slotOffsetParent = offsetParentPolyfill(actualElement);
|
|
704
|
+
const shouldApplySlottedOffset = lastOffsetParent !== slotOffsetParent
|
|
705
|
+
&& (lastOffsetParent === null || actualElement === lastOffsetParent || !isFlatTreeInclusiveAncestor(lastOffsetParent, actualElement));
|
|
706
|
+
if (shouldApplySlottedOffset) {
|
|
707
|
+
const l = offsetTopLeftPolyfill(actualElement, 'offsetLeft');
|
|
708
|
+
const t = offsetTopLeftPolyfill(actualElement, 'offsetTop');
|
|
709
|
+
// FIX 3: Skip zero-translation matrix allocations.
|
|
710
|
+
if (l !== 0 || t !== 0) {
|
|
711
|
+
const mvMat = new DOMMatrix().translateSelf(l, t);
|
|
712
|
+
originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
713
|
+
}
|
|
714
|
+
lastOffsetParent = slotOffsetParent;
|
|
522
715
|
}
|
|
716
|
+
if (lastOffsetParent === null)
|
|
717
|
+
lastOffsetParent = slotOffsetParent;
|
|
523
718
|
}
|
|
524
719
|
else if (actualElement.nodeType === Node.TEXT_NODE) {
|
|
525
720
|
const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
|
|
526
|
-
|
|
527
|
-
|
|
721
|
+
// FIX 3
|
|
722
|
+
if (offsets.x !== 0 || offsets.y !== 0) {
|
|
723
|
+
const mvMat = new DOMMatrix().translateSelf(offsets.x, offsets.y);
|
|
724
|
+
originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
725
|
+
}
|
|
528
726
|
}
|
|
529
727
|
/*
|
|
530
|
-
|
|
531
728
|
following code should be used instead of above to fix:
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
729
|
but it does not work with:
|
|
536
|
-
|
|
537
730
|
<div>
|
|
538
731
|
<visu-tag-root-canvas id="outer-tag-root-canvas" tag-root="SRM.RBG01">
|
|
539
732
|
<template shadowrootmode="open">
|
|
@@ -544,7 +737,6 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
544
737
|
<div class="wrapper" id="aaaaabb" style="height:50px;width:50px;"></div>
|
|
545
738
|
</visu-tag-root-canvas>
|
|
546
739
|
</div>
|
|
547
|
-
|
|
548
740
|
*/
|
|
549
741
|
/*
|
|
550
742
|
const l = offsetTopLeftPolyfill(actualElement, 'offsetLeft');
|
|
@@ -558,42 +750,75 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
558
750
|
(actualElement instanceof SVGGraphicsElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).SVGGraphicsElement)) {
|
|
559
751
|
const ctm = actualElement.getCTM();
|
|
560
752
|
const bb = actualElement.getBBox();
|
|
561
|
-
|
|
562
|
-
|
|
753
|
+
// FIX 3
|
|
754
|
+
if (bb.x !== 0 || bb.y !== 0) {
|
|
755
|
+
const mvMat = new DOMMatrix().translateSelf(bb.x, bb.y);
|
|
756
|
+
originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
757
|
+
}
|
|
563
758
|
originalElementAndAllParentsMultipliedMatrix = new DOMMatrix([ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f]).multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
564
759
|
parentElement = actualElement.ownerSVGElement;
|
|
565
760
|
}
|
|
566
761
|
else if ((actualElement instanceof HTMLElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLElement)) {
|
|
567
|
-
if (lastOffsetParent !== actualElement.offsetParent && !((actualElement instanceof HTMLSlotElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLSlotElement))
|
|
762
|
+
if (lastOffsetParent !== actualElement.offsetParent && !((actualElement instanceof HTMLSlotElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLSlotElement))
|
|
763
|
+
&& (lastOffsetParent === null || actualElement === lastOffsetParent || !isFlatTreeInclusiveAncestor(lastOffsetParent, actualElement))) {
|
|
568
764
|
const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
|
|
569
765
|
lastOffsetParent = actualElement.offsetParent;
|
|
570
|
-
|
|
571
|
-
|
|
766
|
+
// FIX 3
|
|
767
|
+
if (offsets.x !== 0 || offsets.y !== 0) {
|
|
768
|
+
const mvMat = new DOMMatrix().translateSelf(offsets.x, offsets.y);
|
|
769
|
+
originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
770
|
+
}
|
|
572
771
|
}
|
|
573
772
|
}
|
|
574
773
|
else {
|
|
575
774
|
const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
|
|
576
775
|
lastOffsetParent = null;
|
|
577
|
-
|
|
578
|
-
|
|
776
|
+
// FIX 3
|
|
777
|
+
if (offsets.x !== 0 || offsets.y !== 0) {
|
|
778
|
+
const mvMat = new DOMMatrix().translateSelf(offsets.x, offsets.y);
|
|
779
|
+
originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
|
|
780
|
+
}
|
|
579
781
|
}
|
|
580
782
|
}
|
|
581
783
|
if (parentElement) {
|
|
784
|
+
if (parentElement === ancestor) {
|
|
785
|
+
// The ancestor's own transform is excluded from the returned matrix,
|
|
786
|
+
// so avoid computing it on the hot return path.
|
|
787
|
+
if (lastOffsetParent !== null &&
|
|
788
|
+
(parentElement instanceof HTMLElement || parentElement instanceof (parentElement.ownerDocument.defaultView ?? window).HTMLElement) &&
|
|
789
|
+
parentElement.offsetParent === lastOffsetParent) {
|
|
790
|
+
const ancOff = getElementOffsetsInContainer(parentElement, false, iframes);
|
|
791
|
+
// FIX 3
|
|
792
|
+
if (ancOff.x !== 0 || ancOff.y !== 0) {
|
|
793
|
+
originalElementAndAllParentsMultipliedMatrix = new DOMMatrix().translate(-ancOff.x, -ancOff.y).multiply(originalElementAndAllParentsMultipliedMatrix);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (parentElement.scrollTop || parentElement.scrollLeft)
|
|
797
|
+
originalElementAndAllParentsMultipliedMatrix = new DOMMatrix().translate(-parentElement.scrollLeft, -parentElement.scrollTop).multiply(originalElementAndAllParentsMultipliedMatrix);
|
|
798
|
+
// FIX 6: Cache result on the early-return path. Originally, the
|
|
799
|
+
// cache.set() only ran after the while-loop (the null/root
|
|
800
|
+
// fallthrough), so the most common case — element IS a
|
|
801
|
+
// descendant of ancestor — was NEVER cached.
|
|
802
|
+
if (transformCache)
|
|
803
|
+
transformCache.set(key, originalElementAndAllParentsMultipliedMatrix);
|
|
804
|
+
return originalElementAndAllParentsMultipliedMatrix;
|
|
805
|
+
}
|
|
806
|
+
// FIX 12: parentElementMatrix computed here; in the next iteration this
|
|
807
|
+
// becomes the element's own transform, so we can reuse it without
|
|
808
|
+
// calling getElementCombinedTransform again.
|
|
582
809
|
parentElementMatrix = getElementCombinedTransform(parentElement, iframes);
|
|
583
|
-
if (
|
|
810
|
+
if (!parentElementMatrix.isIdentity)
|
|
584
811
|
originalElementAndAllParentsMultipliedMatrix = parentElementMatrix.multiply(originalElementAndAllParentsMultipliedMatrix);
|
|
585
812
|
perspectiveParentElement = getParentElementIncludingSlots(parentElement, iframes);
|
|
586
813
|
if (perspectiveParentElement) {
|
|
587
|
-
|
|
588
|
-
if (
|
|
589
|
-
|
|
814
|
+
// FIX 5: Skip transformStyle read when matrix is already 2D.
|
|
815
|
+
if (!originalElementAndAllParentsMultipliedMatrix.is2D) {
|
|
816
|
+
const s = getCachedComputedStyle(perspectiveParentElement);
|
|
817
|
+
if (s.transformStyle !== 'preserve-3d') {
|
|
818
|
+
projectTo2D(originalElementAndAllParentsMultipliedMatrix);
|
|
819
|
+
}
|
|
590
820
|
}
|
|
591
821
|
}
|
|
592
|
-
if (parentElement === ancestor) {
|
|
593
|
-
if (parentElement.scrollTop || parentElement.scrollLeft)
|
|
594
|
-
originalElementAndAllParentsMultipliedMatrix = new DOMMatrix().translate(-parentElement.scrollLeft, -parentElement.scrollTop).multiply(originalElementAndAllParentsMultipliedMatrix);
|
|
595
|
-
return originalElementAndAllParentsMultipliedMatrix;
|
|
596
|
-
}
|
|
597
822
|
}
|
|
598
823
|
actualElement = parentElement;
|
|
599
824
|
}
|
|
@@ -620,7 +845,7 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
620
845
|
return q;
|
|
621
846
|
}
|
|
622
847
|
|
|
623
|
-
// NEW
|
|
848
|
+
// NEW - two matrices instead of one
|
|
624
849
|
let layoutMatrix = new DOMMatrix();
|
|
625
850
|
|
|
626
851
|
let actualElement = node;
|
|
@@ -681,7 +906,7 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
681
906
|
|
|
682
907
|
if (parentElement) {
|
|
683
908
|
|
|
684
|
-
// NEW
|
|
909
|
+
// NEW - only affects transform pipeline
|
|
685
910
|
const parentTransform = getElementCombinedTransform(parentElement, iframes);
|
|
686
911
|
transformMatrix = parentTransform.multiply(transformMatrix);
|
|
687
912
|
|
|
@@ -699,7 +924,7 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
|
|
|
699
924
|
|
|
700
925
|
if (parentElement === ancestor) {
|
|
701
926
|
|
|
702
|
-
// NEW
|
|
927
|
+
// NEW - scroll offsets belong to layout
|
|
703
928
|
if (parentElement.scrollTop || parentElement.scrollLeft) {
|
|
704
929
|
layoutMatrix = new DOMMatrix()
|
|
705
930
|
.translate(-parentElement.scrollLeft, -parentElement.scrollTop)
|
|
@@ -757,14 +982,24 @@ export function getElementCombinedTransform(element, iframes) {
|
|
|
757
982
|
return new DOMMatrix;
|
|
758
983
|
//https://www.w3.org/TR/css-transforms-2/#ctm
|
|
759
984
|
let s = getCachedComputedStyle(element);
|
|
760
|
-
//
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
const
|
|
764
|
-
const
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
|
|
985
|
+
// FIX 10: Check hasTransform first — it's the most common non-identity case.
|
|
986
|
+
// Reordering so the most frequent hit is evaluated first.
|
|
987
|
+
const hasTransform = s.transform !== 'none' && !!s.transform;
|
|
988
|
+
const hasTranslate = s.translate !== 'none' && !!s.translate;
|
|
989
|
+
const hasRotate = s.rotate !== 'none' && !!s.rotate;
|
|
990
|
+
const hasScale = s.scale !== 'none' && !!s.scale;
|
|
991
|
+
const hasOffsetPath = !!s.offsetPath && s.offsetPath !== 'none';
|
|
992
|
+
if (!hasTransform && !hasTranslate && !hasRotate && !hasScale && !hasOffsetPath) {
|
|
993
|
+
// FIX 1: Check parent perspective right here in the fast-path, so identity
|
|
994
|
+
// elements on non-3D pages return a new DOMMatrix() immediately
|
|
995
|
+
// without calling getElementPerspectiveTransform at all.
|
|
996
|
+
const parent = getParentElementIncludingSlots(element, iframes);
|
|
997
|
+
if (!parent)
|
|
998
|
+
return new DOMMatrix();
|
|
999
|
+
const ps = getCachedComputedStyle(parent);
|
|
1000
|
+
if (!ps.perspective || ps.perspective === 'none')
|
|
1001
|
+
return new DOMMatrix();
|
|
1002
|
+
// Parent has a perspective — fall through to compute it properly.
|
|
768
1003
|
const pt = getElementPerspectiveTransform(element, iframes);
|
|
769
1004
|
return pt != null ? pt : new DOMMatrix();
|
|
770
1005
|
}
|
|
@@ -773,7 +1008,10 @@ export function getElementCombinedTransform(element, iframes) {
|
|
|
773
1008
|
const originX = parseFloat(origin[0]);
|
|
774
1009
|
const originY = parseFloat(origin[1]);
|
|
775
1010
|
const originZ = origin[2] ? parseFloat(origin[2]) : 0;
|
|
776
|
-
|
|
1011
|
+
// FIX 11: Skip the origin wrap/unwrap entirely when origin is (0,0,0).
|
|
1012
|
+
// Saves two DOMMatrix allocations and two multiply calls per element.
|
|
1013
|
+
const hasNonZeroOrigin = (originX !== 0 || originY !== 0 || originZ !== 0);
|
|
1014
|
+
const mOri = hasNonZeroOrigin ? new DOMMatrix().translateSelf(originX, originY, originZ) : null;
|
|
777
1015
|
if (hasTranslate) {
|
|
778
1016
|
let tr = s.translate;
|
|
779
1017
|
if (tr.includes('%')) {
|
|
@@ -799,7 +1037,10 @@ export function getElementCombinedTransform(element, iframes) {
|
|
|
799
1037
|
if (hasTransform) {
|
|
800
1038
|
m.multiplySelf(new DOMMatrix(s.transform));
|
|
801
1039
|
}
|
|
802
|
-
|
|
1040
|
+
// FIX 11 (continued): Only wrap with origin if non-zero.
|
|
1041
|
+
if (hasNonZeroOrigin) {
|
|
1042
|
+
m = mOri.multiply(m.multiplySelf(mOri.inverse()));
|
|
1043
|
+
}
|
|
803
1044
|
//@ts-ignore
|
|
804
1045
|
const pt = getElementPerspectiveTransform(element, iframes);
|
|
805
1046
|
if (pt != null) {
|
|
@@ -874,8 +1115,25 @@ function computeOffsetTransformMatrix(elem) {
|
|
|
874
1115
|
const transformOrigin = cs.transformOrigin;
|
|
875
1116
|
// Parse offset-distance (px or %)
|
|
876
1117
|
let distance = parseOffsetDistance(offsetDistance);
|
|
877
|
-
// Compute position & tangent on path
|
|
1118
|
+
// Compute position & tangent on path (in containing block coordinates)
|
|
878
1119
|
let { x, y, angle } = computeOffsetPathPoint(elem, offsetPath, distance);
|
|
1120
|
+
// Subtract the element's flow position within its containing block.
|
|
1121
|
+
// The offset-path positions the element absolutely within the containing block,
|
|
1122
|
+
// but the walk already adds offsetLeft/offsetTop (flow position). To avoid
|
|
1123
|
+
// double-counting, make the offset relative to the flow position.
|
|
1124
|
+
const parent = elem.parentElement;
|
|
1125
|
+
if (parent instanceof HTMLElement || parent instanceof (parent.ownerDocument.defaultView ?? window).HTMLElement) {
|
|
1126
|
+
if (elem.offsetParent === parent) {
|
|
1127
|
+
// Containing block = parent = offsetParent
|
|
1128
|
+
x -= elem.offsetLeft;
|
|
1129
|
+
y -= elem.offsetTop;
|
|
1130
|
+
}
|
|
1131
|
+
else if (elem.offsetParent === parent.offsetParent) {
|
|
1132
|
+
// Both share the same offsetParent
|
|
1133
|
+
x -= (elem.offsetLeft - parent.offsetLeft);
|
|
1134
|
+
y -= (elem.offsetTop - parent.offsetTop);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
879
1137
|
// Handle offset-rotate
|
|
880
1138
|
let rotateFinal = 0;
|
|
881
1139
|
if (offsetRotate.startsWith("auto")) {
|
|
@@ -1011,7 +1269,7 @@ function computeCircle(str, t) {
|
|
|
1011
1269
|
let [radiusPart, atPart] = inner.split("at").map(s => s.trim());
|
|
1012
1270
|
let r = parseFloat(radiusPart);
|
|
1013
1271
|
let [cx, cy] = atPart.split(/\s+/).map(parseFloat);
|
|
1014
|
-
let angleRad = t * 2 * Math.PI
|
|
1272
|
+
let angleRad = t * 2 * Math.PI;
|
|
1015
1273
|
let x = cx + Math.cos(angleRad) * r;
|
|
1016
1274
|
let y = cy + Math.sin(angleRad) * r;
|
|
1017
1275
|
let tangentAngleDeg = angleRad * 180 / Math.PI + 90;
|
|
@@ -1026,7 +1284,7 @@ function computeEllipse(str, t) {
|
|
|
1026
1284
|
let ry = radii[1];
|
|
1027
1285
|
let cx = center[0];
|
|
1028
1286
|
let cy = center[1];
|
|
1029
|
-
let angleRad = t * 2 * Math.PI
|
|
1287
|
+
let angleRad = t * 2 * Math.PI;
|
|
1030
1288
|
let x = cx + Math.cos(angleRad) * rx;
|
|
1031
1289
|
let y = cy + Math.sin(angleRad) * ry;
|
|
1032
1290
|
// tangent direction derivative
|
|
@@ -1234,7 +1492,7 @@ function evalCalc(ast, env) {
|
|
|
1234
1492
|
case "number":
|
|
1235
1493
|
return ast.value;
|
|
1236
1494
|
case "dimension":
|
|
1237
|
-
return ast.value; // px only
|
|
1495
|
+
return ast.value; // px only -> already a number
|
|
1238
1496
|
case "percentage":
|
|
1239
1497
|
return env.percentBase * (ast.value / 100);
|
|
1240
1498
|
case "binary": {
|
|
@@ -1325,22 +1583,22 @@ function computeInset(str, element, progress) {
|
|
|
1325
1583
|
const P = 2 * ((x2 - x1) + (y2 - y1));
|
|
1326
1584
|
let d = P * progress;
|
|
1327
1585
|
// Walk the rectangle clockwise, return point
|
|
1328
|
-
// Top edge: (x1
|
|
1586
|
+
// Top edge: (x1 -> x2, y1)
|
|
1329
1587
|
let len = x2 - x1;
|
|
1330
1588
|
if (d <= len)
|
|
1331
1589
|
return { x: x1 + d, y: y1, angle: 0 };
|
|
1332
1590
|
d -= len;
|
|
1333
|
-
// Right edge: (x2, y1
|
|
1591
|
+
// Right edge: (x2, y1 -> y2)
|
|
1334
1592
|
len = y2 - y1;
|
|
1335
1593
|
if (d <= len)
|
|
1336
1594
|
return { x: x2, y: y1 + d, angle: 90 };
|
|
1337
1595
|
d -= len;
|
|
1338
|
-
// Bottom edge: (x2
|
|
1596
|
+
// Bottom edge: (x2 -> x1, y2)
|
|
1339
1597
|
len = x2 - x1;
|
|
1340
1598
|
if (d <= len)
|
|
1341
1599
|
return { x: x2 - d, y: y2, angle: 180 };
|
|
1342
1600
|
d -= len;
|
|
1343
|
-
// Left edge: (x1, y2
|
|
1601
|
+
// Left edge: (x1, y2 -> y1)
|
|
1344
1602
|
return { x: x1, y: y2 - d, angle: 270 };
|
|
1345
1603
|
}
|
|
1346
1604
|
//Code from: https://github.com/floating-ui/floating-ui/blob/master/packages/utils/src/dom.ts
|
|
@@ -1374,6 +1632,13 @@ function flatTreeParent(element) {
|
|
|
1374
1632
|
return element.parentNode.host;
|
|
1375
1633
|
return element.parentNode;
|
|
1376
1634
|
}
|
|
1635
|
+
function isFlatTreeInclusiveAncestor(ancestor, node) {
|
|
1636
|
+
for (let current = node; current; current = flatTreeParent(current)) {
|
|
1637
|
+
if (current === ancestor)
|
|
1638
|
+
return true;
|
|
1639
|
+
}
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1377
1642
|
function ancestorTreeScopes(element) {
|
|
1378
1643
|
const scopes = new Set();
|
|
1379
1644
|
let currentScope = element.getRootNode();
|