@mirage-engine/core 0.3.20 → 0.3.22
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/CHANGELOG.md +20 -0
- package/dist/mirage-engine.js +1416 -1203
- package/dist/mirage-engine.umd.js +18 -18
- package/dist/src/animation/Animator.d.ts +1 -1
- package/dist/src/core/Engine.d.ts +1 -1
- package/dist/src/core/Syncer.d.ts +3 -1
- package/dist/src/dom/Extractor.d.ts +6 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/renderer/Renderer.d.ts +16 -1
- package/dist/src/types/common.d.ts +7 -0
- package/dist/src/wasm/WasmSynchronizer.d.ts +12 -0
- package/package.json +4 -3
- package/src/animation/Animator.ts +96 -3
- package/src/core/Engine.ts +2 -2
- package/src/core/Syncer.ts +33 -5
- package/src/dom/Extractor.ts +104 -49
- package/src/index.ts +1 -0
- package/src/renderer/Renderer.ts +111 -165
- package/src/types/common.ts +9 -0
- package/src/wasm/WasmSynchronizer.ts +44 -0
|
@@ -2,25 +2,28 @@ import { StyleData } from "@mirage-engine/dom-tracker";
|
|
|
2
2
|
import { MeshRegistry } from "../store/MeshRegistry";
|
|
3
3
|
import { Painter } from "@mirage-engine/painter";
|
|
4
4
|
import * as THREE from "three";
|
|
5
|
+
import { WASM_STRIDE, OFFSET_LOCAL_X, OFFSET_LOCAL_Y, OFFSET_PARENT, OFFSET_WORLD_X, OFFSET_WORLD_Y } from "../types";
|
|
5
6
|
|
|
6
7
|
export function animateMeshByData(
|
|
7
8
|
registry: MeshRegistry,
|
|
8
9
|
data: Map<HTMLElement, StyleData>,
|
|
10
|
+
sharedArray?: Float32Array,
|
|
9
11
|
) {
|
|
10
12
|
if (data.size === 0) return;
|
|
11
13
|
|
|
14
|
+
const elementsToUpdateLayout = new Set<HTMLElement>();
|
|
15
|
+
|
|
12
16
|
data.forEach((styleData, element) => {
|
|
13
17
|
const mesh = registry.get(element);
|
|
14
18
|
if (!mesh || !mesh.userData.basePosition) return;
|
|
15
19
|
|
|
20
|
+
// Fast-path styling updates (colors, opacity, etc.)
|
|
16
21
|
Painter.forceUpdateUniforms(mesh.material as THREE.ShaderMaterial, {
|
|
17
22
|
backgroundColor: styleData.backgroundColor,
|
|
18
23
|
backgroundImage: styleData.backgroundImage,
|
|
19
24
|
boxShadow: styleData.boxShadow,
|
|
20
25
|
opacity: styleData.opacity,
|
|
21
|
-
borderRadius:
|
|
22
|
-
styleData.borderRadius ?? mesh.userData.baseStyles?.borderRadius,
|
|
23
|
-
// width and height are no longer updated here, they are updated in syncMeshesByDOM
|
|
26
|
+
borderRadius: styleData.borderRadius ?? mesh.userData.baseStyles?.borderRadius,
|
|
24
27
|
});
|
|
25
28
|
|
|
26
29
|
if (mesh.userData.nativeMesh) {
|
|
@@ -31,6 +34,96 @@ export function animateMeshByData(
|
|
|
31
34
|
opacity: styleData.opacity,
|
|
32
35
|
borderRadius: styleData.borderRadius ?? mesh.userData.baseStyles?.borderRadius,
|
|
33
36
|
});
|
|
37
|
+
|
|
38
|
+
if (styleData.scaleX !== undefined || styleData.scaleY !== undefined) {
|
|
39
|
+
const nativeMesh = mesh.userData.nativeMesh as THREE.Mesh;
|
|
40
|
+
const currentScaleX = nativeMesh.scale.x;
|
|
41
|
+
const currentScaleY = nativeMesh.scale.y;
|
|
42
|
+
const currentScaleZ = nativeMesh.scale.z;
|
|
43
|
+
nativeMesh.scale.set(
|
|
44
|
+
styleData.scaleX !== undefined ? styleData.scaleX * currentScaleX : currentScaleX,
|
|
45
|
+
styleData.scaleY !== undefined ? styleData.scaleY * currentScaleY : currentScaleY,
|
|
46
|
+
styleData.scaleZ !== undefined ? styleData.scaleZ * currentScaleZ : currentScaleZ
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (styleData.layoutChanged || styleData.width !== undefined || styleData.height !== undefined) {
|
|
52
|
+
elementsToUpdateLayout.add(element);
|
|
53
|
+
// Add all descendants that are in the registry
|
|
54
|
+
const descendants = element.querySelectorAll('*');
|
|
55
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
56
|
+
const desc = descendants[i] as HTMLElement;
|
|
57
|
+
if (registry.has(desc)) {
|
|
58
|
+
elementsToUpdateLayout.add(desc);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else if (styleData.x !== undefined || styleData.y !== undefined) {
|
|
62
|
+
// Just transform update (x, y) - doesn't affect child layout natively!
|
|
63
|
+
if (sharedArray && mesh.userData.wasmIndex !== undefined) {
|
|
64
|
+
const offset = mesh.userData.wasmIndex * WASM_STRIDE;
|
|
65
|
+
if (styleData.x !== undefined && mesh.userData.initialLocalX !== undefined) {
|
|
66
|
+
sharedArray[offset + OFFSET_LOCAL_X] = mesh.userData.initialLocalX + styleData.x;
|
|
67
|
+
}
|
|
68
|
+
if (styleData.y !== undefined && mesh.userData.initialLocalY !== undefined) {
|
|
69
|
+
sharedArray[offset + OFFSET_LOCAL_Y] = mesh.userData.initialLocalY + styleData.y;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Now, process all layout updates efficiently!
|
|
76
|
+
elementsToUpdateLayout.forEach((element) => {
|
|
77
|
+
const mesh = registry.get(element);
|
|
78
|
+
if (!mesh) return;
|
|
79
|
+
|
|
80
|
+
const rect = element.getBoundingClientRect();
|
|
81
|
+
|
|
82
|
+
if (mesh.userData.domRect) {
|
|
83
|
+
mesh.userData.domRect.width = rect.width;
|
|
84
|
+
mesh.userData.domRect.height = rect.height;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let pad = (mesh.material as THREE.ShaderMaterial).userData?.shadowPadding || 0;
|
|
88
|
+
mesh.scale.set(rect.width + pad * 2, rect.height + pad * 2, 1);
|
|
89
|
+
|
|
90
|
+
Painter.forceUpdateUniforms(mesh.material as THREE.ShaderMaterial, {
|
|
91
|
+
width: rect.width,
|
|
92
|
+
height: rect.height,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (sharedArray && mesh.userData.wasmIndex !== undefined) {
|
|
96
|
+
const offset = mesh.userData.wasmIndex * WASM_STRIDE;
|
|
97
|
+
const myWorldX = rect.left + (mesh.userData.isFixed ? 0 : window.scrollX);
|
|
98
|
+
const myWorldY = rect.top + (mesh.userData.isFixed ? 0 : window.scrollY);
|
|
99
|
+
|
|
100
|
+
const parentIndex = sharedArray[offset + OFFSET_PARENT];
|
|
101
|
+
let parentWorldX = 0;
|
|
102
|
+
let parentWorldY = 0;
|
|
103
|
+
if (parentIndex !== -1) {
|
|
104
|
+
const parentOffset = parentIndex * WASM_STRIDE;
|
|
105
|
+
parentWorldX = sharedArray[parentOffset + OFFSET_WORLD_X];
|
|
106
|
+
parentWorldY = sharedArray[parentOffset + OFFSET_WORLD_Y];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
sharedArray[offset + OFFSET_LOCAL_X] = myWorldX - parentWorldX;
|
|
110
|
+
sharedArray[offset + OFFSET_LOCAL_Y] = myWorldY - parentWorldY;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (mesh.userData.nativeMesh) {
|
|
114
|
+
const nativeMesh = mesh.userData.nativeMesh as THREE.Mesh;
|
|
115
|
+
let nPad = (nativeMesh.material as THREE.ShaderMaterial).userData?.shadowPadding || 0;
|
|
116
|
+
nativeMesh.scale.set(rect.width + nPad * 2, rect.height + nPad * 2, 1);
|
|
117
|
+
|
|
118
|
+
Painter.forceUpdateUniforms(nativeMesh.material as THREE.ShaderMaterial, {
|
|
119
|
+
width: rect.width,
|
|
120
|
+
height: rect.height,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (mesh.userData.nativeRect) {
|
|
124
|
+
mesh.userData.nativeRect.width = rect.width;
|
|
125
|
+
mesh.userData.nativeRect.height = rect.height;
|
|
126
|
+
}
|
|
34
127
|
}
|
|
35
128
|
});
|
|
36
129
|
}
|
package/src/core/Engine.ts
CHANGED
package/src/core/Syncer.ts
CHANGED
|
@@ -2,15 +2,18 @@ import { CoreConfig } from "../types/config";
|
|
|
2
2
|
import { Renderer } from "../renderer/Renderer";
|
|
3
3
|
import { MeshRegistry } from "../store/MeshRegistry";
|
|
4
4
|
import { extractSceneGraph } from "../dom/Extractor";
|
|
5
|
-
import { Visibility, USER_LAYER, ATTR_TRAVEL } from "../types";
|
|
5
|
+
import { Visibility, USER_LAYER, ATTR_TRAVEL, WASM_STRIDE } from "../types";
|
|
6
6
|
import { animateMeshByData } from "../animation/Animator";
|
|
7
7
|
import { Tracker } from "@mirage-engine/dom-tracker";
|
|
8
|
+
import { WasmSynchronizer } from "../wasm/WasmSynchronizer";
|
|
8
9
|
|
|
9
10
|
export class Syncer {
|
|
10
11
|
private target: HTMLElement;
|
|
11
12
|
private renderer: Renderer;
|
|
12
13
|
private registry: MeshRegistry;
|
|
13
14
|
private isTravelEnabled: boolean = false;
|
|
15
|
+
private wasmSync: WasmSynchronizer;
|
|
16
|
+
private lastWasmNodeCount: number = 0;
|
|
14
17
|
|
|
15
18
|
public tracker: Tracker;
|
|
16
19
|
|
|
@@ -23,6 +26,7 @@ export class Syncer {
|
|
|
23
26
|
this.target = target;
|
|
24
27
|
this.renderer = renderer;
|
|
25
28
|
this.registry = registry;
|
|
29
|
+
this.wasmSync = new WasmSynchronizer();
|
|
26
30
|
|
|
27
31
|
// Use Tracker from dom-tracker
|
|
28
32
|
this.tracker = new Tracker(target, {
|
|
@@ -38,31 +42,55 @@ export class Syncer {
|
|
|
38
42
|
this.renderer.createRenderTarget();
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
const sharedArray = this.wasmSync.sharedArray;
|
|
46
|
+
this.renderer.updateScroll();
|
|
47
|
+
const extractContext = {
|
|
48
|
+
sharedArray: sharedArray || new Float32Array(),
|
|
49
|
+
currentIndex: 0,
|
|
50
|
+
scrollX: (this.renderer as any).getScrollX(),
|
|
51
|
+
scrollY: (this.renderer as any).getScrollY(),
|
|
52
|
+
};
|
|
53
|
+
|
|
41
54
|
const sceneGraph = extractSceneGraph(
|
|
42
55
|
this.target,
|
|
43
56
|
pendingMask,
|
|
44
57
|
USER_LAYER as Visibility,
|
|
45
58
|
1,
|
|
46
59
|
0,
|
|
47
|
-
this.renderer.qualityFactor
|
|
60
|
+
this.renderer.qualityFactor,
|
|
61
|
+
undefined,
|
|
62
|
+
undefined,
|
|
63
|
+
undefined,
|
|
64
|
+
extractContext
|
|
48
65
|
);
|
|
49
66
|
|
|
50
67
|
if (sceneGraph) {
|
|
68
|
+
this.lastWasmNodeCount = extractContext.currentIndex;
|
|
51
69
|
this.renderer.syncScene(sceneGraph, pendingDeletions);
|
|
70
|
+
|
|
71
|
+
if (sharedArray) {
|
|
72
|
+
this.renderer.saveInitialLocals(sharedArray);
|
|
73
|
+
}
|
|
52
74
|
}
|
|
53
75
|
});
|
|
54
76
|
|
|
55
77
|
this.tracker.onStyleChange.add((pendingStyles) => {
|
|
56
|
-
animateMeshByData(this.registry, pendingStyles);
|
|
78
|
+
animateMeshByData(this.registry, pendingStyles, this.wasmSync.sharedArray || undefined);
|
|
57
79
|
});
|
|
58
80
|
|
|
59
81
|
this.tracker.onRender.add(() => {
|
|
60
|
-
this.renderer.
|
|
82
|
+
this.renderer.updateScroll();
|
|
83
|
+
this.wasmSync.updatePhysics(this.lastWasmNodeCount);
|
|
84
|
+
if (this.wasmSync.sharedArray) {
|
|
85
|
+
this.renderer.syncMeshesByWasm(this.wasmSync.sharedArray);
|
|
86
|
+
}
|
|
61
87
|
this.renderer.render();
|
|
62
88
|
});
|
|
63
89
|
}
|
|
64
90
|
|
|
65
|
-
public start() {
|
|
91
|
+
public async start() {
|
|
92
|
+
// 10000개 노드 분량의 공유 메모리를 넉넉하게 선행 할당 (1-Pass 위함)
|
|
93
|
+
await this.wasmSync.initialize(10000 * WASM_STRIDE);
|
|
66
94
|
this.tracker.start();
|
|
67
95
|
}
|
|
68
96
|
|
package/src/dom/Extractor.ts
CHANGED
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
ATTR_SELECT,
|
|
15
15
|
ATTR_TRAVEL,
|
|
16
16
|
ATTR_SHADER,
|
|
17
|
+
WASM_STRIDE,
|
|
18
|
+
OFFSET_PARENT,
|
|
19
|
+
OFFSET_LOCAL_X,
|
|
20
|
+
OFFSET_LOCAL_Y,
|
|
17
21
|
} from "../types";
|
|
18
22
|
|
|
19
23
|
import { BoxStyles, TextStyles, ShaderHooks } from "@mirage-engine/painter";
|
|
@@ -210,7 +214,15 @@ export function extractSceneGraph(
|
|
|
210
214
|
inheritedNativeLayer?: number,
|
|
211
215
|
inheritedNativeStyles?: any,
|
|
212
216
|
inheritedClipElements?: HTMLElement[],
|
|
217
|
+
extractContext?: { sharedArray: Float32Array; currentIndex: number; scrollX?: number; scrollY?: number },
|
|
218
|
+
parentWasmIndex: number = -1,
|
|
219
|
+
parentWorldX: number = 0,
|
|
220
|
+
parentWorldY: number = 0,
|
|
221
|
+
inheritedIsFixed: boolean = false
|
|
213
222
|
): SceneNode | null {
|
|
223
|
+
const scrollX = extractContext?.scrollX ?? window.scrollX;
|
|
224
|
+
const scrollY = extractContext?.scrollY ?? window.scrollY;
|
|
225
|
+
|
|
214
226
|
// Check text node
|
|
215
227
|
if (sourceNode.nodeType === Node.TEXT_NODE) {
|
|
216
228
|
const textNode = sourceNode as Text;
|
|
@@ -228,20 +240,34 @@ export function extractSceneGraph(
|
|
|
228
240
|
const computed = parent ? window.getComputedStyle(parent) : null;
|
|
229
241
|
if (!computed) return null;
|
|
230
242
|
|
|
243
|
+
const myIsFixed = inheritedIsFixed || computed.position === "fixed";
|
|
244
|
+
|
|
231
245
|
// Calculate overall bounding box of the lines
|
|
232
246
|
const minX = Math.min(...textLines.map((l) => l.rect.left));
|
|
233
247
|
const minY = Math.min(...textLines.map((l) => l.rect.top));
|
|
234
248
|
const maxX = Math.max(...textLines.map((l) => l.rect.left + l.rect.width));
|
|
235
249
|
const maxY = Math.max(...textLines.map((l) => l.rect.top + l.rect.height));
|
|
236
250
|
|
|
251
|
+
const myWorldX = minX + (myIsFixed ? 0 : scrollX);
|
|
252
|
+
const myWorldY = minY + (myIsFixed ? 0 : scrollY);
|
|
253
|
+
|
|
254
|
+
let myWasmIndex = -1;
|
|
255
|
+
if (extractContext && extractContext.sharedArray) {
|
|
256
|
+
myWasmIndex = extractContext.currentIndex++;
|
|
257
|
+
const offset = myWasmIndex * WASM_STRIDE;
|
|
258
|
+
extractContext.sharedArray[offset + OFFSET_PARENT] = parentWasmIndex;
|
|
259
|
+
extractContext.sharedArray[offset + OFFSET_LOCAL_X] = myWorldX - parentWorldX;
|
|
260
|
+
extractContext.sharedArray[offset + OFFSET_LOCAL_Y] = myWorldY - parentWorldY;
|
|
261
|
+
}
|
|
262
|
+
|
|
237
263
|
// Create SceneNode for the text node
|
|
238
264
|
return {
|
|
239
265
|
id: Math.random().toString(36).substring(2, 9),
|
|
240
266
|
type: "TEXT",
|
|
241
267
|
element: textNode as unknown as HTMLElement,
|
|
242
268
|
rect: {
|
|
243
|
-
x: minX +
|
|
244
|
-
y: minY +
|
|
269
|
+
x: minX + (myIsFixed ? 0 : scrollX),
|
|
270
|
+
y: minY + (myIsFixed ? 0 : scrollY),
|
|
245
271
|
width: maxX - minX,
|
|
246
272
|
height: maxY - minY,
|
|
247
273
|
},
|
|
@@ -264,8 +290,8 @@ export function extractSceneGraph(
|
|
|
264
290
|
textLines: textLines.map((l) => ({
|
|
265
291
|
text: l.text.trim(),
|
|
266
292
|
rect: {
|
|
267
|
-
x: l.rect.left +
|
|
268
|
-
y: l.rect.top +
|
|
293
|
+
x: l.rect.left + (myIsFixed ? 0 : scrollX),
|
|
294
|
+
y: l.rect.top + (myIsFixed ? 0 : scrollY),
|
|
269
295
|
width: l.rect.width,
|
|
270
296
|
height: l.rect.height,
|
|
271
297
|
},
|
|
@@ -275,7 +301,7 @@ export function extractSceneGraph(
|
|
|
275
301
|
visibility: inheritedFlow,
|
|
276
302
|
isTraveler: false,
|
|
277
303
|
captureLayer,
|
|
278
|
-
isFixed:
|
|
304
|
+
isFixed: myIsFixed,
|
|
279
305
|
nativeLayer: inheritedNativeLayer,
|
|
280
306
|
nativeStyles: inheritedNativeStyles
|
|
281
307
|
? {
|
|
@@ -299,13 +325,14 @@ export function extractSceneGraph(
|
|
|
299
325
|
: undefined,
|
|
300
326
|
nativeRect: inheritedNativeStyles
|
|
301
327
|
? {
|
|
302
|
-
x: minX +
|
|
303
|
-
y: minY +
|
|
328
|
+
x: minX + (myIsFixed ? 0 : scrollX),
|
|
329
|
+
y: minY + (myIsFixed ? 0 : scrollY),
|
|
304
330
|
width: maxX - minX,
|
|
305
331
|
height: maxY - minY,
|
|
306
332
|
}
|
|
307
333
|
: undefined,
|
|
308
334
|
clipElements: inheritedClipElements,
|
|
335
|
+
wasmIndex: myWasmIndex !== -1 ? myWasmIndex : undefined,
|
|
309
336
|
children: [],
|
|
310
337
|
};
|
|
311
338
|
}
|
|
@@ -498,6 +525,20 @@ export function extractSceneGraph(
|
|
|
498
525
|
return null;
|
|
499
526
|
}
|
|
500
527
|
|
|
528
|
+
const myIsFixed = inheritedIsFixed || computed.position === "fixed";
|
|
529
|
+
|
|
530
|
+
const myWorldX = rect.left + (myIsFixed ? 0 : scrollX);
|
|
531
|
+
const myWorldY = rect.top + (myIsFixed ? 0 : scrollY);
|
|
532
|
+
|
|
533
|
+
let myWasmIndex = -1;
|
|
534
|
+
if (extractContext && extractContext.sharedArray) {
|
|
535
|
+
myWasmIndex = extractContext.currentIndex++;
|
|
536
|
+
const offset = myWasmIndex * WASM_STRIDE;
|
|
537
|
+
extractContext.sharedArray[offset + OFFSET_PARENT] = parentWasmIndex;
|
|
538
|
+
extractContext.sharedArray[offset + OFFSET_LOCAL_X] = myWorldX - parentWorldX;
|
|
539
|
+
extractContext.sharedArray[offset + OFFSET_LOCAL_Y] = myWorldY - parentWorldY;
|
|
540
|
+
}
|
|
541
|
+
|
|
501
542
|
// [TODO] dataset 방식으로 변경
|
|
502
543
|
let id = element.getAttribute("data-mid");
|
|
503
544
|
if (!id) {
|
|
@@ -511,64 +552,71 @@ export function extractSceneGraph(
|
|
|
511
552
|
// console.log(`${element.id}: ${computed.background}`);
|
|
512
553
|
// console.log(computed.backgroundImage);
|
|
513
554
|
let imageSrc: string | undefined;
|
|
555
|
+
let nativeImageSrc: string | undefined;
|
|
514
556
|
if (element.tagName === "IMG") {
|
|
515
557
|
imageSrc = (element as HTMLImageElement).src;
|
|
516
558
|
} else if (element.tagName.toLowerCase() === "svg") {
|
|
517
|
-
const clone = element.cloneNode(true) as SVGSVGElement;
|
|
518
|
-
|
|
519
559
|
const overrideColor = nativeParsedStyles?.color;
|
|
520
560
|
const overrideFill = nativeParsedStyles?.fill;
|
|
521
561
|
const overrideStroke = nativeParsedStyles?.stroke;
|
|
522
562
|
const overrideOpacity = nativeParsedStyles?.opacity;
|
|
523
563
|
|
|
524
|
-
const
|
|
525
|
-
const
|
|
526
|
-
|
|
564
|
+
const getSvgImageSrc = (useOverrides: boolean) => {
|
|
565
|
+
const clone = element.cloneNode(true) as SVGSVGElement;
|
|
566
|
+
|
|
567
|
+
const inlineSVGStyles = (orig: Element, cloned: Element) => {
|
|
568
|
+
const computed = window.getComputedStyle(orig);
|
|
569
|
+
const clonedHtml = cloned as HTMLElement;
|
|
527
570
|
|
|
528
|
-
|
|
529
|
-
|
|
571
|
+
const isCurrentColorFill = computed.fill === computed.color;
|
|
572
|
+
const isCurrentColorStroke = computed.stroke === computed.color;
|
|
530
573
|
|
|
531
|
-
|
|
532
|
-
|
|
574
|
+
const fill = (useOverrides ? (overrideFill || (isCurrentColorFill ? overrideColor : undefined)) : undefined) || computed.fill;
|
|
575
|
+
if (fill && fill !== "none") clonedHtml.style.fill = fill;
|
|
533
576
|
|
|
534
|
-
|
|
535
|
-
|
|
577
|
+
const stroke = (useOverrides ? (overrideStroke || (isCurrentColorStroke ? overrideColor : undefined)) : undefined) || computed.stroke;
|
|
578
|
+
if (stroke && stroke !== "none") clonedHtml.style.stroke = stroke;
|
|
536
579
|
|
|
537
|
-
|
|
538
|
-
|
|
580
|
+
if (computed.strokeWidth && computed.strokeWidth !== "0px")
|
|
581
|
+
clonedHtml.style.strokeWidth = computed.strokeWidth;
|
|
539
582
|
|
|
540
|
-
|
|
541
|
-
|
|
583
|
+
const color = (useOverrides ? overrideColor : undefined) || computed.color;
|
|
584
|
+
if (color) clonedHtml.style.color = color;
|
|
542
585
|
|
|
543
|
-
|
|
544
|
-
|
|
586
|
+
const opacity = (useOverrides ? overrideOpacity : undefined) || computed.opacity;
|
|
587
|
+
if (opacity && opacity !== "1") clonedHtml.style.opacity = opacity;
|
|
545
588
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
589
|
+
for (let i = 0; i < orig.children.length; i++) {
|
|
590
|
+
inlineSVGStyles(orig.children[i], cloned.children[i]);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
550
593
|
|
|
551
|
-
|
|
594
|
+
inlineSVGStyles(element, clone);
|
|
552
595
|
|
|
553
|
-
|
|
554
|
-
|
|
596
|
+
const svgRect = element.getBoundingClientRect();
|
|
597
|
+
const scale = window.devicePixelRatio * qualityFactor;
|
|
555
598
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
599
|
+
if (!clone.hasAttribute("viewBox")) {
|
|
600
|
+
clone.setAttribute("viewBox", `0 0 ${svgRect.width} ${svgRect.height}`);
|
|
601
|
+
}
|
|
559
602
|
|
|
560
|
-
|
|
561
|
-
|
|
603
|
+
clone.setAttribute("width", (svgRect.width * scale).toString());
|
|
604
|
+
clone.setAttribute("height", (svgRect.height * scale).toString());
|
|
562
605
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
606
|
+
let svgString = new XMLSerializer().serializeToString(clone);
|
|
607
|
+
if (!svgString.includes("xmlns=")) {
|
|
608
|
+
svgString = svgString.replace(
|
|
609
|
+
"<svg",
|
|
610
|
+
'<svg xmlns="http://www.w3.org/2000/svg"',
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
return `data:image/svg+xml;utf8,${encodeURIComponent(svgString)}`;
|
|
614
|
+
};
|
|
570
615
|
|
|
571
|
-
imageSrc =
|
|
616
|
+
imageSrc = getSvgImageSrc(false);
|
|
617
|
+
if (nativeLayer !== undefined && (overrideColor || overrideFill || overrideStroke || overrideOpacity)) {
|
|
618
|
+
nativeImageSrc = getSvgImageSrc(true);
|
|
619
|
+
}
|
|
572
620
|
} else if (computed.backgroundImage && computed.backgroundImage !== "none") {
|
|
573
621
|
const match = computed.backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);
|
|
574
622
|
if (match) {
|
|
@@ -620,6 +668,11 @@ export function extractSceneGraph(
|
|
|
620
668
|
? nativeParsedStyles
|
|
621
669
|
: undefined,
|
|
622
670
|
nextClipElements,
|
|
671
|
+
extractContext,
|
|
672
|
+
myWasmIndex,
|
|
673
|
+
myWorldX,
|
|
674
|
+
myWorldY,
|
|
675
|
+
myIsFixed
|
|
623
676
|
);
|
|
624
677
|
if (childNode) {
|
|
625
678
|
children.push(childNode);
|
|
@@ -632,8 +685,8 @@ export function extractSceneGraph(
|
|
|
632
685
|
type: "BOX",
|
|
633
686
|
element,
|
|
634
687
|
rect: {
|
|
635
|
-
x: rect.left +
|
|
636
|
-
y: rect.top +
|
|
688
|
+
x: rect.left + scrollX,
|
|
689
|
+
y: rect.top + scrollY,
|
|
637
690
|
width: rect.width,
|
|
638
691
|
height: rect.height,
|
|
639
692
|
},
|
|
@@ -668,6 +721,7 @@ export function extractSceneGraph(
|
|
|
668
721
|
nativeParsedStyles.boxShadow ?? baseStyles.boxShadow,
|
|
669
722
|
isTraveler: baseStyles.isTraveler,
|
|
670
723
|
transform: nativeParsedStyles.transform,
|
|
724
|
+
imageSrc: nativeImageSrc ?? imageSrc,
|
|
671
725
|
}
|
|
672
726
|
: undefined,
|
|
673
727
|
nativeRect:
|
|
@@ -676,11 +730,11 @@ export function extractSceneGraph(
|
|
|
676
730
|
x:
|
|
677
731
|
nativeParsedStyles.x !== undefined
|
|
678
732
|
? parseFloat(nativeParsedStyles.x)
|
|
679
|
-
: rect.left +
|
|
733
|
+
: rect.left + scrollX,
|
|
680
734
|
y:
|
|
681
735
|
nativeParsedStyles.y !== undefined
|
|
682
736
|
? parseFloat(nativeParsedStyles.y)
|
|
683
|
-
: rect.top +
|
|
737
|
+
: rect.top + scrollY,
|
|
684
738
|
width:
|
|
685
739
|
nativeParsedStyles.width !== undefined
|
|
686
740
|
? parseFloat(nativeParsedStyles.width)
|
|
@@ -691,8 +745,9 @@ export function extractSceneGraph(
|
|
|
691
745
|
: rect.height,
|
|
692
746
|
}
|
|
693
747
|
: undefined,
|
|
694
|
-
isFixed:
|
|
748
|
+
isFixed: myIsFixed,
|
|
695
749
|
clipElements: inheritedClipElements,
|
|
750
|
+
wasmIndex: myWasmIndex !== -1 ? myWasmIndex : undefined,
|
|
696
751
|
children,
|
|
697
752
|
shaderHooks,
|
|
698
753
|
};
|
package/src/index.ts
CHANGED