stickyflow 0.3.0 → 0.5.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/CHANGELOG.md +33 -0
- package/README.md +51 -5
- package/dist/binding/index.cjs +34 -0
- package/dist/binding/index.cjs.map +1 -0
- package/dist/binding/index.d.cts +11 -0
- package/dist/binding/index.d.ts +11 -0
- package/dist/binding/index.js +5 -0
- package/dist/binding/index.js.map +1 -0
- package/dist/{chunk-XEN5QIIJ.js → chunk-7VW2XKVB.js} +3 -3
- package/dist/{chunk-XEN5QIIJ.js.map → chunk-7VW2XKVB.js.map} +1 -1
- package/dist/chunk-BODZN3ZI.js +1182 -0
- package/dist/chunk-BODZN3ZI.js.map +1 -0
- package/dist/{chunk-CSXQD3ON.js → chunk-G7NRK5AG.js} +1128 -1081
- package/dist/chunk-G7NRK5AG.js.map +1 -0
- package/dist/{chunk-BYMIYXP5.js → chunk-IEHE6WVN.js} +197 -19
- package/dist/chunk-IEHE6WVN.js.map +1 -0
- package/dist/{chunk-HFOGKSNU.cjs → chunk-L3VJXZFD.cjs} +15 -15
- package/dist/{chunk-HFOGKSNU.cjs.map → chunk-L3VJXZFD.cjs.map} +1 -1
- package/dist/{chunk-65IVT4GK.js → chunk-LTGF5OHP.js} +1008 -631
- package/dist/chunk-LTGF5OHP.js.map +1 -0
- package/dist/chunk-TWDLOXRM.cjs +1189 -0
- package/dist/chunk-TWDLOXRM.cjs.map +1 -0
- package/dist/{chunk-UXDWH2JC.cjs → chunk-VK3T6O5Z.cjs} +1165 -1118
- package/dist/chunk-VK3T6O5Z.cjs.map +1 -0
- package/dist/{chunk-CXL254BT.cjs → chunk-XY2GZUHC.cjs} +204 -18
- package/dist/chunk-XY2GZUHC.cjs.map +1 -0
- package/dist/{chunk-DDCTNLLD.cjs → chunk-ZMLQIMJK.cjs} +1504 -1128
- package/dist/chunk-ZMLQIMJK.cjs.map +1 -0
- package/dist/index.cjs +53 -1013
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -14
- package/dist/index.d.ts +22 -14
- package/dist/index.js +6 -993
- package/dist/index.js.map +1 -1
- package/dist/interaction/index.cjs +474 -305
- package/dist/interaction/index.cjs.map +1 -1
- package/dist/interaction/index.d.cts +11 -3
- package/dist/interaction/index.d.ts +11 -3
- package/dist/interaction/index.js +255 -87
- package/dist/interaction/index.js.map +1 -1
- package/dist/{render-C5X74hds.d.cts → render-CgX_y15a.d.cts} +193 -116
- package/dist/{render-C5X74hds.d.ts → render-CgX_y15a.d.ts} +193 -116
- package/dist/runtime-DnUxca3Y.d.ts +10 -0
- package/dist/runtime-reWgr7MP.d.cts +10 -0
- package/dist/{runtimeTypes-D8hPZ62T.d.ts → runtimeTypes-CEBGueYM.d.ts} +10 -5
- package/dist/{runtimeTypes-yTSAvtCn.d.cts → runtimeTypes-D60w6nyF.d.cts} +10 -5
- package/dist/stickyflow-diagram.global.js +35 -35
- package/dist/stickyflow-diagram.global.js.map +1 -1
- package/dist/{types-BDKDf4zr.d.cts → types-DYLC_lsk.d.ts} +3 -2
- package/dist/{types-CdgGdtoD.d.ts → types-DvhMpqrL.d.cts} +3 -2
- package/dist/viewer/index.cjs +9 -9
- package/dist/viewer/index.d.cts +4 -4
- package/dist/viewer/index.d.ts +4 -4
- package/dist/viewer/index.js +4 -4
- package/dist/web-component/index.cjs +6 -6
- package/dist/web-component/index.d.cts +2 -2
- package/dist/web-component/index.d.ts +2 -2
- package/dist/web-component/index.js +4 -4
- package/package.json +6 -1
- package/dist/chunk-65IVT4GK.js.map +0 -1
- package/dist/chunk-BYMIYXP5.js.map +0 -1
- package/dist/chunk-CSXQD3ON.js.map +0 -1
- package/dist/chunk-CXL254BT.cjs.map +0 -1
- package/dist/chunk-DDCTNLLD.cjs.map +0 -1
- package/dist/chunk-UXDWH2JC.cjs.map +0 -1
|
@@ -1,248 +1,618 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkZMLQIMJK_cjs = require('./chunk-ZMLQIMJK.cjs');
|
|
4
|
+
var chunkL3VJXZFD_cjs = require('./chunk-L3VJXZFD.cjs');
|
|
5
|
+
var chunkXY2GZUHC_cjs = require('./chunk-XY2GZUHC.cjs');
|
|
5
6
|
|
|
6
|
-
// src/runtime/viewer/
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
// src/runtime/viewer/components/rollingNumberDom.ts
|
|
8
|
+
var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
|
9
|
+
var setStyles = (element, styles) => {
|
|
10
|
+
Object.assign(element.style, styles);
|
|
11
|
+
};
|
|
12
|
+
function createDigit(document, character, theme) {
|
|
13
|
+
const digit = document.createElementNS(HTML_NAMESPACE, "span");
|
|
14
|
+
digit.setAttribute("data-sf-rolling-current", "true");
|
|
15
|
+
digit.textContent = character;
|
|
16
|
+
setStyles(digit, {
|
|
17
|
+
position: "absolute",
|
|
18
|
+
inset: "0",
|
|
19
|
+
display: "grid",
|
|
20
|
+
placeItems: "center",
|
|
21
|
+
color: theme.color,
|
|
22
|
+
fontWeight: theme.fontWeight,
|
|
23
|
+
lineHeight: "1"
|
|
24
|
+
});
|
|
25
|
+
return digit;
|
|
26
|
+
}
|
|
27
|
+
function createDigitCell(document, character, theme) {
|
|
28
|
+
const cell = document.createElementNS(HTML_NAMESPACE, "span");
|
|
29
|
+
cell.setAttribute("data-sf-rolling-digit", "true");
|
|
30
|
+
if (theme.variant === "plain") {
|
|
31
|
+
setStyles(cell, {
|
|
32
|
+
position: "relative",
|
|
33
|
+
display: "inline-block",
|
|
34
|
+
width: "0.62em",
|
|
35
|
+
height: "1.1em",
|
|
36
|
+
overflow: "hidden"
|
|
37
|
+
});
|
|
38
|
+
cell.appendChild(createDigit(document, character, theme));
|
|
39
|
+
return cell;
|
|
18
40
|
}
|
|
41
|
+
setStyles(cell, {
|
|
42
|
+
position: "relative",
|
|
43
|
+
display: "inline-block",
|
|
44
|
+
width: "0.72em",
|
|
45
|
+
height: "1.2em",
|
|
46
|
+
overflow: "hidden",
|
|
47
|
+
border: `1px solid ${theme.divider}`,
|
|
48
|
+
borderRadius: "0.09em",
|
|
49
|
+
background: theme.surface,
|
|
50
|
+
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.7), inset 0 -0.16em 0.38em rgba(0,0,0,0.12)"
|
|
51
|
+
});
|
|
52
|
+
cell.appendChild(createDigit(document, character, theme));
|
|
53
|
+
const divider = document.createElementNS(HTML_NAMESPACE, "span");
|
|
54
|
+
setStyles(divider, {
|
|
55
|
+
position: "absolute",
|
|
56
|
+
zIndex: "2",
|
|
57
|
+
left: "0",
|
|
58
|
+
right: "0",
|
|
59
|
+
top: "50%",
|
|
60
|
+
height: "1px",
|
|
61
|
+
background: theme.divider,
|
|
62
|
+
pointerEvents: "none"
|
|
63
|
+
});
|
|
64
|
+
cell.appendChild(divider);
|
|
65
|
+
return cell;
|
|
19
66
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const added = [];
|
|
24
|
-
const removed = [];
|
|
25
|
-
const changed = [];
|
|
26
|
-
for (const id of touchedOwnerIds) {
|
|
27
|
-
const wasPresent = oldOwnerIds.has(id);
|
|
28
|
-
const isPresent = newOwnerIds.has(id);
|
|
29
|
-
if (isPresent && !wasPresent) {
|
|
30
|
-
added.push(id);
|
|
31
|
-
} else if (wasPresent && !isPresent) {
|
|
32
|
-
removed.push(id);
|
|
33
|
-
} else if (wasPresent && isPresent) {
|
|
34
|
-
changed.push(id);
|
|
35
|
-
}
|
|
67
|
+
function animateDigit(element, keyframes, duration) {
|
|
68
|
+
if (duration === 0 || typeof element.animate !== "function") {
|
|
69
|
+
return null;
|
|
36
70
|
}
|
|
37
|
-
return
|
|
71
|
+
return element.animate(keyframes, {
|
|
72
|
+
duration,
|
|
73
|
+
easing: "cubic-bezier(0.22, 1, 0.36, 1)",
|
|
74
|
+
fill: "forwards"
|
|
75
|
+
});
|
|
38
76
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
function fadeDigit(cell, character, theme, duration) {
|
|
78
|
+
const previous = cell.querySelector("[data-sf-rolling-current]");
|
|
79
|
+
previous?.removeAttribute("data-sf-rolling-current");
|
|
80
|
+
const next = createDigit(cell.ownerDocument, character, theme);
|
|
81
|
+
next.style.opacity = "0";
|
|
82
|
+
cell.insertBefore(next, cell.lastElementChild ?? null);
|
|
83
|
+
const hidden = { opacity: 0, filter: "blur(0.025em)", transform: "scale(0.985)" };
|
|
84
|
+
const shown = { opacity: 1, filter: "blur(0)", transform: "scale(1)" };
|
|
85
|
+
const incoming = animateDigit(next, [hidden, shown], duration);
|
|
86
|
+
const outgoing = previous ? animateDigit(previous, [shown, hidden], duration) : null;
|
|
87
|
+
const finish = () => {
|
|
88
|
+
previous?.remove();
|
|
89
|
+
next.style.opacity = "1";
|
|
90
|
+
};
|
|
91
|
+
if (incoming) {
|
|
92
|
+
incoming.finished.then(finish, finish);
|
|
93
|
+
} else {
|
|
94
|
+
outgoing?.cancel();
|
|
95
|
+
finish();
|
|
51
96
|
}
|
|
52
|
-
currentDefinitions?.remove();
|
|
53
|
-
return currentDefinitions;
|
|
54
97
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for (const attribute of Array.from(current.attributes)) {
|
|
60
|
-
if (!next.hasAttribute(attribute.name)) {
|
|
61
|
-
current.removeAttribute(attribute.name);
|
|
62
|
-
changed = true;
|
|
63
|
-
}
|
|
98
|
+
function replaceDigit(cell, character, theme, duration) {
|
|
99
|
+
if (theme.motion === "fade") {
|
|
100
|
+
fadeDigit(cell, character, theme, duration);
|
|
101
|
+
return;
|
|
64
102
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
103
|
+
const previous = cell.querySelector("[data-sf-rolling-current]");
|
|
104
|
+
previous?.removeAttribute("data-sf-rolling-current");
|
|
105
|
+
const next = createDigit(cell.ownerDocument, character, theme);
|
|
106
|
+
next.style.transform = "translateY(100%)";
|
|
107
|
+
next.style.opacity = "0.25";
|
|
108
|
+
cell.insertBefore(next, cell.lastElementChild);
|
|
109
|
+
const incoming = animateDigit(
|
|
110
|
+
next,
|
|
111
|
+
[
|
|
112
|
+
{ transform: "translateY(100%)", opacity: 0.25 },
|
|
113
|
+
{ transform: "translateY(0)", opacity: 1 }
|
|
114
|
+
],
|
|
115
|
+
duration
|
|
116
|
+
);
|
|
117
|
+
const outgoing = previous ? animateDigit(
|
|
118
|
+
previous,
|
|
119
|
+
[
|
|
120
|
+
{ transform: "translateY(0)", opacity: 1 },
|
|
121
|
+
{ transform: "translateY(-100%)", opacity: 0.25 }
|
|
122
|
+
],
|
|
123
|
+
duration
|
|
124
|
+
) : null;
|
|
125
|
+
const finish = () => {
|
|
126
|
+
previous?.remove();
|
|
127
|
+
next.style.transform = "translateY(0)";
|
|
128
|
+
next.style.opacity = "1";
|
|
129
|
+
};
|
|
130
|
+
if (incoming) {
|
|
131
|
+
incoming.finished.then(finish, finish);
|
|
132
|
+
} else {
|
|
133
|
+
outgoing?.cancel();
|
|
134
|
+
finish();
|
|
70
135
|
}
|
|
71
|
-
return changed;
|
|
72
136
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return
|
|
137
|
+
function updateRollingDigits(digits, previousValue, nextValue, theme, duration) {
|
|
138
|
+
if (previousValue.length !== nextValue.length) {
|
|
139
|
+
digits.replaceChildren(...[...nextValue].map((character) => createDigitCell(digits.ownerDocument, character, theme)));
|
|
140
|
+
digits.setAttribute("aria-label", nextValue);
|
|
141
|
+
return;
|
|
78
142
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
if (x.nodeType === Node.TEXT_NODE) {
|
|
86
|
-
if (x.textContent !== y.textContent) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (x.nodeType !== Node.ELEMENT_NODE) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const xElement = x;
|
|
95
|
-
const yElement = y;
|
|
96
|
-
if (xElement.tagName !== yElement.tagName) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
if (xElement.attributes.length !== yElement.attributes.length) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
for (const attribute of Array.from(xElement.attributes)) {
|
|
103
|
-
if (yElement.getAttribute(attribute.name) !== attribute.value) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (!childrenEqual(xElement, yElement)) {
|
|
108
|
-
return false;
|
|
143
|
+
const cells = [...digits.querySelectorAll("[data-sf-rolling-digit]")];
|
|
144
|
+
[...nextValue].forEach((character, index) => {
|
|
145
|
+
if (previousValue[index] !== character) {
|
|
146
|
+
replaceDigit(cells[index], character, theme, duration);
|
|
109
147
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
148
|
+
});
|
|
149
|
+
digits.setAttribute("aria-label", nextValue);
|
|
112
150
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
151
|
+
|
|
152
|
+
// src/runtime/viewer/components/documentComponents.ts
|
|
153
|
+
function findRollingNumber(svg, componentId) {
|
|
154
|
+
return [...svg.querySelectorAll('foreignObject[data-sf-widget="rollingNumber"]')].find(
|
|
155
|
+
(surface) => surface.getAttribute("data-sf-id") === componentId
|
|
156
|
+
);
|
|
120
157
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
var FADE_INTERVAL = 140;
|
|
159
|
+
function componentDigits(surface) {
|
|
160
|
+
return surface.querySelector("[data-sf-rolling-digits]") ?? void 0;
|
|
161
|
+
}
|
|
162
|
+
function componentStyle(surface) {
|
|
163
|
+
const encoded = surface.getAttribute("data-sf-widget-style");
|
|
164
|
+
if (!encoded) {
|
|
165
|
+
return chunkXY2GZUHC_cjs.DEFAULT_ROLLING_NUMBER_STYLE;
|
|
128
166
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
167
|
+
try {
|
|
168
|
+
return { ...chunkXY2GZUHC_cjs.DEFAULT_ROLLING_NUMBER_STYLE, ...JSON.parse(encoded) };
|
|
169
|
+
} catch {
|
|
170
|
+
return chunkXY2GZUHC_cjs.DEFAULT_ROLLING_NUMBER_STYLE;
|
|
132
171
|
}
|
|
133
|
-
return attributesChanged || contentChanged;
|
|
134
172
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return element.getAttribute("data-sf-id") ?? element.id;
|
|
139
|
-
}
|
|
140
|
-
function currentElementsById(svg) {
|
|
141
|
-
const elements = /* @__PURE__ */ new Map();
|
|
142
|
-
for (const element of svg.querySelectorAll(":scope > [id]")) {
|
|
143
|
-
elements.set(element.id, element);
|
|
144
|
-
}
|
|
145
|
-
return elements;
|
|
146
|
-
}
|
|
147
|
-
function reusableElement(current, next, markTouched) {
|
|
148
|
-
if (current && current.tagName === next.tagName) {
|
|
149
|
-
if (patchSceneElement(current, next)) {
|
|
150
|
-
markTouched(ownerIdOf(next));
|
|
151
|
-
}
|
|
152
|
-
return current;
|
|
173
|
+
function positiveInteger(value) {
|
|
174
|
+
if (!value) {
|
|
175
|
+
return void 0;
|
|
153
176
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return next;
|
|
177
|
+
const number2 = Number(value);
|
|
178
|
+
return Number.isInteger(number2) && number2 > 0 ? number2 : void 0;
|
|
157
179
|
}
|
|
158
|
-
function
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
|
|
180
|
+
function durationFor(surface) {
|
|
181
|
+
const duration = Number(surface.getAttribute("data-sf-widget-duration"));
|
|
182
|
+
if (!Number.isFinite(duration) || duration < 0) {
|
|
183
|
+
return 420;
|
|
162
184
|
}
|
|
185
|
+
const reduceMotion = surface.ownerDocument.defaultView?.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
186
|
+
return reduceMotion ? 0 : duration;
|
|
163
187
|
}
|
|
164
|
-
function
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const oldOwnerIds = /* @__PURE__ */ new Set();
|
|
169
|
-
for (const element of currentById.values()) {
|
|
170
|
-
oldOwnerIds.add(ownerIdOf(element));
|
|
188
|
+
function setRollingNumber(surface, value, animate) {
|
|
189
|
+
const digits = componentDigits(surface);
|
|
190
|
+
if (!digits) {
|
|
191
|
+
return false;
|
|
171
192
|
}
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
};
|
|
177
|
-
let previousSibling = definitions;
|
|
178
|
-
for (const nextElement of next.querySelectorAll(":scope > [id]")) {
|
|
179
|
-
retainedIds.add(nextElement.id);
|
|
180
|
-
newOwnerIds.add(ownerIdOf(nextElement));
|
|
181
|
-
const liveElement = reusableElement(currentById.get(nextElement.id), nextElement, markTouched);
|
|
182
|
-
placeAfter(svg, liveElement, previousSibling);
|
|
183
|
-
previousSibling = liveElement;
|
|
193
|
+
const previousValue = surface.getAttribute("data-sf-widget-value") ?? "";
|
|
194
|
+
const nextValue = chunkXY2GZUHC_cjs.formatRollingNumber(value, positiveInteger(surface.getAttribute("data-sf-widget-digits")));
|
|
195
|
+
if (previousValue === nextValue) {
|
|
196
|
+
return true;
|
|
184
197
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
198
|
+
updateRollingDigits(digits, previousValue, nextValue, componentStyle(surface), animate ? durationFor(surface) : 0);
|
|
199
|
+
surface.setAttribute("data-sf-widget-value", nextValue);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
function mountDocumentComponents(svg) {
|
|
203
|
+
const valueOverrides = /* @__PURE__ */ new Map();
|
|
204
|
+
const lastApplied = /* @__PURE__ */ new Map();
|
|
205
|
+
const pending = /* @__PURE__ */ new Map();
|
|
206
|
+
return {
|
|
207
|
+
setValue(componentId, value) {
|
|
208
|
+
const surface = findRollingNumber(svg, componentId);
|
|
209
|
+
if (!surface) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
valueOverrides.set(componentId, value);
|
|
213
|
+
if (componentStyle(surface).motion !== "fade") {
|
|
214
|
+
return setRollingNumber(surface, value, true);
|
|
215
|
+
}
|
|
216
|
+
const now = Date.now();
|
|
217
|
+
const wait = (lastApplied.get(componentId) ?? 0) + FADE_INTERVAL - now;
|
|
218
|
+
if (wait <= 0) {
|
|
219
|
+
lastApplied.set(componentId, now);
|
|
220
|
+
return setRollingNumber(surface, value, true);
|
|
221
|
+
}
|
|
222
|
+
if (!pending.has(componentId)) {
|
|
223
|
+
pending.set(
|
|
224
|
+
componentId,
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
pending.delete(componentId);
|
|
227
|
+
lastApplied.set(componentId, Date.now());
|
|
228
|
+
const current = findRollingNumber(svg, componentId);
|
|
229
|
+
const latest = valueOverrides.get(componentId);
|
|
230
|
+
if (current && latest !== void 0) {
|
|
231
|
+
setRollingNumber(current, latest, true);
|
|
232
|
+
}
|
|
233
|
+
}, wait)
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
},
|
|
238
|
+
refresh() {
|
|
239
|
+
for (const [componentId, value] of valueOverrides) {
|
|
240
|
+
const surface = findRollingNumber(svg, componentId);
|
|
241
|
+
if (surface) {
|
|
242
|
+
setRollingNumber(surface, value, false);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
clearValues() {
|
|
247
|
+
for (const timer of pending.values()) {
|
|
248
|
+
clearTimeout(timer);
|
|
249
|
+
}
|
|
250
|
+
pending.clear();
|
|
251
|
+
valueOverrides.clear();
|
|
252
|
+
},
|
|
253
|
+
destroy() {
|
|
254
|
+
for (const timer of pending.values()) {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
}
|
|
257
|
+
pending.clear();
|
|
258
|
+
valueOverrides.clear();
|
|
189
259
|
}
|
|
190
|
-
}
|
|
191
|
-
return classifySceneDiff(oldOwnerIds, newOwnerIds, touchedOwnerIds);
|
|
260
|
+
};
|
|
192
261
|
}
|
|
193
262
|
|
|
194
|
-
// src/runtime/viewer/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
263
|
+
// src/runtime/viewer/components/rulerKnob.ts
|
|
264
|
+
var bases = /* @__PURE__ */ new WeakMap();
|
|
265
|
+
var written = /* @__PURE__ */ new WeakMap();
|
|
266
|
+
var fills = /* @__PURE__ */ new WeakMap();
|
|
267
|
+
function clamp01(value) {
|
|
268
|
+
return Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
|
|
198
269
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (root.nodeName.toLowerCase() !== "svg") {
|
|
205
|
-
throw new Error("viewer: source did not parse to an <svg> root");
|
|
270
|
+
function parameters(surface) {
|
|
271
|
+
try {
|
|
272
|
+
return JSON.parse(surface.getAttribute("data-sf-shader-params") ?? "{}");
|
|
273
|
+
} catch {
|
|
274
|
+
return {};
|
|
206
275
|
}
|
|
207
|
-
return root;
|
|
208
276
|
}
|
|
209
|
-
function
|
|
210
|
-
|
|
211
|
-
return { x: values[0], y: values[1], w: values[2], h: values[3] };
|
|
277
|
+
function positive(value, fallback) {
|
|
278
|
+
return Number(value) > 0 ? Number(value) : fallback;
|
|
212
279
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
280
|
+
function rulerProgress(surface, value) {
|
|
281
|
+
const params = parameters(surface);
|
|
282
|
+
const min = Number(params.min) || 0;
|
|
283
|
+
const max = Number.isFinite(Number(params.max)) && params.max !== void 0 ? Number(params.max) : 100;
|
|
284
|
+
return clamp01(max === min ? 0 : (value - min) / (max - min));
|
|
285
|
+
}
|
|
286
|
+
function move(node, dx, dy) {
|
|
287
|
+
const current = node.getAttribute("transform") ?? "";
|
|
288
|
+
const base = current === written.get(node) ? bases.get(node) ?? "" : current;
|
|
289
|
+
bases.set(node, base);
|
|
290
|
+
const next = `translate(${dx} ${dy}) ${base}`.trim();
|
|
291
|
+
written.set(node, next);
|
|
292
|
+
node.setAttribute("transform", next);
|
|
293
|
+
}
|
|
294
|
+
function hexToRgb(value) {
|
|
295
|
+
const match = /^#([0-9a-f]{6})$/i.exec(value.trim());
|
|
296
|
+
if (!match) {
|
|
297
|
+
return null;
|
|
223
298
|
}
|
|
224
|
-
|
|
225
|
-
|
|
299
|
+
const number2 = parseInt(match[1], 16);
|
|
300
|
+
return [number2 >> 16 & 255, number2 >> 8 & 255, number2 & 255];
|
|
301
|
+
}
|
|
302
|
+
var WHITE = [255, 255, 255];
|
|
303
|
+
function shade(node, bump, target) {
|
|
304
|
+
const base = fills.get(node) ?? node.getAttribute("fill") ?? "";
|
|
305
|
+
fills.set(node, base);
|
|
306
|
+
const rgb = hexToRgb(base);
|
|
307
|
+
if (!rgb) {
|
|
308
|
+
return;
|
|
226
309
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
310
|
+
const mixed = rgb.map((channel, index) => Math.round(channel + (target[index] - channel) * bump));
|
|
311
|
+
const fill = `rgb(${mixed[0]}, ${mixed[1]}, ${mixed[2]})`;
|
|
312
|
+
node.style.fill = fill;
|
|
313
|
+
for (const child of node.querySelectorAll("tspan")) {
|
|
314
|
+
child.style.fill = fill;
|
|
230
315
|
}
|
|
231
|
-
|
|
232
|
-
|
|
316
|
+
}
|
|
317
|
+
function placeRulerKnobs(svg, progressOf) {
|
|
318
|
+
const radii = /* @__PURE__ */ new Map();
|
|
319
|
+
for (const surface of svg.querySelectorAll('foreignObject[data-sf-shader="ruler"]')) {
|
|
320
|
+
const params = parameters(surface);
|
|
321
|
+
const peak = (typeof params.peak === "string" ? hexToRgb(params.peak) : null) ?? WHITE;
|
|
322
|
+
const id = surface.getAttribute("data-sf-id") ?? "";
|
|
323
|
+
const x = Number(surface.getAttribute("x"));
|
|
324
|
+
const y = Number(surface.getAttribute("y"));
|
|
325
|
+
const width = Number(surface.getAttribute("width"));
|
|
326
|
+
const height = Number(surface.getAttribute("height"));
|
|
327
|
+
const horizontal = params.axis === "horizontal";
|
|
328
|
+
const progress = clamp01(progressOf(id) ?? Number(params.progress));
|
|
329
|
+
const inset = positive(params.inset, 0.05);
|
|
330
|
+
const line = positive(params.line, 0.7);
|
|
331
|
+
const extent = horizontal ? width : height;
|
|
332
|
+
const across = horizontal ? height : width;
|
|
333
|
+
const along = inset + (1 - 2 * inset) * progress;
|
|
334
|
+
const dent = params.dent === void 0 ? 1 : Number(params.dent);
|
|
335
|
+
const depth = (dent < 0 ? 1 : dent) * 0.16 * across;
|
|
336
|
+
const knobId = typeof params.knob === "string" ? params.knob : "";
|
|
337
|
+
if (knobId) {
|
|
338
|
+
const nodes = [...svg.querySelectorAll(`[data-sf-id="${CSS.escape(knobId)}"]`)];
|
|
339
|
+
const primary = nodes.find((node) => node.hasAttribute("data-sf-primary"));
|
|
340
|
+
if (primary?.getBBox) {
|
|
341
|
+
move(primary, 0, 0);
|
|
342
|
+
const box = primary.getBBox();
|
|
343
|
+
const half = (horizontal ? box.height : box.width) / 2;
|
|
344
|
+
radii.set(id, half / across);
|
|
345
|
+
const gap = (params.gap === void 0 ? 0.04 : Number(params.gap)) * across;
|
|
346
|
+
const side = line * across - depth + half + gap;
|
|
347
|
+
const target = horizontal ? { x: x + width * along, y: y + side } : { x: x + side, y: y + height * (1 - along) };
|
|
348
|
+
const dx = target.x - (box.x + box.width / 2);
|
|
349
|
+
const dy = target.y - (box.y + box.height / 2);
|
|
350
|
+
for (const node of nodes) {
|
|
351
|
+
move(node, dx, dy);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const min = Number(params.min) || 0;
|
|
356
|
+
const max = Number.isFinite(Number(params.max)) && params.max !== void 0 ? Number(params.max) : 100;
|
|
357
|
+
const spread = positive(params.spread, 0.07) * extent;
|
|
358
|
+
const start = inset * extent;
|
|
359
|
+
const span = (1 - 2 * inset) * extent;
|
|
360
|
+
const knobAt = start + span * progress;
|
|
361
|
+
for (const label of svg.querySelectorAll(`text[data-sf-id="${CSS.escape(id)}"]`)) {
|
|
362
|
+
const value = Number(label.textContent);
|
|
363
|
+
if (!Number.isFinite(value) || max === min) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const labelAt = start + span * clamp01((value - min) / (max - min));
|
|
367
|
+
const bump = Math.exp(-(((labelAt - knobAt) / spread) ** 2));
|
|
368
|
+
const shift = depth * 0.4 * bump;
|
|
369
|
+
move(label, horizontal ? 0 : -shift, horizontal ? -shift : 0);
|
|
370
|
+
shade(label, bump, peak);
|
|
371
|
+
}
|
|
233
372
|
}
|
|
234
|
-
|
|
235
|
-
|
|
373
|
+
return radii;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/runtime/viewer/display/rootAttributesPatch.ts
|
|
377
|
+
var CAMERA_OWNED_ATTRIBUTES = /* @__PURE__ */ new Set(["viewbox", "width", "height"]);
|
|
378
|
+
function patchRootAttributes(svg, next) {
|
|
379
|
+
for (const attribute of Array.from(svg.attributes)) {
|
|
380
|
+
if (!CAMERA_OWNED_ATTRIBUTES.has(attribute.name.toLowerCase())) {
|
|
381
|
+
svg.removeAttribute(attribute.name);
|
|
382
|
+
}
|
|
236
383
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return null;
|
|
384
|
+
for (const attribute of Array.from(next.attributes)) {
|
|
385
|
+
if (!CAMERA_OWNED_ATTRIBUTES.has(attribute.name.toLowerCase())) {
|
|
386
|
+
svg.setAttribute(attribute.name, attribute.value);
|
|
241
387
|
}
|
|
242
|
-
const point = new DOMPoint(clientX, clientY).matrixTransform(matrix.inverse());
|
|
243
|
-
return { x: point.x, y: point.y };
|
|
244
388
|
}
|
|
245
|
-
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/runtime/viewer/display/classifySceneDiff.ts
|
|
392
|
+
function classifySceneDiff(oldOwnerIds, newOwnerIds, touchedOwnerIds) {
|
|
393
|
+
const added = [];
|
|
394
|
+
const removed = [];
|
|
395
|
+
const changed = [];
|
|
396
|
+
for (const id of touchedOwnerIds) {
|
|
397
|
+
const wasPresent = oldOwnerIds.has(id);
|
|
398
|
+
const isPresent = newOwnerIds.has(id);
|
|
399
|
+
if (isPresent && !wasPresent) {
|
|
400
|
+
added.push(id);
|
|
401
|
+
} else if (wasPresent && !isPresent) {
|
|
402
|
+
removed.push(id);
|
|
403
|
+
} else if (wasPresent && isPresent) {
|
|
404
|
+
changed.push(id);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return { added, removed, changed };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/runtime/viewer/display/definitionsPatch.ts
|
|
411
|
+
function patchDefinitions(svg, next) {
|
|
412
|
+
const currentDefinitions = svg.querySelector(":scope > defs");
|
|
413
|
+
const nextDefinitions = next.querySelector(":scope > defs");
|
|
414
|
+
if (nextDefinitions) {
|
|
415
|
+
if (currentDefinitions) {
|
|
416
|
+
currentDefinitions.replaceWith(nextDefinitions);
|
|
417
|
+
} else {
|
|
418
|
+
svg.insertBefore(nextDefinitions, svg.firstChild);
|
|
419
|
+
}
|
|
420
|
+
return nextDefinitions;
|
|
421
|
+
}
|
|
422
|
+
currentDefinitions?.remove();
|
|
423
|
+
return currentDefinitions;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/runtime/viewer/display/elementPatch.ts
|
|
427
|
+
function patchAttributes(current, next) {
|
|
428
|
+
let changed = false;
|
|
429
|
+
for (const attribute of Array.from(current.attributes)) {
|
|
430
|
+
if (!next.hasAttribute(attribute.name)) {
|
|
431
|
+
current.removeAttribute(attribute.name);
|
|
432
|
+
changed = true;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
for (const attribute of Array.from(next.attributes)) {
|
|
436
|
+
if (current.getAttribute(attribute.name) !== attribute.value) {
|
|
437
|
+
current.setAttribute(attribute.name, attribute.value);
|
|
438
|
+
changed = true;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return changed;
|
|
442
|
+
}
|
|
443
|
+
function childrenEqual(a, b) {
|
|
444
|
+
const aChildren = Array.from(a.childNodes);
|
|
445
|
+
const bChildren = Array.from(b.childNodes);
|
|
446
|
+
if (aChildren.length !== bChildren.length) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
for (let i = 0; i < aChildren.length; i++) {
|
|
450
|
+
const x = aChildren[i];
|
|
451
|
+
const y = bChildren[i];
|
|
452
|
+
if (x.nodeType !== y.nodeType) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
if (x.nodeType === Node.TEXT_NODE) {
|
|
456
|
+
if (x.textContent !== y.textContent) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (x.nodeType !== Node.ELEMENT_NODE) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const xElement = x;
|
|
465
|
+
const yElement = y;
|
|
466
|
+
if (xElement.tagName !== yElement.tagName) {
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
if (xElement.attributes.length !== yElement.attributes.length) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
for (const attribute of Array.from(xElement.attributes)) {
|
|
473
|
+
if (yElement.getAttribute(attribute.name) !== attribute.value) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (!childrenEqual(xElement, yElement)) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
function replaceTextContent(current, next) {
|
|
484
|
+
while (current.firstChild) {
|
|
485
|
+
current.removeChild(current.firstChild);
|
|
486
|
+
}
|
|
487
|
+
while (next.firstChild) {
|
|
488
|
+
current.appendChild(next.firstChild);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function patchSceneElement(current, next) {
|
|
492
|
+
const componentRestyled = next.hasAttribute("data-sf-widget") && (current.getAttribute("data-sf-widget-style") !== next.getAttribute("data-sf-widget-style") || current.getAttribute("data-sf-widget-value") !== next.getAttribute("data-sf-widget-value"));
|
|
493
|
+
const attributesChanged = patchAttributes(current, next);
|
|
494
|
+
let contentChanged = false;
|
|
495
|
+
if (componentRestyled) {
|
|
496
|
+
contentChanged = true;
|
|
497
|
+
replaceTextContent(current, next);
|
|
498
|
+
}
|
|
499
|
+
if (next.tagName.toLowerCase() === "text" && !childrenEqual(current, next)) {
|
|
500
|
+
contentChanged = true;
|
|
501
|
+
replaceTextContent(current, next);
|
|
502
|
+
}
|
|
503
|
+
return attributesChanged || contentChanged;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/runtime/viewer/display/sceneNodesPatch.ts
|
|
507
|
+
function ownerIdOf(element) {
|
|
508
|
+
return element.getAttribute("data-sf-id") ?? element.id;
|
|
509
|
+
}
|
|
510
|
+
function currentElementsById(svg) {
|
|
511
|
+
const elements = /* @__PURE__ */ new Map();
|
|
512
|
+
for (const element of svg.querySelectorAll(":scope > [id]")) {
|
|
513
|
+
elements.set(element.id, element);
|
|
514
|
+
}
|
|
515
|
+
return elements;
|
|
516
|
+
}
|
|
517
|
+
function reusableElement(current, next, markTouched) {
|
|
518
|
+
if (current && current.tagName === next.tagName) {
|
|
519
|
+
if (patchSceneElement(current, next)) {
|
|
520
|
+
markTouched(ownerIdOf(next));
|
|
521
|
+
}
|
|
522
|
+
return current;
|
|
523
|
+
}
|
|
524
|
+
current?.remove();
|
|
525
|
+
markTouched(ownerIdOf(next));
|
|
526
|
+
return next;
|
|
527
|
+
}
|
|
528
|
+
function placeAfter(svg, element, previousSibling) {
|
|
529
|
+
const wantedNext = previousSibling ? previousSibling.nextSibling : svg.firstChild;
|
|
530
|
+
if (wantedNext !== element) {
|
|
531
|
+
svg.insertBefore(element, wantedNext);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function patchSceneNodes(svg, next) {
|
|
535
|
+
const definitions = patchDefinitions(svg, next);
|
|
536
|
+
const currentById = currentElementsById(svg);
|
|
537
|
+
const retainedIds = /* @__PURE__ */ new Set();
|
|
538
|
+
const oldOwnerIds = /* @__PURE__ */ new Set();
|
|
539
|
+
for (const element of currentById.values()) {
|
|
540
|
+
oldOwnerIds.add(ownerIdOf(element));
|
|
541
|
+
}
|
|
542
|
+
const newOwnerIds = /* @__PURE__ */ new Set();
|
|
543
|
+
const touchedOwnerIds = /* @__PURE__ */ new Set();
|
|
544
|
+
const markTouched = (ownerId) => {
|
|
545
|
+
touchedOwnerIds.add(ownerId);
|
|
546
|
+
};
|
|
547
|
+
let previousSibling = definitions;
|
|
548
|
+
for (const nextElement of next.querySelectorAll(":scope > [id]")) {
|
|
549
|
+
retainedIds.add(nextElement.id);
|
|
550
|
+
newOwnerIds.add(ownerIdOf(nextElement));
|
|
551
|
+
const liveElement = reusableElement(currentById.get(nextElement.id), nextElement, markTouched);
|
|
552
|
+
placeAfter(svg, liveElement, previousSibling);
|
|
553
|
+
previousSibling = liveElement;
|
|
554
|
+
}
|
|
555
|
+
for (const [id, element] of currentById) {
|
|
556
|
+
if (!retainedIds.has(id)) {
|
|
557
|
+
touchedOwnerIds.add(ownerIdOf(element));
|
|
558
|
+
element.remove();
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return classifySceneDiff(oldOwnerIds, newOwnerIds, touchedOwnerIds);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/runtime/viewer/display/scenePatch.ts
|
|
565
|
+
function patchDisplayContent(svg, next) {
|
|
566
|
+
patchRootAttributes(svg, next);
|
|
567
|
+
return patchSceneNodes(svg, next);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/runtime/viewer/display/svgDocument.ts
|
|
571
|
+
function parseSvg(svgString) {
|
|
572
|
+
const document = new DOMParser().parseFromString(svgString, "image/svg+xml");
|
|
573
|
+
const root = document.documentElement;
|
|
574
|
+
if (root.nodeName.toLowerCase() !== "svg") {
|
|
575
|
+
throw new Error("viewer: source did not parse to an <svg> root");
|
|
576
|
+
}
|
|
577
|
+
return root;
|
|
578
|
+
}
|
|
579
|
+
function readViewBox(svg) {
|
|
580
|
+
const values = (svg.getAttribute("viewBox") ?? "0 0 100 100").split(/\s+/).map(Number);
|
|
581
|
+
return { x: values[0], y: values[1], w: values[2], h: values[3] };
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// src/runtime/viewer/display/viewport.ts
|
|
585
|
+
var ViewportController = class {
|
|
586
|
+
#svg;
|
|
587
|
+
#natural;
|
|
588
|
+
#view;
|
|
589
|
+
constructor(svg, natural) {
|
|
590
|
+
this.#svg = svg;
|
|
591
|
+
this.#natural = natural;
|
|
592
|
+
this.#view = { ...natural };
|
|
593
|
+
}
|
|
594
|
+
apply() {
|
|
595
|
+
this.#svg.setAttribute("viewBox", `${this.#view.x} ${this.#view.y} ${this.#view.w} ${this.#view.h}`);
|
|
596
|
+
}
|
|
597
|
+
fit() {
|
|
598
|
+
this.#view = { ...this.#natural };
|
|
599
|
+
this.apply();
|
|
600
|
+
}
|
|
601
|
+
get() {
|
|
602
|
+
return { ...this.#view };
|
|
603
|
+
}
|
|
604
|
+
setNatural(natural) {
|
|
605
|
+
this.#natural = natural;
|
|
606
|
+
}
|
|
607
|
+
#userPoint(clientX, clientY) {
|
|
608
|
+
const matrix = this.#svg.getScreenCTM();
|
|
609
|
+
if (!matrix) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
const point = new DOMPoint(clientX, clientY).matrixTransform(matrix.inverse());
|
|
613
|
+
return { x: point.x, y: point.y };
|
|
614
|
+
}
|
|
615
|
+
zoomBy(factor, clientX, clientY) {
|
|
246
616
|
const rect = this.#svg.getBoundingClientRect();
|
|
247
617
|
if (rect.width <= 0 || rect.height <= 0) {
|
|
248
618
|
return;
|
|
@@ -297,11 +667,11 @@ function mountDisplay(container, svgString) {
|
|
|
297
667
|
}
|
|
298
668
|
|
|
299
669
|
// src/runtime/viewer/events.ts
|
|
300
|
-
var Emitter2 = class extends
|
|
670
|
+
var Emitter2 = class extends chunkL3VJXZFD_cjs.Emitter {
|
|
301
671
|
};
|
|
302
672
|
|
|
303
673
|
// src/runtime/viewer/export/raster.ts
|
|
304
|
-
function
|
|
674
|
+
function positive2(value, fallback) {
|
|
305
675
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
306
676
|
}
|
|
307
677
|
function loadImage(document, source) {
|
|
@@ -334,7 +704,7 @@ function canvasBlob(canvas, mimeType, quality) {
|
|
|
334
704
|
}
|
|
335
705
|
async function rasterizeSvgSnapshot(svg, snapshot, options = {}) {
|
|
336
706
|
const viewBox = readViewBox(svg);
|
|
337
|
-
const scale =
|
|
707
|
+
const scale = positive2(options.scale, 1);
|
|
338
708
|
const width = Math.max(1, Math.round(viewBox.w * scale));
|
|
339
709
|
const height = Math.max(1, Math.round(viewBox.h * scale));
|
|
340
710
|
const canvas = svg.ownerDocument.createElement("canvas");
|
|
@@ -384,14 +754,14 @@ function svgElement(document, name, attributes) {
|
|
|
384
754
|
}
|
|
385
755
|
return element;
|
|
386
756
|
}
|
|
387
|
-
function
|
|
757
|
+
function readComponentStyle(surface) {
|
|
388
758
|
try {
|
|
389
759
|
return {
|
|
390
|
-
...
|
|
760
|
+
...chunkXY2GZUHC_cjs.DEFAULT_ROLLING_NUMBER_STYLE,
|
|
391
761
|
...JSON.parse(surface.getAttribute("data-sf-widget-style") ?? "{}")
|
|
392
762
|
};
|
|
393
763
|
} catch {
|
|
394
|
-
return
|
|
764
|
+
return chunkXY2GZUHC_cjs.DEFAULT_ROLLING_NUMBER_STYLE;
|
|
395
765
|
}
|
|
396
766
|
}
|
|
397
767
|
function cellsOf(box, plain, fontSize = 0) {
|
|
@@ -479,7 +849,7 @@ function flattenRollingNumbers(svg) {
|
|
|
479
849
|
height: Number(surface.getAttribute("height"))
|
|
480
850
|
};
|
|
481
851
|
const value = surface.getAttribute("data-sf-widget-value") ?? "";
|
|
482
|
-
const style =
|
|
852
|
+
const style = readComponentStyle(surface);
|
|
483
853
|
const label = surface.querySelector("div > span:not([data-sf-rolling-digit])")?.textContent ?? "";
|
|
484
854
|
const cells = cellsOf(box, style.variant === "plain", style.fontSize);
|
|
485
855
|
const labelBlock = label ? cells.size * 0.3 : 0;
|
|
@@ -531,7 +901,7 @@ function serializeSvgSnapshot(svg, captures) {
|
|
|
531
901
|
// src/runtime/viewer/interaction/changeFlash.ts
|
|
532
902
|
function createChangeFlash(svg) {
|
|
533
903
|
const timers = /* @__PURE__ */ new Map();
|
|
534
|
-
const flash = (ownerIds, color2 =
|
|
904
|
+
const flash = (ownerIds, color2 = chunkL3VJXZFD_cjs.CHANGE_COLOR) => {
|
|
535
905
|
const ids = [...new Set(ownerIds)];
|
|
536
906
|
if (ids.length === 0) {
|
|
537
907
|
return;
|
|
@@ -539,7 +909,7 @@ function createChangeFlash(svg) {
|
|
|
539
909
|
const doc = svg.ownerDocument;
|
|
540
910
|
const reducedMotion = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
541
911
|
for (const id of ids) {
|
|
542
|
-
const primary =
|
|
912
|
+
const primary = chunkL3VJXZFD_cjs.findOwnerNode(svg, id, chunkL3VJXZFD_cjs.isPrimary);
|
|
543
913
|
if (!primary) {
|
|
544
914
|
continue;
|
|
545
915
|
}
|
|
@@ -550,10 +920,10 @@ function createChangeFlash(svg) {
|
|
|
550
920
|
for (const stale of svg.querySelectorAll(`[data-sf-change-overlay="${CSS.escape(id)}"]`)) {
|
|
551
921
|
stale.remove();
|
|
552
922
|
}
|
|
553
|
-
const overlay = primary.getAttribute("data-sf-role") === "link" ?
|
|
923
|
+
const overlay = primary.getAttribute("data-sf-role") === "link" ? chunkL3VJXZFD_cjs.linkChangeOverlay(doc, primary, id, color2) : chunkL3VJXZFD_cjs.shapeChangeOverlay(doc, primary, id, color2);
|
|
554
924
|
svg.appendChild(overlay);
|
|
555
|
-
|
|
556
|
-
const duration = reducedMotion ?
|
|
925
|
+
chunkL3VJXZFD_cjs.startChangeFade(overlay, reducedMotion);
|
|
926
|
+
const duration = reducedMotion ? chunkL3VJXZFD_cjs.REDUCED_MOTION_DURATION_MS : chunkL3VJXZFD_cjs.FLASH_DURATION_MS;
|
|
557
927
|
timers.set(
|
|
558
928
|
id,
|
|
559
929
|
setTimeout(() => {
|
|
@@ -640,7 +1010,7 @@ var OwnerPointerController = class {
|
|
|
640
1010
|
this.#selection = selection;
|
|
641
1011
|
}
|
|
642
1012
|
hover(event) {
|
|
643
|
-
const owner =
|
|
1013
|
+
const owner = chunkL3VJXZFD_cjs.resolveOwner(event.target);
|
|
644
1014
|
this.#emitter.emit(
|
|
645
1015
|
"ownerHover",
|
|
646
1016
|
owner ? { diagramId: this.#diagramId, owner, modifiers: modifiersOf(event) } : { diagramId: this.#diagramId, owner: null }
|
|
@@ -648,7 +1018,7 @@ var OwnerPointerController = class {
|
|
|
648
1018
|
}
|
|
649
1019
|
select(event) {
|
|
650
1020
|
const target = event.target;
|
|
651
|
-
const owner =
|
|
1021
|
+
const owner = chunkL3VJXZFD_cjs.resolveOwner(target);
|
|
652
1022
|
if (!owner) {
|
|
653
1023
|
this.#clearWhenOutsideOverlay(target);
|
|
654
1024
|
return;
|
|
@@ -669,7 +1039,7 @@ var OwnerPointerController = class {
|
|
|
669
1039
|
owner,
|
|
670
1040
|
modifiers
|
|
671
1041
|
});
|
|
672
|
-
const node =
|
|
1042
|
+
const node = chunkL3VJXZFD_cjs.findOwnerNode(this.#svg, owner.id, chunkL3VJXZFD_cjs.isPrimary);
|
|
673
1043
|
if (node && !node.hasAttribute("tabindex")) {
|
|
674
1044
|
node.setAttribute("tabindex", "-1");
|
|
675
1045
|
}
|
|
@@ -697,12 +1067,12 @@ var PointerInteractionSession = class {
|
|
|
697
1067
|
}
|
|
698
1068
|
#onPointerDown = (event) => {
|
|
699
1069
|
const target = event.target;
|
|
700
|
-
const overContent = Boolean(
|
|
1070
|
+
const overContent = Boolean(chunkL3VJXZFD_cjs.resolveOwner(target)) || isSelectionOverlayControl(target);
|
|
701
1071
|
this.#down = {
|
|
702
1072
|
x: event.clientX,
|
|
703
1073
|
y: event.clientY,
|
|
704
1074
|
moved: false,
|
|
705
|
-
panable:
|
|
1075
|
+
panable: chunkL3VJXZFD_cjs.isCameraGesture(event) || !overContent
|
|
706
1076
|
};
|
|
707
1077
|
};
|
|
708
1078
|
#onPointerMove = (event) => {
|
|
@@ -730,7 +1100,7 @@ var PointerInteractionSession = class {
|
|
|
730
1100
|
if (!this.#down.moved) {
|
|
731
1101
|
return false;
|
|
732
1102
|
}
|
|
733
|
-
if (this.#down.panable &&
|
|
1103
|
+
if (this.#down.panable && chunkL3VJXZFD_cjs.isCameraGesture(event)) {
|
|
734
1104
|
this.#display.panBy(event.movementX, event.movementY);
|
|
735
1105
|
}
|
|
736
1106
|
return true;
|
|
@@ -754,15 +1124,15 @@ function paintSelectionOverlays(svg, selectedIds, owners) {
|
|
|
754
1124
|
}
|
|
755
1125
|
const document = svg.ownerDocument;
|
|
756
1126
|
for (const id of selectedIds) {
|
|
757
|
-
const primary =
|
|
1127
|
+
const primary = chunkL3VJXZFD_cjs.findOwnerNode(svg, id, chunkL3VJXZFD_cjs.isPrimary);
|
|
758
1128
|
if (!primary) {
|
|
759
1129
|
continue;
|
|
760
1130
|
}
|
|
761
1131
|
const owner = owners.get(id);
|
|
762
|
-
const overlay = owner?.role === "link" ?
|
|
1132
|
+
const overlay = owner?.role === "link" ? chunkL3VJXZFD_cjs.linkSelectionOverlay(document, primary, id, svg) : owner?.role === "path" ? chunkL3VJXZFD_cjs.pathSelectionOverlay(document, primary, id, svg) : owner?.role === "isometric" ? chunkL3VJXZFD_cjs.isometricSelectionOverlay(document, primary, id, svg) : chunkL3VJXZFD_cjs.shapeSelectionOverlay(document, primary, id, svg, owner ? chunkL3VJXZFD_cjs.DERIVED_HEIGHT_ROLES.has(owner.role) : false);
|
|
763
1133
|
svg.appendChild(overlay);
|
|
764
1134
|
if (owner?.role === "shape" && selectedIds.size === 1) {
|
|
765
|
-
svg.appendChild(
|
|
1135
|
+
svg.appendChild(chunkL3VJXZFD_cjs.quickDuplicateBubbles(document, primary, id, svg));
|
|
766
1136
|
}
|
|
767
1137
|
}
|
|
768
1138
|
}
|
|
@@ -801,7 +1171,7 @@ var SelectionController = class {
|
|
|
801
1171
|
selectIds(ids) {
|
|
802
1172
|
for (const id of ids) {
|
|
803
1173
|
const element = this.#svg.querySelector(`[data-sf-id="${CSS.escape(id)}"]`);
|
|
804
|
-
const owner =
|
|
1174
|
+
const owner = chunkL3VJXZFD_cjs.resolveOwner(element);
|
|
805
1175
|
if (owner) {
|
|
806
1176
|
this.remember(owner);
|
|
807
1177
|
}
|
|
@@ -813,7 +1183,7 @@ var SelectionController = class {
|
|
|
813
1183
|
// src/runtime/viewer/interaction/wheel.ts
|
|
814
1184
|
function bindWheelZoom(display, selection) {
|
|
815
1185
|
const onWheel = (event) => {
|
|
816
|
-
if (!
|
|
1186
|
+
if (!chunkL3VJXZFD_cjs.isCameraGesture(event)) {
|
|
817
1187
|
return;
|
|
818
1188
|
}
|
|
819
1189
|
event.preventDefault();
|
|
@@ -2427,951 +2797,584 @@ var violetGlassLightProgram = {
|
|
|
2427
2797
|
fragmentSource: fragmentSource20
|
|
2428
2798
|
};
|
|
2429
2799
|
|
|
2430
|
-
// src/runtime/viewer/shaders/programs.ts
|
|
2431
|
-
var builtins = [
|
|
2432
|
-
orbProgram,
|
|
2433
|
-
haloProgram,
|
|
2434
|
-
halftoneHaloProgram,
|
|
2435
|
-
chromaticHaloProgram,
|
|
2436
|
-
chromaticGlassPlateProgram,
|
|
2437
|
-
glassRefractionProgram,
|
|
2438
|
-
emberSlitsProgram,
|
|
2439
|
-
smearOrbProgram,
|
|
2440
|
-
pixelConstellationProgram,
|
|
2441
|
-
plasmaGaugeProgram,
|
|
2442
|
-
tickScaleProgram,
|
|
2443
|
-
rulerProgram,
|
|
2444
|
-
buttonProgram,
|
|
2445
|
-
prismSlatsProgram,
|
|
2446
|
-
eclipseOrbProgram,
|
|
2447
|
-
emberMatrixProgram,
|
|
2448
|
-
violetGlassProgram,
|
|
2449
|
-
violetGlassLightProgram,
|
|
2450
|
-
lumenPortalProgram,
|
|
2451
|
-
lumenPortalLightProgram
|
|
2452
|
-
];
|
|
2453
|
-
var programs = new Map(builtins.map((program) => [program.name, program]));
|
|
2454
|
-
function registerShaderProgram(program) {
|
|
2455
|
-
if (!program.name.trim()) {
|
|
2456
|
-
throw new Error("registerShaderProgram: name must not be empty.");
|
|
2457
|
-
}
|
|
2458
|
-
if (!program.fragmentSource.includes("void main")) {
|
|
2459
|
-
throw new Error(`registerShaderProgram: "${program.name}" has no main function.`);
|
|
2460
|
-
}
|
|
2461
|
-
programs.set(program.name, program);
|
|
2462
|
-
return () => {
|
|
2463
|
-
if (programs.get(program.name) === program) {
|
|
2464
|
-
programs.delete(program.name);
|
|
2465
|
-
}
|
|
2466
|
-
};
|
|
2467
|
-
}
|
|
2468
|
-
function shaderProgram(name) {
|
|
2469
|
-
return programs.get(name);
|
|
2470
|
-
}
|
|
2471
|
-
|
|
2472
|
-
// src/runtime/viewer/shaders/backdrop.ts
|
|
2473
|
-
var MIN_BACKDROP_DENSITY = 2.5;
|
|
2474
|
-
var MAX_BACKDROP_PIXELS = 4096;
|
|
2475
|
-
var TRANSPARENT = /^rgba?(s*d+,s*d+,s*d+,s*0s*)$|^transparent$/;
|
|
2476
|
-
function hostBackground(svg) {
|
|
2477
|
-
const view = svg.ownerDocument.defaultView;
|
|
2478
|
-
for (let element = svg.parentElement; element && view; element = element.parentElement) {
|
|
2479
|
-
const color2 = view.getComputedStyle(element).backgroundColor;
|
|
2480
|
-
if (color2 && !TRANSPARENT.test(color2.trim())) {
|
|
2481
|
-
return color2;
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
|
-
return void 0;
|
|
2485
|
-
}
|
|
2486
|
-
function backdropClone(svg, owner, width, height) {
|
|
2487
|
-
const clone = svg.cloneNode(true);
|
|
2488
|
-
const ownerIndex = [...svg.children].indexOf(owner);
|
|
2489
|
-
if (ownerIndex >= 0) {
|
|
2490
|
-
while (clone.children.length > ownerIndex) {
|
|
2491
|
-
clone.lastElementChild?.remove();
|
|
2492
|
-
}
|
|
2493
|
-
}
|
|
2494
|
-
for (const surface of clone.querySelectorAll("foreignObject[data-sf-shader]")) {
|
|
2495
|
-
surface.remove();
|
|
2496
|
-
}
|
|
2497
|
-
const background = hostBackground(svg);
|
|
2498
|
-
if (background) {
|
|
2499
|
-
const { x, y, width: viewWidth, height: viewHeight } = svg.viewBox.baseVal;
|
|
2500
|
-
const fill = svg.ownerDocument.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
2501
|
-
fill.setAttribute("x", String(x));
|
|
2502
|
-
fill.setAttribute("y", String(y));
|
|
2503
|
-
fill.setAttribute("width", String(viewWidth));
|
|
2504
|
-
fill.setAttribute("height", String(viewHeight));
|
|
2505
|
-
fill.setAttribute("fill", background);
|
|
2506
|
-
clone.insertBefore(fill, clone.firstChild);
|
|
2507
|
-
}
|
|
2508
|
-
clone.setAttribute("width", String(width));
|
|
2509
|
-
clone.setAttribute("height", String(height));
|
|
2510
|
-
clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
2511
|
-
return clone;
|
|
2512
|
-
}
|
|
2513
|
-
function captureShaderBackdrop(svg, owner) {
|
|
2514
|
-
const density = Math.max(globalThis.devicePixelRatio || 1, MIN_BACKDROP_DENSITY);
|
|
2515
|
-
const scale = Math.min(density, MAX_BACKDROP_PIXELS / Math.max(1, Math.max(svg.clientWidth, svg.clientHeight)));
|
|
2516
|
-
const width = Math.max(1, Math.round(svg.clientWidth * scale));
|
|
2517
|
-
const height = Math.max(1, Math.round(svg.clientHeight * scale));
|
|
2518
|
-
const view = svg.ownerDocument.defaultView;
|
|
2519
|
-
if (!view) {
|
|
2520
|
-
return Promise.resolve(void 0);
|
|
2521
|
-
}
|
|
2522
|
-
const markup = new XMLSerializer().serializeToString(backdropClone(svg, owner, width, height));
|
|
2523
|
-
const image = svg.ownerDocument.createElement("img");
|
|
2524
|
-
const source = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;
|
|
2525
|
-
return new Promise((resolve) => {
|
|
2526
|
-
image.onload = () => resolve({ image, width, height });
|
|
2527
|
-
image.onerror = () => resolve(void 0);
|
|
2528
|
-
image.src = source;
|
|
2529
|
-
});
|
|
2530
|
-
}
|
|
2531
|
-
|
|
2532
|
-
// src/runtime/viewer/shaders/uniforms.ts
|
|
2533
|
-
function color(value, fallback) {
|
|
2534
|
-
if (typeof value !== "string") {
|
|
2535
|
-
return fallback;
|
|
2536
|
-
}
|
|
2537
|
-
const match = /^#([0-9a-f]{6})$/i.exec(value);
|
|
2538
|
-
if (!match) {
|
|
2539
|
-
return fallback;
|
|
2540
|
-
}
|
|
2541
|
-
const integer = Number.parseInt(match[1], 16);
|
|
2542
|
-
return [(integer >> 16 & 255) / 255, (integer >> 8 & 255) / 255, (integer & 255) / 255];
|
|
2543
|
-
}
|
|
2544
|
-
function number(value, fallback) {
|
|
2545
|
-
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
2546
|
-
}
|
|
2547
|
-
function uniform1f(surface, name, value) {
|
|
2548
|
-
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2549
|
-
if (location) {
|
|
2550
|
-
surface.gl.uniform1f(location, value);
|
|
2551
|
-
}
|
|
2552
|
-
}
|
|
2553
|
-
function uniform3f(surface, name, value) {
|
|
2554
|
-
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2555
|
-
if (location) {
|
|
2556
|
-
surface.gl.uniform3f(location, ...value);
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
function uniform2f(surface, name, value) {
|
|
2560
|
-
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2561
|
-
if (location) {
|
|
2562
|
-
surface.gl.uniform2f(location, ...value);
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
function uniformName(parameter) {
|
|
2566
|
-
return `u${parameter.charAt(0).toUpperCase()}${parameter.slice(1)}`;
|
|
2567
|
-
}
|
|
2568
|
-
function enumParameter(name, value) {
|
|
2569
|
-
const values = {
|
|
2570
|
-
direction: { left: 0, right: 1, top: 2, bottom: 3 },
|
|
2571
|
-
orientation: { vertical: 0, horizontal: 1 },
|
|
2572
|
-
axis: { vertical: 0, horizontal: 1 }
|
|
2573
|
-
};
|
|
2574
|
-
return values[name]?.[value];
|
|
2575
|
-
}
|
|
2576
|
-
function applyParameters(surface, elapsed) {
|
|
2577
|
-
for (const [key, value] of Object.entries(surface.parameters)) {
|
|
2578
|
-
const name = uniformName(key);
|
|
2579
|
-
if (typeof value === "number") {
|
|
2580
|
-
const lag = surface.parameters[`${key}Lag`];
|
|
2581
|
-
if (typeof lag === "number" && lag > 0) {
|
|
2582
|
-
const current = surface.smoothed.get(key) ?? value;
|
|
2583
|
-
const next = current + (value - current) * (1 - Math.exp(-elapsed / lag));
|
|
2584
|
-
surface.smoothed.set(key, next);
|
|
2585
|
-
uniform1f(surface, name, next);
|
|
2586
|
-
continue;
|
|
2587
|
-
}
|
|
2588
|
-
uniform1f(surface, name, value);
|
|
2589
|
-
continue;
|
|
2590
|
-
}
|
|
2591
|
-
if (typeof value === "boolean") {
|
|
2592
|
-
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2593
|
-
if (location) {
|
|
2594
|
-
surface.gl.uniform1i(location, value ? 1 : 0);
|
|
2595
|
-
}
|
|
2596
|
-
continue;
|
|
2597
|
-
}
|
|
2598
|
-
const enumValue = enumParameter(key, value);
|
|
2599
|
-
if (enumValue !== void 0) {
|
|
2600
|
-
uniform1f(surface, name, enumValue);
|
|
2601
|
-
continue;
|
|
2602
|
-
}
|
|
2603
|
-
if (/^#[0-9a-f]{6}$/i.test(value)) {
|
|
2604
|
-
uniform3f(surface, name, color(value, [0, 0, 0]));
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
|
|
2609
|
-
// src/runtime/viewer/shaders/webgl.ts
|
|
2610
|
-
var VERTEX_SOURCE = `
|
|
2611
|
-
attribute vec2 aPosition;
|
|
2612
|
-
varying vec2 vUv;
|
|
2613
|
-
|
|
2614
|
-
void main() {
|
|
2615
|
-
vUv = aPosition * 0.5 + 0.5;
|
|
2616
|
-
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
2617
|
-
}
|
|
2618
|
-
`;
|
|
2619
|
-
function compile(gl, type, source) {
|
|
2620
|
-
const shader = gl.createShader(type);
|
|
2621
|
-
if (!shader) {
|
|
2622
|
-
return void 0;
|
|
2623
|
-
}
|
|
2624
|
-
gl.shaderSource(shader, source);
|
|
2625
|
-
gl.compileShader(shader);
|
|
2626
|
-
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
2627
|
-
gl.deleteShader(shader);
|
|
2628
|
-
return void 0;
|
|
2629
|
-
}
|
|
2630
|
-
return shader;
|
|
2631
|
-
}
|
|
2632
|
-
function linkProgram(gl, fragmentSource21) {
|
|
2633
|
-
const vertex = compile(gl, gl.VERTEX_SHADER, VERTEX_SOURCE);
|
|
2634
|
-
const fragment = compile(gl, gl.FRAGMENT_SHADER, fragmentSource21);
|
|
2635
|
-
if (!vertex || !fragment) {
|
|
2636
|
-
if (vertex) {
|
|
2637
|
-
gl.deleteShader(vertex);
|
|
2638
|
-
}
|
|
2639
|
-
if (fragment) {
|
|
2640
|
-
gl.deleteShader(fragment);
|
|
2641
|
-
}
|
|
2642
|
-
return void 0;
|
|
2643
|
-
}
|
|
2644
|
-
const program = gl.createProgram();
|
|
2645
|
-
if (!program) {
|
|
2646
|
-
gl.deleteShader(vertex);
|
|
2647
|
-
gl.deleteShader(fragment);
|
|
2648
|
-
return void 0;
|
|
2649
|
-
}
|
|
2650
|
-
gl.attachShader(program, vertex);
|
|
2651
|
-
gl.attachShader(program, fragment);
|
|
2652
|
-
gl.linkProgram(program);
|
|
2653
|
-
gl.deleteShader(vertex);
|
|
2654
|
-
gl.deleteShader(fragment);
|
|
2655
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
2656
|
-
gl.deleteProgram(program);
|
|
2657
|
-
return void 0;
|
|
2658
|
-
}
|
|
2659
|
-
return program;
|
|
2660
|
-
}
|
|
2661
|
-
function transparentTexture(gl) {
|
|
2662
|
-
const texture = gl.createTexture();
|
|
2663
|
-
if (!texture) {
|
|
2664
|
-
return void 0;
|
|
2665
|
-
}
|
|
2666
|
-
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
2667
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
2668
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
2669
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
2670
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
2671
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
|
|
2672
|
-
return texture;
|
|
2673
|
-
}
|
|
2674
|
-
|
|
2675
|
-
// src/runtime/viewer/shaders/createSurface.ts
|
|
2676
|
-
var FULL_SCREEN_QUAD = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);
|
|
2677
|
-
function parametersOf(owner) {
|
|
2678
|
-
try {
|
|
2679
|
-
return JSON.parse(owner.getAttribute("data-sf-shader-params") ?? "{}");
|
|
2680
|
-
} catch {
|
|
2681
|
-
return {};
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
function bindFullScreenQuad(gl, program) {
|
|
2685
|
-
const buffer = gl.createBuffer();
|
|
2686
|
-
if (!buffer) {
|
|
2687
|
-
return void 0;
|
|
2688
|
-
}
|
|
2689
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
2690
|
-
gl.bufferData(gl.ARRAY_BUFFER, FULL_SCREEN_QUAD, gl.STATIC_DRAW);
|
|
2691
|
-
const position = gl.getAttribLocation(program, "aPosition");
|
|
2692
|
-
if (position < 0) {
|
|
2693
|
-
gl.deleteBuffer(buffer);
|
|
2694
|
-
return void 0;
|
|
2695
|
-
}
|
|
2696
|
-
gl.enableVertexAttribArray(position);
|
|
2697
|
-
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
|
2698
|
-
return buffer;
|
|
2699
|
-
}
|
|
2700
|
-
function findBaseGeometry(owner, definition) {
|
|
2701
|
-
const ownerId = owner.getAttribute("data-sf-id");
|
|
2702
|
-
if (!definition.replacesBaseFill || !ownerId) {
|
|
2703
|
-
return void 0;
|
|
2704
|
-
}
|
|
2705
|
-
const candidates = [...owner.closest("svg")?.querySelectorAll('[data-sf-primary="true"]') ?? []];
|
|
2706
|
-
return candidates.find((element) => element !== owner && element.getAttribute("data-sf-id") === ownerId);
|
|
2707
|
-
}
|
|
2708
|
-
function createSurface(canvas) {
|
|
2709
|
-
const owner = canvas.closest("[data-sf-shader]");
|
|
2710
|
-
const name = owner?.getAttribute("data-sf-shader");
|
|
2711
|
-
const definition = name ? shaderProgram(name) : void 0;
|
|
2712
|
-
const gl = canvas.getContext("webgl", { alpha: true, antialias: true, premultipliedAlpha: true });
|
|
2713
|
-
if (!owner || !definition || !gl) {
|
|
2714
|
-
return void 0;
|
|
2715
|
-
}
|
|
2716
|
-
const program = linkProgram(gl, definition.fragmentSource);
|
|
2717
|
-
if (!program) {
|
|
2718
|
-
return void 0;
|
|
2719
|
-
}
|
|
2720
|
-
gl.useProgram(program);
|
|
2721
|
-
const buffer = bindFullScreenQuad(gl, program);
|
|
2722
|
-
if (!buffer) {
|
|
2723
|
-
gl.deleteProgram(program);
|
|
2724
|
-
return void 0;
|
|
2725
|
-
}
|
|
2726
|
-
const usesBackdrop = definition.usesBackdrop === true;
|
|
2727
|
-
const baseGeometry = findBaseGeometry(owner, definition);
|
|
2728
|
-
const baseFill = baseGeometry?.getAttribute("fill");
|
|
2729
|
-
baseGeometry?.setAttribute("fill", "none");
|
|
2730
|
-
return {
|
|
2731
|
-
owner,
|
|
2732
|
-
canvas,
|
|
2733
|
-
gl,
|
|
2734
|
-
program,
|
|
2735
|
-
buffer,
|
|
2736
|
-
parameters: parametersOf(owner),
|
|
2737
|
-
smoothed: /* @__PURE__ */ new Map(),
|
|
2738
|
-
backdropTexture: usesBackdrop ? transparentTexture(gl) : void 0,
|
|
2739
|
-
backdropOrigin: [0, 0],
|
|
2740
|
-
backdropScale: [1, 1],
|
|
2741
|
-
usesBackdrop,
|
|
2742
|
-
shapeColor: color(owner.getAttribute("data-sf-shader-fill") ?? void 0, [1, 1, 1]),
|
|
2743
|
-
baseGeometry,
|
|
2744
|
-
baseFill
|
|
2745
|
-
};
|
|
2746
|
-
}
|
|
2747
|
-
function releaseSurface(surface) {
|
|
2748
|
-
if (surface.backdropTexture) {
|
|
2749
|
-
surface.gl.deleteTexture(surface.backdropTexture);
|
|
2750
|
-
}
|
|
2751
|
-
surface.gl.deleteBuffer(surface.buffer);
|
|
2752
|
-
surface.gl.deleteProgram(surface.program);
|
|
2753
|
-
if (!surface.baseGeometry) {
|
|
2754
|
-
return;
|
|
2755
|
-
}
|
|
2756
|
-
if (surface.baseFill === null || surface.baseFill === void 0) {
|
|
2757
|
-
surface.baseGeometry.removeAttribute("fill");
|
|
2758
|
-
} else {
|
|
2759
|
-
surface.baseGeometry.setAttribute("fill", surface.baseFill);
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
|
|
2763
|
-
// src/runtime/viewer/shaders/renderSurface.ts
|
|
2764
|
-
function syncBackdropBounds(surface) {
|
|
2765
|
-
const svg = surface.canvas.closest("svg");
|
|
2766
|
-
if (!svg) {
|
|
2767
|
-
return;
|
|
2800
|
+
// src/runtime/viewer/shaders/programs.ts
|
|
2801
|
+
var builtins = [
|
|
2802
|
+
orbProgram,
|
|
2803
|
+
haloProgram,
|
|
2804
|
+
halftoneHaloProgram,
|
|
2805
|
+
chromaticHaloProgram,
|
|
2806
|
+
chromaticGlassPlateProgram,
|
|
2807
|
+
glassRefractionProgram,
|
|
2808
|
+
emberSlitsProgram,
|
|
2809
|
+
smearOrbProgram,
|
|
2810
|
+
pixelConstellationProgram,
|
|
2811
|
+
plasmaGaugeProgram,
|
|
2812
|
+
tickScaleProgram,
|
|
2813
|
+
rulerProgram,
|
|
2814
|
+
buttonProgram,
|
|
2815
|
+
prismSlatsProgram,
|
|
2816
|
+
eclipseOrbProgram,
|
|
2817
|
+
emberMatrixProgram,
|
|
2818
|
+
violetGlassProgram,
|
|
2819
|
+
violetGlassLightProgram,
|
|
2820
|
+
lumenPortalProgram,
|
|
2821
|
+
lumenPortalLightProgram
|
|
2822
|
+
];
|
|
2823
|
+
var programs = new Map(builtins.map((program) => [program.name, program]));
|
|
2824
|
+
function registerShaderProgram(program) {
|
|
2825
|
+
if (!program.name.trim()) {
|
|
2826
|
+
throw new Error("registerShaderProgram: name must not be empty.");
|
|
2768
2827
|
}
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
if (svgBounds.width <= 0 || svgBounds.height <= 0) {
|
|
2772
|
-
return;
|
|
2828
|
+
if (!program.fragmentSource.includes("void main")) {
|
|
2829
|
+
throw new Error(`registerShaderProgram: "${program.name}" has no main function.`);
|
|
2773
2830
|
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
(
|
|
2777
|
-
|
|
2778
|
-
|
|
2831
|
+
programs.set(program.name, program);
|
|
2832
|
+
return () => {
|
|
2833
|
+
if (programs.get(program.name) === program) {
|
|
2834
|
+
programs.delete(program.name);
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2779
2837
|
}
|
|
2780
|
-
function
|
|
2781
|
-
|
|
2782
|
-
return;
|
|
2783
|
-
}
|
|
2784
|
-
syncBackdropBounds(surface);
|
|
2785
|
-
const { gl } = surface;
|
|
2786
|
-
gl.bindTexture(gl.TEXTURE_2D, surface.backdropTexture);
|
|
2787
|
-
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
|
|
2788
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, backdrop.image);
|
|
2838
|
+
function shaderProgram(name) {
|
|
2839
|
+
return programs.get(name);
|
|
2789
2840
|
}
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
const
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
gl.viewport(0, 0, width, height);
|
|
2803
|
-
gl.clearColor(0, 0, 0, 0);
|
|
2804
|
-
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
2805
|
-
gl.useProgram(surface.program);
|
|
2806
|
-
const resolution = gl.getUniformLocation(surface.program, "uResolution");
|
|
2807
|
-
if (resolution) {
|
|
2808
|
-
gl.uniform2f(resolution, width, height);
|
|
2841
|
+
|
|
2842
|
+
// src/runtime/viewer/shaders/backdrop.ts
|
|
2843
|
+
var MIN_BACKDROP_DENSITY = 2.5;
|
|
2844
|
+
var MAX_BACKDROP_PIXELS = 4096;
|
|
2845
|
+
var TRANSPARENT = /^rgba?(s*d+,s*d+,s*d+,s*0s*)$|^transparent$/;
|
|
2846
|
+
function hostBackground(svg) {
|
|
2847
|
+
const view = svg.ownerDocument.defaultView;
|
|
2848
|
+
for (let element = svg.parentElement; element && view; element = element.parentElement) {
|
|
2849
|
+
const color2 = view.getComputedStyle(element).backgroundColor;
|
|
2850
|
+
if (color2 && !TRANSPARENT.test(color2.trim())) {
|
|
2851
|
+
return color2;
|
|
2852
|
+
}
|
|
2809
2853
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2854
|
+
return void 0;
|
|
2855
|
+
}
|
|
2856
|
+
function backdropClone(svg, owner, width, height) {
|
|
2857
|
+
const clone = svg.cloneNode(true);
|
|
2858
|
+
const ownerIndex = [...svg.children].indexOf(owner);
|
|
2859
|
+
if (ownerIndex >= 0) {
|
|
2860
|
+
while (clone.children.length > ownerIndex) {
|
|
2861
|
+
clone.lastElementChild?.remove();
|
|
2818
2862
|
}
|
|
2819
|
-
uniform2f(surface, "uBackdropOrigin", surface.backdropOrigin);
|
|
2820
|
-
uniform2f(surface, "uBackdropScale", surface.backdropScale);
|
|
2821
2863
|
}
|
|
2822
|
-
for (const
|
|
2823
|
-
|
|
2864
|
+
for (const surface of clone.querySelectorAll("foreignObject[data-sf-shader]")) {
|
|
2865
|
+
surface.remove();
|
|
2824
2866
|
}
|
|
2825
|
-
|
|
2826
|
-
|
|
2867
|
+
const background = hostBackground(svg);
|
|
2868
|
+
if (background) {
|
|
2869
|
+
const { x, y, width: viewWidth, height: viewHeight } = svg.viewBox.baseVal;
|
|
2870
|
+
const fill = svg.ownerDocument.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
2871
|
+
fill.setAttribute("x", String(x));
|
|
2872
|
+
fill.setAttribute("y", String(y));
|
|
2873
|
+
fill.setAttribute("width", String(viewWidth));
|
|
2874
|
+
fill.setAttribute("height", String(viewHeight));
|
|
2875
|
+
fill.setAttribute("fill", background);
|
|
2876
|
+
clone.insertBefore(fill, clone.firstChild);
|
|
2827
2877
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
2878
|
+
clone.setAttribute("width", String(width));
|
|
2879
|
+
clone.setAttribute("height", String(height));
|
|
2880
|
+
clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
2881
|
+
return clone;
|
|
2833
2882
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
const
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
}
|
|
2852
|
-
};
|
|
2883
|
+
function captureShaderBackdrop(svg, owner) {
|
|
2884
|
+
const density = Math.max(globalThis.devicePixelRatio || 1, MIN_BACKDROP_DENSITY);
|
|
2885
|
+
const scale = Math.min(density, MAX_BACKDROP_PIXELS / Math.max(1, Math.max(svg.clientWidth, svg.clientHeight)));
|
|
2886
|
+
const width = Math.max(1, Math.round(svg.clientWidth * scale));
|
|
2887
|
+
const height = Math.max(1, Math.round(svg.clientHeight * scale));
|
|
2888
|
+
const view = svg.ownerDocument.defaultView;
|
|
2889
|
+
if (!view) {
|
|
2890
|
+
return Promise.resolve(void 0);
|
|
2891
|
+
}
|
|
2892
|
+
const markup = new XMLSerializer().serializeToString(backdropClone(svg, owner, width, height));
|
|
2893
|
+
const image = svg.ownerDocument.createElement("img");
|
|
2894
|
+
const source = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;
|
|
2895
|
+
return new Promise((resolve) => {
|
|
2896
|
+
image.onload = () => resolve({ image, width, height });
|
|
2897
|
+
image.onerror = () => resolve(void 0);
|
|
2898
|
+
image.src = source;
|
|
2899
|
+
});
|
|
2853
2900
|
}
|
|
2854
2901
|
|
|
2855
|
-
// src/runtime/viewer/shaders/
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
return surface.canvas.toDataURL("image/png");
|
|
2867
|
-
} catch {
|
|
2868
|
-
return void 0;
|
|
2869
|
-
}
|
|
2870
|
-
});
|
|
2902
|
+
// src/runtime/viewer/shaders/uniforms.ts
|
|
2903
|
+
function color(value, fallback) {
|
|
2904
|
+
if (typeof value !== "string") {
|
|
2905
|
+
return fallback;
|
|
2906
|
+
}
|
|
2907
|
+
const match = /^#([0-9a-f]{6})$/i.exec(value);
|
|
2908
|
+
if (!match) {
|
|
2909
|
+
return fallback;
|
|
2910
|
+
}
|
|
2911
|
+
const integer = Number.parseInt(match[1], 16);
|
|
2912
|
+
return [(integer >> 16 & 255) / 255, (integer >> 8 & 255) / 255, (integer & 255) / 255];
|
|
2871
2913
|
}
|
|
2872
|
-
function
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
surface.owner.setAttribute("data-sf-shader-params", JSON.stringify(surface.parameters));
|
|
2880
|
-
renderSurface(surface, seconds);
|
|
2881
|
-
changed = true;
|
|
2914
|
+
function number(value, fallback) {
|
|
2915
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
2916
|
+
}
|
|
2917
|
+
function uniform1f(surface, name, value) {
|
|
2918
|
+
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2919
|
+
if (location) {
|
|
2920
|
+
surface.gl.uniform1f(location, value);
|
|
2882
2921
|
}
|
|
2883
|
-
return changed;
|
|
2884
2922
|
}
|
|
2885
|
-
function
|
|
2886
|
-
|
|
2887
|
-
|
|
2923
|
+
function uniform3f(surface, name, value) {
|
|
2924
|
+
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2925
|
+
if (location) {
|
|
2926
|
+
surface.gl.uniform3f(location, ...value);
|
|
2888
2927
|
}
|
|
2889
|
-
const mutations = new view.MutationObserver(onChange);
|
|
2890
|
-
mutations.observe(svg, { attributes: true, attributeFilter: ["viewBox"] });
|
|
2891
|
-
const sizes = view.ResizeObserver ? new view.ResizeObserver(onChange) : void 0;
|
|
2892
|
-
sizes?.observe(svg);
|
|
2893
|
-
return () => {
|
|
2894
|
-
mutations.disconnect();
|
|
2895
|
-
sizes?.disconnect();
|
|
2896
|
-
};
|
|
2897
2928
|
}
|
|
2898
|
-
function
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
}
|
|
2911
|
-
|
|
2912
|
-
};
|
|
2913
|
-
const stop = () => {
|
|
2914
|
-
if (frame !== void 0) {
|
|
2915
|
-
view?.cancelAnimationFrame(frame);
|
|
2916
|
-
frame = void 0;
|
|
2917
|
-
}
|
|
2918
|
-
for (const surface of surfaces) {
|
|
2919
|
-
releaseSurface(surface);
|
|
2920
|
-
}
|
|
2921
|
-
surfaces = [];
|
|
2929
|
+
function uniform2f(surface, name, value) {
|
|
2930
|
+
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2931
|
+
if (location) {
|
|
2932
|
+
surface.gl.uniform2f(location, ...value);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
function uniformName(parameter) {
|
|
2936
|
+
return `u${parameter.charAt(0).toUpperCase()}${parameter.slice(1)}`;
|
|
2937
|
+
}
|
|
2938
|
+
function enumParameter(name, value) {
|
|
2939
|
+
const values = {
|
|
2940
|
+
direction: { left: 0, right: 1, top: 2, bottom: 3 },
|
|
2941
|
+
orientation: { vertical: 0, horizontal: 1 },
|
|
2942
|
+
axis: { vertical: 0, horizontal: 1 }
|
|
2922
2943
|
};
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2944
|
+
return values[name]?.[value];
|
|
2945
|
+
}
|
|
2946
|
+
function applyParameters(surface, elapsed) {
|
|
2947
|
+
for (const [key, value] of Object.entries(surface.parameters)) {
|
|
2948
|
+
const name = uniformName(key);
|
|
2949
|
+
if (typeof value === "number") {
|
|
2950
|
+
const lag = surface.parameters[`${key}Lag`];
|
|
2951
|
+
if (typeof lag === "number" && lag > 0) {
|
|
2952
|
+
const current = surface.smoothed.get(key) ?? value;
|
|
2953
|
+
const next = current + (value - current) * (1 - Math.exp(-elapsed / lag));
|
|
2954
|
+
surface.smoothed.set(key, next);
|
|
2955
|
+
uniform1f(surface, name, next);
|
|
2926
2956
|
continue;
|
|
2927
2957
|
}
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
applyBackdrop(surface, backdrop);
|
|
2931
|
-
}
|
|
2932
|
-
});
|
|
2933
|
-
}
|
|
2934
|
-
};
|
|
2935
|
-
const startFrames = () => {
|
|
2936
|
-
if (!view?.requestAnimationFrame) {
|
|
2937
|
-
for (const surface of surfaces) {
|
|
2938
|
-
renderSurface(surface, 0);
|
|
2939
|
-
}
|
|
2940
|
-
return;
|
|
2958
|
+
uniform1f(surface, name, value);
|
|
2959
|
+
continue;
|
|
2941
2960
|
}
|
|
2942
|
-
if (
|
|
2943
|
-
|
|
2944
|
-
|
|
2961
|
+
if (typeof value === "boolean") {
|
|
2962
|
+
const location = surface.gl.getUniformLocation(surface.program, name);
|
|
2963
|
+
if (location) {
|
|
2964
|
+
surface.gl.uniform1i(location, value ? 1 : 0);
|
|
2945
2965
|
}
|
|
2966
|
+
continue;
|
|
2946
2967
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
const generation = ++backdropGeneration;
|
|
2952
|
-
surfaces = [...svg.querySelectorAll("canvas[data-sf-shader-canvas]")].flatMap((canvas) => {
|
|
2953
|
-
const surface = createSurface(canvas);
|
|
2954
|
-
return surface ? [surface] : [];
|
|
2955
|
-
});
|
|
2956
|
-
captureBackdrops(generation);
|
|
2957
|
-
if (surfaces.length > 0) {
|
|
2958
|
-
startFrames();
|
|
2959
|
-
}
|
|
2960
|
-
};
|
|
2961
|
-
const scheduleRecapture = () => {
|
|
2962
|
-
if (recapture !== void 0) {
|
|
2963
|
-
view?.clearTimeout(recapture);
|
|
2968
|
+
const enumValue = enumParameter(key, value);
|
|
2969
|
+
if (enumValue !== void 0) {
|
|
2970
|
+
uniform1f(surface, name, enumValue);
|
|
2971
|
+
continue;
|
|
2964
2972
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
captureBackdrops(backdropGeneration);
|
|
2968
|
-
}, RECAPTURE_DELAY_MS);
|
|
2969
|
-
};
|
|
2970
|
-
const unwatch = watchSvgChanges(svg, view, scheduleRecapture);
|
|
2971
|
-
refresh();
|
|
2972
|
-
const destroy = () => {
|
|
2973
|
-
backdropGeneration += 1;
|
|
2974
|
-
unwatch();
|
|
2975
|
-
if (recapture !== void 0) {
|
|
2976
|
-
view?.clearTimeout(recapture);
|
|
2973
|
+
if (/^#[0-9a-f]{6}$/i.test(value)) {
|
|
2974
|
+
uniform3f(surface, name, color(value, [0, 0, 0]));
|
|
2977
2975
|
}
|
|
2978
|
-
|
|
2979
|
-
};
|
|
2980
|
-
return {
|
|
2981
|
-
capture: () => capturePngs(svg, surfaces, clock.now()),
|
|
2982
|
-
setParameters: (ownerId, parameters3) => updateParameters(surfaces, ownerId, parameters3, clock.now()),
|
|
2983
|
-
setPaused: clock.setPaused,
|
|
2984
|
-
refresh,
|
|
2985
|
-
destroy
|
|
2986
|
-
};
|
|
2976
|
+
}
|
|
2987
2977
|
}
|
|
2988
2978
|
|
|
2989
|
-
// src/runtime/viewer/
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2979
|
+
// src/runtime/viewer/shaders/webgl.ts
|
|
2980
|
+
var VERTEX_SOURCE = `
|
|
2981
|
+
attribute vec2 aPosition;
|
|
2982
|
+
varying vec2 vUv;
|
|
2983
|
+
|
|
2984
|
+
void main() {
|
|
2985
|
+
vUv = aPosition * 0.5 + 0.5;
|
|
2986
|
+
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
2996
2987
|
}
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
2988
|
+
`;
|
|
2989
|
+
function compile(gl, type, source) {
|
|
2990
|
+
const shader = gl.createShader(type);
|
|
2991
|
+
if (!shader) {
|
|
2992
|
+
return void 0;
|
|
3001
2993
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2994
|
+
gl.shaderSource(shader, source);
|
|
2995
|
+
gl.compileShader(shader);
|
|
2996
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
2997
|
+
gl.deleteShader(shader);
|
|
2998
|
+
return void 0;
|
|
3007
2999
|
}
|
|
3000
|
+
return shader;
|
|
3008
3001
|
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
position: "absolute",
|
|
3021
|
-
inset: "0",
|
|
3022
|
-
display: "grid",
|
|
3023
|
-
placeItems: "center",
|
|
3024
|
-
color: theme.color,
|
|
3025
|
-
fontWeight: theme.fontWeight,
|
|
3026
|
-
lineHeight: "1"
|
|
3027
|
-
});
|
|
3028
|
-
return digit;
|
|
3029
|
-
}
|
|
3030
|
-
function createDigitCell(document, character, theme) {
|
|
3031
|
-
const cell = document.createElementNS(HTML_NAMESPACE, "span");
|
|
3032
|
-
cell.setAttribute("data-sf-rolling-digit", "true");
|
|
3033
|
-
if (theme.variant === "plain") {
|
|
3034
|
-
setStyles(cell, {
|
|
3035
|
-
position: "relative",
|
|
3036
|
-
display: "inline-block",
|
|
3037
|
-
width: "0.62em",
|
|
3038
|
-
height: "1.1em",
|
|
3039
|
-
overflow: "hidden"
|
|
3040
|
-
});
|
|
3041
|
-
cell.appendChild(createDigit(document, character, theme));
|
|
3042
|
-
return cell;
|
|
3002
|
+
function linkProgram(gl, fragmentSource21) {
|
|
3003
|
+
const vertex = compile(gl, gl.VERTEX_SHADER, VERTEX_SOURCE);
|
|
3004
|
+
const fragment = compile(gl, gl.FRAGMENT_SHADER, fragmentSource21);
|
|
3005
|
+
if (!vertex || !fragment) {
|
|
3006
|
+
if (vertex) {
|
|
3007
|
+
gl.deleteShader(vertex);
|
|
3008
|
+
}
|
|
3009
|
+
if (fragment) {
|
|
3010
|
+
gl.deleteShader(fragment);
|
|
3011
|
+
}
|
|
3012
|
+
return void 0;
|
|
3043
3013
|
}
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
left: "0",
|
|
3061
|
-
right: "0",
|
|
3062
|
-
top: "50%",
|
|
3063
|
-
height: "1px",
|
|
3064
|
-
background: theme.divider,
|
|
3065
|
-
pointerEvents: "none"
|
|
3066
|
-
});
|
|
3067
|
-
cell.appendChild(divider);
|
|
3068
|
-
return cell;
|
|
3014
|
+
const program = gl.createProgram();
|
|
3015
|
+
if (!program) {
|
|
3016
|
+
gl.deleteShader(vertex);
|
|
3017
|
+
gl.deleteShader(fragment);
|
|
3018
|
+
return void 0;
|
|
3019
|
+
}
|
|
3020
|
+
gl.attachShader(program, vertex);
|
|
3021
|
+
gl.attachShader(program, fragment);
|
|
3022
|
+
gl.linkProgram(program);
|
|
3023
|
+
gl.deleteShader(vertex);
|
|
3024
|
+
gl.deleteShader(fragment);
|
|
3025
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
3026
|
+
gl.deleteProgram(program);
|
|
3027
|
+
return void 0;
|
|
3028
|
+
}
|
|
3029
|
+
return program;
|
|
3069
3030
|
}
|
|
3070
|
-
function
|
|
3071
|
-
|
|
3072
|
-
|
|
3031
|
+
function transparentTexture(gl) {
|
|
3032
|
+
const texture = gl.createTexture();
|
|
3033
|
+
if (!texture) {
|
|
3034
|
+
return void 0;
|
|
3073
3035
|
}
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3036
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
3037
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
3038
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
3039
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
3040
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
3041
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
|
|
3042
|
+
return texture;
|
|
3079
3043
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
const incoming = animateDigit(next, [hidden, shown], duration);
|
|
3089
|
-
const outgoing = previous ? animateDigit(previous, [shown, hidden], duration) : null;
|
|
3090
|
-
const finish = () => {
|
|
3091
|
-
previous?.remove();
|
|
3092
|
-
next.style.opacity = "1";
|
|
3093
|
-
};
|
|
3094
|
-
if (incoming) {
|
|
3095
|
-
incoming.finished.then(finish, finish);
|
|
3096
|
-
} else {
|
|
3097
|
-
outgoing?.cancel();
|
|
3098
|
-
finish();
|
|
3044
|
+
|
|
3045
|
+
// src/runtime/viewer/shaders/createSurface.ts
|
|
3046
|
+
var FULL_SCREEN_QUAD = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);
|
|
3047
|
+
function parametersOf(owner) {
|
|
3048
|
+
try {
|
|
3049
|
+
return JSON.parse(owner.getAttribute("data-sf-shader-params") ?? "{}");
|
|
3050
|
+
} catch {
|
|
3051
|
+
return {};
|
|
3099
3052
|
}
|
|
3100
3053
|
}
|
|
3101
|
-
function
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
return;
|
|
3054
|
+
function bindFullScreenQuad(gl, program) {
|
|
3055
|
+
const buffer = gl.createBuffer();
|
|
3056
|
+
if (!buffer) {
|
|
3057
|
+
return void 0;
|
|
3105
3058
|
}
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
const
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
const incoming = animateDigit(
|
|
3113
|
-
next,
|
|
3114
|
-
[
|
|
3115
|
-
{ transform: "translateY(100%)", opacity: 0.25 },
|
|
3116
|
-
{ transform: "translateY(0)", opacity: 1 }
|
|
3117
|
-
],
|
|
3118
|
-
duration
|
|
3119
|
-
);
|
|
3120
|
-
const outgoing = previous ? animateDigit(
|
|
3121
|
-
previous,
|
|
3122
|
-
[
|
|
3123
|
-
{ transform: "translateY(0)", opacity: 1 },
|
|
3124
|
-
{ transform: "translateY(-100%)", opacity: 0.25 }
|
|
3125
|
-
],
|
|
3126
|
-
duration
|
|
3127
|
-
) : null;
|
|
3128
|
-
const finish = () => {
|
|
3129
|
-
previous?.remove();
|
|
3130
|
-
next.style.transform = "translateY(0)";
|
|
3131
|
-
next.style.opacity = "1";
|
|
3132
|
-
};
|
|
3133
|
-
if (incoming) {
|
|
3134
|
-
incoming.finished.then(finish, finish);
|
|
3135
|
-
} else {
|
|
3136
|
-
outgoing?.cancel();
|
|
3137
|
-
finish();
|
|
3059
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
3060
|
+
gl.bufferData(gl.ARRAY_BUFFER, FULL_SCREEN_QUAD, gl.STATIC_DRAW);
|
|
3061
|
+
const position = gl.getAttribLocation(program, "aPosition");
|
|
3062
|
+
if (position < 0) {
|
|
3063
|
+
gl.deleteBuffer(buffer);
|
|
3064
|
+
return void 0;
|
|
3138
3065
|
}
|
|
3066
|
+
gl.enableVertexAttribArray(position);
|
|
3067
|
+
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
|
3068
|
+
return buffer;
|
|
3139
3069
|
}
|
|
3140
|
-
function
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
return;
|
|
3070
|
+
function findBaseGeometry(owner, definition) {
|
|
3071
|
+
const ownerId = owner.getAttribute("data-sf-id");
|
|
3072
|
+
if (!definition.replacesBaseFill || !ownerId) {
|
|
3073
|
+
return void 0;
|
|
3145
3074
|
}
|
|
3146
|
-
const
|
|
3147
|
-
|
|
3148
|
-
if (previousValue[index] !== character) {
|
|
3149
|
-
replaceDigit(cells[index], character, theme, duration);
|
|
3150
|
-
}
|
|
3151
|
-
});
|
|
3152
|
-
digits.setAttribute("aria-label", nextValue);
|
|
3153
|
-
}
|
|
3154
|
-
|
|
3155
|
-
// src/runtime/viewer/widgets/documentWidgets.ts
|
|
3156
|
-
function findRollingNumber(svg, widgetId) {
|
|
3157
|
-
return [...svg.querySelectorAll('foreignObject[data-sf-widget="rollingNumber"]')].find(
|
|
3158
|
-
(surface) => surface.getAttribute("data-sf-id") === widgetId
|
|
3159
|
-
);
|
|
3075
|
+
const candidates = [...owner.closest("svg")?.querySelectorAll('[data-sf-primary="true"]') ?? []];
|
|
3076
|
+
return candidates.find((element) => element !== owner && element.getAttribute("data-sf-id") === ownerId);
|
|
3160
3077
|
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3078
|
+
function createSurface(canvas) {
|
|
3079
|
+
const owner = canvas.closest("[data-sf-shader]");
|
|
3080
|
+
const name = owner?.getAttribute("data-sf-shader");
|
|
3081
|
+
const definition = name ? shaderProgram(name) : void 0;
|
|
3082
|
+
const gl = canvas.getContext("webgl", { alpha: true, antialias: true, premultipliedAlpha: true });
|
|
3083
|
+
if (!owner || !definition || !gl) {
|
|
3084
|
+
return void 0;
|
|
3085
|
+
}
|
|
3086
|
+
const program = linkProgram(gl, definition.fragmentSource);
|
|
3087
|
+
if (!program) {
|
|
3088
|
+
return void 0;
|
|
3089
|
+
}
|
|
3090
|
+
gl.useProgram(program);
|
|
3091
|
+
const buffer = bindFullScreenQuad(gl, program);
|
|
3092
|
+
if (!buffer) {
|
|
3093
|
+
gl.deleteProgram(program);
|
|
3094
|
+
return void 0;
|
|
3095
|
+
}
|
|
3096
|
+
const usesBackdrop = definition.usesBackdrop === true;
|
|
3097
|
+
const baseGeometry = findBaseGeometry(owner, definition);
|
|
3098
|
+
const baseFill = baseGeometry?.getAttribute("fill");
|
|
3099
|
+
baseGeometry?.setAttribute("fill", "none");
|
|
3100
|
+
return {
|
|
3101
|
+
owner,
|
|
3102
|
+
canvas,
|
|
3103
|
+
gl,
|
|
3104
|
+
program,
|
|
3105
|
+
buffer,
|
|
3106
|
+
parameters: parametersOf(owner),
|
|
3107
|
+
smoothed: /* @__PURE__ */ new Map(),
|
|
3108
|
+
backdropTexture: usesBackdrop ? transparentTexture(gl) : void 0,
|
|
3109
|
+
backdropOrigin: [0, 0],
|
|
3110
|
+
backdropScale: [1, 1],
|
|
3111
|
+
usesBackdrop,
|
|
3112
|
+
shapeColor: color(owner.getAttribute("data-sf-shader-fill") ?? void 0, [1, 1, 1]),
|
|
3113
|
+
baseGeometry,
|
|
3114
|
+
baseFill
|
|
3115
|
+
};
|
|
3164
3116
|
}
|
|
3165
|
-
function
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
return chunkDDCTNLLD_cjs.DEFAULT_ROLLING_NUMBER_STYLE;
|
|
3117
|
+
function releaseSurface(surface) {
|
|
3118
|
+
if (surface.backdropTexture) {
|
|
3119
|
+
surface.gl.deleteTexture(surface.backdropTexture);
|
|
3169
3120
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
return
|
|
3121
|
+
surface.gl.deleteBuffer(surface.buffer);
|
|
3122
|
+
surface.gl.deleteProgram(surface.program);
|
|
3123
|
+
if (!surface.baseGeometry) {
|
|
3124
|
+
return;
|
|
3125
|
+
}
|
|
3126
|
+
if (surface.baseFill === null || surface.baseFill === void 0) {
|
|
3127
|
+
surface.baseGeometry.removeAttribute("fill");
|
|
3128
|
+
} else {
|
|
3129
|
+
surface.baseGeometry.setAttribute("fill", surface.baseFill);
|
|
3174
3130
|
}
|
|
3175
3131
|
}
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3132
|
+
|
|
3133
|
+
// src/runtime/viewer/shaders/renderSurface.ts
|
|
3134
|
+
function syncBackdropBounds(surface) {
|
|
3135
|
+
const svg = surface.canvas.closest("svg");
|
|
3136
|
+
if (!svg) {
|
|
3137
|
+
return;
|
|
3179
3138
|
}
|
|
3180
|
-
const
|
|
3181
|
-
|
|
3139
|
+
const svgBounds = svg.getBoundingClientRect();
|
|
3140
|
+
const surfaceBounds = surface.canvas.getBoundingClientRect();
|
|
3141
|
+
if (svgBounds.width <= 0 || svgBounds.height <= 0) {
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
surface.backdropOrigin = [
|
|
3145
|
+
(surfaceBounds.left - svgBounds.left) / svgBounds.width,
|
|
3146
|
+
(svgBounds.bottom - surfaceBounds.bottom) / svgBounds.height
|
|
3147
|
+
];
|
|
3148
|
+
surface.backdropScale = [surfaceBounds.width / svgBounds.width, surfaceBounds.height / svgBounds.height];
|
|
3182
3149
|
}
|
|
3183
|
-
function
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
return 420;
|
|
3150
|
+
function applyBackdrop(surface, backdrop) {
|
|
3151
|
+
if (!surface.backdropTexture) {
|
|
3152
|
+
return;
|
|
3187
3153
|
}
|
|
3188
|
-
|
|
3189
|
-
|
|
3154
|
+
syncBackdropBounds(surface);
|
|
3155
|
+
const { gl } = surface;
|
|
3156
|
+
gl.bindTexture(gl.TEXTURE_2D, surface.backdropTexture);
|
|
3157
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
|
|
3158
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, backdrop.image);
|
|
3190
3159
|
}
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3160
|
+
var MAX_SURFACE_PIXELS = 2560;
|
|
3161
|
+
function renderSurface(surface, seconds) {
|
|
3162
|
+
const { canvas, gl, parameters: parameters3 } = surface;
|
|
3163
|
+
const shown = canvas.getBoundingClientRect();
|
|
3164
|
+
const density = Math.min(globalThis.devicePixelRatio || 1, 3);
|
|
3165
|
+
const fit = Math.min(1, MAX_SURFACE_PIXELS / Math.max(1, shown.width * density, shown.height * density));
|
|
3166
|
+
const width = Math.max(1, Math.round((shown.width || canvas.clientWidth) * density * fit));
|
|
3167
|
+
const height = Math.max(1, Math.round((shown.height || canvas.clientHeight) * density * fit));
|
|
3168
|
+
if (canvas.width !== width || canvas.height !== height) {
|
|
3169
|
+
canvas.width = width;
|
|
3170
|
+
canvas.height = height;
|
|
3195
3171
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3172
|
+
gl.viewport(0, 0, width, height);
|
|
3173
|
+
gl.clearColor(0, 0, 0, 0);
|
|
3174
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
3175
|
+
gl.useProgram(surface.program);
|
|
3176
|
+
const resolution = gl.getUniformLocation(surface.program, "uResolution");
|
|
3177
|
+
if (resolution) {
|
|
3178
|
+
gl.uniform2f(resolution, width, height);
|
|
3200
3179
|
}
|
|
3201
|
-
|
|
3202
|
-
surface.
|
|
3203
|
-
|
|
3180
|
+
uniform1f(surface, "uTime", seconds);
|
|
3181
|
+
if (surface.backdropTexture) {
|
|
3182
|
+
syncBackdropBounds(surface);
|
|
3183
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
3184
|
+
gl.bindTexture(gl.TEXTURE_2D, surface.backdropTexture);
|
|
3185
|
+
const sampler = gl.getUniformLocation(surface.program, "uBackdrop");
|
|
3186
|
+
if (sampler) {
|
|
3187
|
+
gl.uniform1i(sampler, 0);
|
|
3188
|
+
}
|
|
3189
|
+
uniform2f(surface, "uBackdropOrigin", surface.backdropOrigin);
|
|
3190
|
+
uniform2f(surface, "uBackdropScale", surface.backdropScale);
|
|
3191
|
+
}
|
|
3192
|
+
for (const [key, fallback] of Object.entries(SHADER_DEFAULTS.numbers)) {
|
|
3193
|
+
uniform1f(surface, uniformName(key), number(parameters3[key], fallback));
|
|
3194
|
+
}
|
|
3195
|
+
for (const [key, fallback] of Object.entries(SHADER_DEFAULTS.colors)) {
|
|
3196
|
+
uniform3f(surface, uniformName(key), color(parameters3[key], [...fallback]));
|
|
3197
|
+
}
|
|
3198
|
+
uniform3f(surface, "uShapeColor", surface.shapeColor);
|
|
3199
|
+
const elapsed = surface.lastSeconds === void 0 ? 0 : Math.max(0, Math.min(seconds - surface.lastSeconds, 0.1));
|
|
3200
|
+
surface.lastSeconds = seconds;
|
|
3201
|
+
applyParameters(surface, elapsed);
|
|
3202
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
3204
3203
|
}
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3204
|
+
|
|
3205
|
+
// src/runtime/viewer/shaders/surfaceClock.ts
|
|
3206
|
+
function createSurfaceClock(view) {
|
|
3207
|
+
let pausedSince = null;
|
|
3208
|
+
let spentPaused = 0;
|
|
3209
|
+
const real = () => (view?.performance.now() ?? 0) / 1e3;
|
|
3209
3210
|
return {
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
if (
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
const now = Date.now();
|
|
3220
|
-
const wait = (lastApplied.get(widgetId) ?? 0) + FADE_INTERVAL - now;
|
|
3221
|
-
if (wait <= 0) {
|
|
3222
|
-
lastApplied.set(widgetId, now);
|
|
3223
|
-
return setRollingNumber(surface, value, true);
|
|
3224
|
-
}
|
|
3225
|
-
if (!pending.has(widgetId)) {
|
|
3226
|
-
pending.set(
|
|
3227
|
-
widgetId,
|
|
3228
|
-
setTimeout(() => {
|
|
3229
|
-
pending.delete(widgetId);
|
|
3230
|
-
lastApplied.set(widgetId, Date.now());
|
|
3231
|
-
const current = findRollingNumber(svg, widgetId);
|
|
3232
|
-
const latest = valueOverrides.get(widgetId);
|
|
3233
|
-
if (current && latest !== void 0) {
|
|
3234
|
-
setRollingNumber(current, latest, true);
|
|
3235
|
-
}
|
|
3236
|
-
}, wait)
|
|
3237
|
-
);
|
|
3238
|
-
}
|
|
3239
|
-
return true;
|
|
3240
|
-
},
|
|
3241
|
-
refresh() {
|
|
3242
|
-
for (const [widgetId, value] of valueOverrides) {
|
|
3243
|
-
const surface = findRollingNumber(svg, widgetId);
|
|
3244
|
-
if (surface) {
|
|
3245
|
-
setRollingNumber(surface, value, false);
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3248
|
-
},
|
|
3249
|
-
clearValues() {
|
|
3250
|
-
for (const timer of pending.values()) {
|
|
3251
|
-
clearTimeout(timer);
|
|
3252
|
-
}
|
|
3253
|
-
pending.clear();
|
|
3254
|
-
valueOverrides.clear();
|
|
3255
|
-
},
|
|
3256
|
-
destroy() {
|
|
3257
|
-
for (const timer of pending.values()) {
|
|
3258
|
-
clearTimeout(timer);
|
|
3211
|
+
now: () => (pausedSince ?? real()) - spentPaused,
|
|
3212
|
+
paused: () => pausedSince !== null,
|
|
3213
|
+
spent: () => spentPaused,
|
|
3214
|
+
setPaused(paused) {
|
|
3215
|
+
if (paused && pausedSince === null) {
|
|
3216
|
+
pausedSince = real();
|
|
3217
|
+
} else if (!paused && pausedSince !== null) {
|
|
3218
|
+
spentPaused += real() - pausedSince;
|
|
3219
|
+
pausedSince = null;
|
|
3259
3220
|
}
|
|
3260
|
-
pending.clear();
|
|
3261
|
-
valueOverrides.clear();
|
|
3262
3221
|
}
|
|
3263
3222
|
};
|
|
3264
3223
|
}
|
|
3265
3224
|
|
|
3266
|
-
// src/runtime/viewer/
|
|
3267
|
-
var
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
}
|
|
3283
|
-
function rulerProgress(surface, value) {
|
|
3284
|
-
const params = parameters(surface);
|
|
3285
|
-
const min = Number(params.min) || 0;
|
|
3286
|
-
const max = Number.isFinite(Number(params.max)) && params.max !== void 0 ? Number(params.max) : 100;
|
|
3287
|
-
return clamp01(max === min ? 0 : (value - min) / (max - min));
|
|
3288
|
-
}
|
|
3289
|
-
function move(node, dx, dy) {
|
|
3290
|
-
const current = node.getAttribute("transform") ?? "";
|
|
3291
|
-
const base = current === written.get(node) ? bases.get(node) ?? "" : current;
|
|
3292
|
-
bases.set(node, base);
|
|
3293
|
-
const next = `translate(${dx} ${dy}) ${base}`.trim();
|
|
3294
|
-
written.set(node, next);
|
|
3295
|
-
node.setAttribute("transform", next);
|
|
3225
|
+
// src/runtime/viewer/shaders/surface.ts
|
|
3226
|
+
var RECAPTURE_DELAY_MS = 120;
|
|
3227
|
+
function capturePngs(svg, surfaces, seconds) {
|
|
3228
|
+
const surfaceByCanvas = new Map(surfaces.map((surface) => [surface.canvas, surface]));
|
|
3229
|
+
return [...svg.querySelectorAll("canvas[data-sf-shader-canvas]")].map((canvas) => {
|
|
3230
|
+
const surface = surfaceByCanvas.get(canvas);
|
|
3231
|
+
if (!surface) {
|
|
3232
|
+
return void 0;
|
|
3233
|
+
}
|
|
3234
|
+
try {
|
|
3235
|
+
renderSurface(surface, seconds);
|
|
3236
|
+
return surface.canvas.toDataURL("image/png");
|
|
3237
|
+
} catch {
|
|
3238
|
+
return void 0;
|
|
3239
|
+
}
|
|
3240
|
+
});
|
|
3296
3241
|
}
|
|
3297
|
-
function
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3242
|
+
function updateParameters(surfaces, ownerId, parameters3, seconds) {
|
|
3243
|
+
let changed = false;
|
|
3244
|
+
for (const surface of surfaces) {
|
|
3245
|
+
if (surface.owner.getAttribute("data-sf-id") !== ownerId) {
|
|
3246
|
+
continue;
|
|
3247
|
+
}
|
|
3248
|
+
Object.assign(surface.parameters, parameters3);
|
|
3249
|
+
surface.owner.setAttribute("data-sf-shader-params", JSON.stringify(surface.parameters));
|
|
3250
|
+
renderSurface(surface, seconds);
|
|
3251
|
+
changed = true;
|
|
3301
3252
|
}
|
|
3302
|
-
|
|
3303
|
-
return [number2 >> 16 & 255, number2 >> 8 & 255, number2 & 255];
|
|
3253
|
+
return changed;
|
|
3304
3254
|
}
|
|
3305
|
-
function
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
const rgb = hexToRgb(base);
|
|
3309
|
-
if (!rgb) {
|
|
3310
|
-
return;
|
|
3311
|
-
}
|
|
3312
|
-
const mixed = rgb.map((channel) => Math.round(channel + (255 - channel) * bump));
|
|
3313
|
-
const fill = `rgb(${mixed[0]}, ${mixed[1]}, ${mixed[2]})`;
|
|
3314
|
-
node.style.fill = fill;
|
|
3315
|
-
for (const child of node.querySelectorAll("tspan")) {
|
|
3316
|
-
child.style.fill = fill;
|
|
3255
|
+
function watchSvgChanges(svg, view, onChange) {
|
|
3256
|
+
if (!view) {
|
|
3257
|
+
return () => void 0;
|
|
3317
3258
|
}
|
|
3259
|
+
const mutations = new view.MutationObserver(onChange);
|
|
3260
|
+
mutations.observe(svg, { attributes: true, attributeFilter: ["viewBox"] });
|
|
3261
|
+
const sizes = view.ResizeObserver ? new view.ResizeObserver(onChange) : void 0;
|
|
3262
|
+
sizes?.observe(svg);
|
|
3263
|
+
return () => {
|
|
3264
|
+
mutations.disconnect();
|
|
3265
|
+
sizes?.disconnect();
|
|
3266
|
+
};
|
|
3318
3267
|
}
|
|
3319
|
-
function
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
const inset = positive2(params.inset, 0.05);
|
|
3331
|
-
const line = positive2(params.line, 0.7);
|
|
3332
|
-
const extent = horizontal ? width : height;
|
|
3333
|
-
const across = horizontal ? height : width;
|
|
3334
|
-
const along = inset + (1 - 2 * inset) * progress;
|
|
3335
|
-
const dent = params.dent === void 0 ? 1 : Number(params.dent);
|
|
3336
|
-
const depth = (dent < 0 ? 1 : dent) * 0.16 * across;
|
|
3337
|
-
const knobId = typeof params.knob === "string" ? params.knob : "";
|
|
3338
|
-
if (knobId) {
|
|
3339
|
-
const nodes = [...svg.querySelectorAll(`[data-sf-id="${CSS.escape(knobId)}"]`)];
|
|
3340
|
-
const primary = nodes.find((node) => node.hasAttribute("data-sf-primary"));
|
|
3341
|
-
if (primary?.getBBox) {
|
|
3342
|
-
move(primary, 0, 0);
|
|
3343
|
-
const box = primary.getBBox();
|
|
3344
|
-
const half = (horizontal ? box.height : box.width) / 2;
|
|
3345
|
-
radii.set(id, half / across);
|
|
3346
|
-
const gap = (params.gap === void 0 ? 0.04 : Number(params.gap)) * across;
|
|
3347
|
-
const side = line * across - depth + half + gap;
|
|
3348
|
-
const target = horizontal ? { x: x + width * along, y: y + side } : { x: x + side, y: y + height * (1 - along) };
|
|
3349
|
-
const dx = target.x - (box.x + box.width / 2);
|
|
3350
|
-
const dy = target.y - (box.y + box.height / 2);
|
|
3351
|
-
for (const node of nodes) {
|
|
3352
|
-
move(node, dx, dy);
|
|
3353
|
-
}
|
|
3268
|
+
function mountShaderSurfaces(svg) {
|
|
3269
|
+
let surfaces = [];
|
|
3270
|
+
let frame;
|
|
3271
|
+
let backdropGeneration = 0;
|
|
3272
|
+
let recapture;
|
|
3273
|
+
const view = svg.ownerDocument.defaultView;
|
|
3274
|
+
const clock = createSurfaceClock(view);
|
|
3275
|
+
const draw = (milliseconds) => {
|
|
3276
|
+
if (!clock.paused()) {
|
|
3277
|
+
for (const surface of surfaces) {
|
|
3278
|
+
renderSurface(surface, milliseconds / 1e3 - clock.spent());
|
|
3354
3279
|
}
|
|
3355
3280
|
}
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3281
|
+
frame = view?.requestAnimationFrame(draw);
|
|
3282
|
+
};
|
|
3283
|
+
const stop = () => {
|
|
3284
|
+
if (frame !== void 0) {
|
|
3285
|
+
view?.cancelAnimationFrame(frame);
|
|
3286
|
+
frame = void 0;
|
|
3287
|
+
}
|
|
3288
|
+
for (const surface of surfaces) {
|
|
3289
|
+
releaseSurface(surface);
|
|
3290
|
+
}
|
|
3291
|
+
surfaces = [];
|
|
3292
|
+
};
|
|
3293
|
+
const captureBackdrops = (generation) => {
|
|
3294
|
+
for (const surface of surfaces) {
|
|
3295
|
+
if (!surface.usesBackdrop) {
|
|
3365
3296
|
continue;
|
|
3366
3297
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3298
|
+
void captureShaderBackdrop(svg, surface.owner).then((backdrop) => {
|
|
3299
|
+
if (backdrop && generation === backdropGeneration) {
|
|
3300
|
+
applyBackdrop(surface, backdrop);
|
|
3301
|
+
}
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
const startFrames = () => {
|
|
3306
|
+
if (!view?.requestAnimationFrame) {
|
|
3307
|
+
for (const surface of surfaces) {
|
|
3308
|
+
renderSurface(surface, 0);
|
|
3309
|
+
}
|
|
3310
|
+
return;
|
|
3311
|
+
}
|
|
3312
|
+
if (clock.paused()) {
|
|
3313
|
+
for (const surface of surfaces) {
|
|
3314
|
+
renderSurface(surface, clock.now());
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
frame = view.requestAnimationFrame(draw);
|
|
3318
|
+
};
|
|
3319
|
+
const refresh = () => {
|
|
3320
|
+
stop();
|
|
3321
|
+
const generation = ++backdropGeneration;
|
|
3322
|
+
surfaces = [...svg.querySelectorAll("canvas[data-sf-shader-canvas]")].flatMap((canvas) => {
|
|
3323
|
+
const surface = createSurface(canvas);
|
|
3324
|
+
return surface ? [surface] : [];
|
|
3325
|
+
});
|
|
3326
|
+
captureBackdrops(generation);
|
|
3327
|
+
if (surfaces.length > 0) {
|
|
3328
|
+
startFrames();
|
|
3329
|
+
}
|
|
3330
|
+
};
|
|
3331
|
+
const scheduleRecapture = () => {
|
|
3332
|
+
if (recapture !== void 0) {
|
|
3333
|
+
view?.clearTimeout(recapture);
|
|
3334
|
+
}
|
|
3335
|
+
recapture = view?.setTimeout(() => {
|
|
3336
|
+
recapture = void 0;
|
|
3337
|
+
captureBackdrops(backdropGeneration);
|
|
3338
|
+
}, RECAPTURE_DELAY_MS);
|
|
3339
|
+
};
|
|
3340
|
+
const unwatch = watchSvgChanges(svg, view, scheduleRecapture);
|
|
3341
|
+
refresh();
|
|
3342
|
+
const destroy = () => {
|
|
3343
|
+
backdropGeneration += 1;
|
|
3344
|
+
unwatch();
|
|
3345
|
+
if (recapture !== void 0) {
|
|
3346
|
+
view?.clearTimeout(recapture);
|
|
3372
3347
|
}
|
|
3348
|
+
stop();
|
|
3349
|
+
};
|
|
3350
|
+
return {
|
|
3351
|
+
capture: () => capturePngs(svg, surfaces, clock.now()),
|
|
3352
|
+
setParameters: (ownerId, parameters3) => updateParameters(surfaces, ownerId, parameters3, clock.now()),
|
|
3353
|
+
setPaused: clock.setPaused,
|
|
3354
|
+
refresh,
|
|
3355
|
+
destroy
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// src/runtime/viewer/source.ts
|
|
3360
|
+
function renderViewerSource(next, defaultRenderOptions) {
|
|
3361
|
+
const svg = next.svg ?? (next.source != null ? chunkZMLQIMJK_cjs.render(next.source, { ...next.renderOptions ?? defaultRenderOptions, linkHitAreas: true }).svg : null);
|
|
3362
|
+
if (svg == null) {
|
|
3363
|
+
throw new Error("createViewer: provide either `source` (SFL) or `svg`.");
|
|
3364
|
+
}
|
|
3365
|
+
return svg;
|
|
3366
|
+
}
|
|
3367
|
+
function assertCreateViewerContract(svg) {
|
|
3368
|
+
const version = chunkL3VJXZFD_cjs.parseContractVersion(svg);
|
|
3369
|
+
if (!chunkL3VJXZFD_cjs.isContractCompatible(version)) {
|
|
3370
|
+
throw new Error(`createViewer: incompatible DOM contract (svg=${version}). Renderer and viewer versions differ.`);
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
function assertViewerUpdateContract(svg) {
|
|
3374
|
+
const version = chunkL3VJXZFD_cjs.parseContractVersion(svg);
|
|
3375
|
+
if (!chunkL3VJXZFD_cjs.isContractCompatible(version)) {
|
|
3376
|
+
throw new Error(`viewer.update: incompatible DOM contract (svg=${version}). Renderer and viewer versions differ.`);
|
|
3373
3377
|
}
|
|
3374
|
-
return radii;
|
|
3375
3378
|
}
|
|
3376
3379
|
|
|
3377
3380
|
// src/runtime/viewer/session.ts
|
|
@@ -3381,7 +3384,7 @@ var ViewerSession = class {
|
|
|
3381
3384
|
this.diagramId = diagramId;
|
|
3382
3385
|
this.display = mountDisplay(options.container, initialSvg);
|
|
3383
3386
|
this.shaderSurfaces = mountShaderSurfaces(this.display.svg);
|
|
3384
|
-
this.
|
|
3387
|
+
this.documentComponents = mountDocumentComponents(this.display.svg);
|
|
3385
3388
|
this.interaction = options.interactive ? bindInteraction(this.display, this.emitter, diagramId, { selectable: options.selectable }) : null;
|
|
3386
3389
|
this.placeKnobs();
|
|
3387
3390
|
}
|
|
@@ -3391,7 +3394,7 @@ var ViewerSession = class {
|
|
|
3391
3394
|
display;
|
|
3392
3395
|
interaction;
|
|
3393
3396
|
shaderSurfaces;
|
|
3394
|
-
|
|
3397
|
+
documentComponents;
|
|
3395
3398
|
shaderParameterOverrides = /* @__PURE__ */ new Map();
|
|
3396
3399
|
rulerProgressOverrides = /* @__PURE__ */ new Map();
|
|
3397
3400
|
placeKnobs() {
|
|
@@ -3430,22 +3433,25 @@ var ViewerSession = class {
|
|
|
3430
3433
|
this.shaderParameterOverrides.set(ownerId, merged);
|
|
3431
3434
|
return this.shaderSurfaces.setParameters(ownerId, parameters3);
|
|
3432
3435
|
}
|
|
3433
|
-
setWidgetValue(
|
|
3434
|
-
|
|
3436
|
+
setWidgetValue(componentId, value) {
|
|
3437
|
+
return this.setComponentValue(componentId, value);
|
|
3438
|
+
}
|
|
3439
|
+
setComponentValue(componentId, value) {
|
|
3440
|
+
if (this.documentComponents.setValue(componentId, value)) {
|
|
3435
3441
|
return true;
|
|
3436
3442
|
}
|
|
3437
3443
|
const ruler = [...this.svg.querySelectorAll('foreignObject[data-sf-shader="ruler"]')].find(
|
|
3438
|
-
(element) => element.getAttribute("data-sf-id") ===
|
|
3444
|
+
(element) => element.getAttribute("data-sf-id") === componentId
|
|
3439
3445
|
);
|
|
3440
3446
|
if (ruler) {
|
|
3441
3447
|
const progress = rulerProgress(ruler, Number(value));
|
|
3442
|
-
this.rulerProgressOverrides.set(
|
|
3443
|
-
const applied = this.setShaderParameters(
|
|
3448
|
+
this.rulerProgressOverrides.set(componentId, progress);
|
|
3449
|
+
const applied = this.setShaderParameters(componentId, { progress });
|
|
3444
3450
|
this.placeKnobs();
|
|
3445
3451
|
return applied;
|
|
3446
3452
|
}
|
|
3447
3453
|
const scale = [...this.svg.querySelectorAll('foreignObject[data-sf-shader="tickScale"]')].find(
|
|
3448
|
-
(element) => element.getAttribute("data-sf-id") ===
|
|
3454
|
+
(element) => element.getAttribute("data-sf-id") === componentId
|
|
3449
3455
|
);
|
|
3450
3456
|
if (!scale) {
|
|
3451
3457
|
return false;
|
|
@@ -3456,7 +3462,7 @@ var ViewerSession = class {
|
|
|
3456
3462
|
} catch {
|
|
3457
3463
|
max = 100;
|
|
3458
3464
|
}
|
|
3459
|
-
return this.setShaderParameters(
|
|
3465
|
+
return this.setShaderParameters(componentId, { progress: Math.min(1, Math.max(0, Number(value) / max)) });
|
|
3460
3466
|
}
|
|
3461
3467
|
setPaused(paused) {
|
|
3462
3468
|
this.shaderSurfaces.setPaused(paused);
|
|
@@ -3464,14 +3470,14 @@ var ViewerSession = class {
|
|
|
3464
3470
|
clearOverrides() {
|
|
3465
3471
|
this.shaderParameterOverrides.clear();
|
|
3466
3472
|
this.rulerProgressOverrides.clear();
|
|
3467
|
-
this.
|
|
3473
|
+
this.documentComponents.clearValues();
|
|
3468
3474
|
}
|
|
3469
3475
|
update(next) {
|
|
3470
3476
|
const svg = renderViewerSource(next, this.options.renderOptions);
|
|
3471
3477
|
assertViewerUpdateContract(svg);
|
|
3472
3478
|
const diff = this.display.updateContent(svg);
|
|
3473
3479
|
this.shaderSurfaces.refresh();
|
|
3474
|
-
this.
|
|
3480
|
+
this.documentComponents.refresh();
|
|
3475
3481
|
this.placeKnobs();
|
|
3476
3482
|
for (const [ownerId, parameters3] of this.shaderParameterOverrides) {
|
|
3477
3483
|
this.shaderSurfaces.setParameters(ownerId, parameters3);
|
|
@@ -3495,13 +3501,52 @@ var ViewerSession = class {
|
|
|
3495
3501
|
destroy() {
|
|
3496
3502
|
this.interaction?.destroy();
|
|
3497
3503
|
this.shaderSurfaces.destroy();
|
|
3498
|
-
this.
|
|
3504
|
+
this.documentComponents.destroy();
|
|
3499
3505
|
this.shaderParameterOverrides.clear();
|
|
3500
3506
|
this.display.destroy();
|
|
3501
3507
|
this.emitter.clear();
|
|
3502
3508
|
}
|
|
3503
3509
|
};
|
|
3504
3510
|
|
|
3511
|
+
// src/runtime/viewer/connectKeyboard.ts
|
|
3512
|
+
var ACTIVATION_KEYS = /* @__PURE__ */ new Set([" ", "Enter"]);
|
|
3513
|
+
function operatedId(runtime, target) {
|
|
3514
|
+
const node = target instanceof Element ? target.closest("[data-sf-primary][data-sf-id]") : null;
|
|
3515
|
+
const id = node?.getAttribute("data-sf-id") ?? null;
|
|
3516
|
+
return id && runtime.interactive.pressable.has(id) ? id : null;
|
|
3517
|
+
}
|
|
3518
|
+
function connectKeyboard(viewer, runtime, options = {}) {
|
|
3519
|
+
const focusChanged = (event, focused) => {
|
|
3520
|
+
const id = operatedId(runtime, event.target);
|
|
3521
|
+
if (id) {
|
|
3522
|
+
runtime.setElementState(id, { focused });
|
|
3523
|
+
}
|
|
3524
|
+
};
|
|
3525
|
+
const activate = (event) => {
|
|
3526
|
+
if (!ACTIVATION_KEYS.has(event.key) || event.repeat || options.enabled?.() === false) {
|
|
3527
|
+
return;
|
|
3528
|
+
}
|
|
3529
|
+
const id = operatedId(runtime, event.target);
|
|
3530
|
+
if (id) {
|
|
3531
|
+
event.preventDefault();
|
|
3532
|
+
runtime.activate(id);
|
|
3533
|
+
}
|
|
3534
|
+
};
|
|
3535
|
+
const listeners = [
|
|
3536
|
+
["focusin", (event) => focusChanged(event, true)],
|
|
3537
|
+
["focusout", (event) => focusChanged(event, false)],
|
|
3538
|
+
["keydown", activate]
|
|
3539
|
+
];
|
|
3540
|
+
for (const [type, listener] of listeners) {
|
|
3541
|
+
viewer.svg.addEventListener(type, listener);
|
|
3542
|
+
}
|
|
3543
|
+
return () => {
|
|
3544
|
+
for (const [type, listener] of listeners) {
|
|
3545
|
+
viewer.svg.removeEventListener(type, listener);
|
|
3546
|
+
}
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3505
3550
|
// src/runtime/viewer/connectInteraction.ts
|
|
3506
3551
|
var TAU = Math.PI * 2;
|
|
3507
3552
|
var LONGEST_TICK = 0.05;
|
|
@@ -3650,11 +3695,13 @@ function connectInteraction(viewer, runtime, options = {}) {
|
|
|
3650
3695
|
for (const [type, listener] of listeners) {
|
|
3651
3696
|
window.addEventListener(type, listener, true);
|
|
3652
3697
|
}
|
|
3698
|
+
const disconnectKeyboard = connectKeyboard(viewer, runtime, options);
|
|
3653
3699
|
const stopTicks = startTicks(runtime, options);
|
|
3654
3700
|
return () => {
|
|
3655
3701
|
for (const [type, listener] of listeners) {
|
|
3656
3702
|
window.removeEventListener(type, listener, true);
|
|
3657
3703
|
}
|
|
3704
|
+
disconnectKeyboard();
|
|
3658
3705
|
stopTicks();
|
|
3659
3706
|
if (session.active) {
|
|
3660
3707
|
runtime.release(session.active, false);
|
|
@@ -3680,5 +3727,5 @@ exports.connectInteraction = connectInteraction;
|
|
|
3680
3727
|
exports.createViewer = createViewer;
|
|
3681
3728
|
exports.registerShaderProgram = registerShaderProgram;
|
|
3682
3729
|
exports.shaderProgram = shaderProgram;
|
|
3683
|
-
//# sourceMappingURL=chunk-
|
|
3684
|
-
//# sourceMappingURL=chunk-
|
|
3730
|
+
//# sourceMappingURL=chunk-VK3T6O5Z.cjs.map
|
|
3731
|
+
//# sourceMappingURL=chunk-VK3T6O5Z.cjs.map
|