@markdy/renderer-dom 0.8.13 → 0.8.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +92 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ Web Animations API renderer for [MarkdyScript](../../docs/SYNTAX.md) scenes. Tra
|
|
|
11
11
|
- **Focused diagram visuals** — flowchart shapes, tree buses, state self-loops, sequence lifelines/messages, constellation orbits, group zones, and annotations
|
|
12
12
|
- **Semantic node cards** — compact SVG glyphs for browsers, services, gateways, queues, workers, databases, storage, CDN, security, platform, and more
|
|
13
13
|
- **Seek-safe** — manual `currentTime` control enables reliable `seek()` in any direction
|
|
14
|
-
- **Playback-rate controls** — set timeline speed to slow down or speed up diagrams without rebuilding animations
|
|
14
|
+
- **Playback-rate controls** — set normalized timeline speed to slow down or speed up diagrams without rebuilding animations
|
|
15
|
+
- **Interactive viewport** — opt into wheel zoom and drag pan while click-to-pause stays available
|
|
15
16
|
- **Semantic themes** — `paper`, `editorial`, `nebula`, `midnight`, `blueprint`, and `graphite`, with per-role node and edge colors
|
|
16
17
|
- **Single dependency** — only `@markdy/core`
|
|
17
18
|
|
|
@@ -73,7 +74,8 @@ diagram.destroy(); // clean up DOM + cancel animations
|
|
|
73
74
|
| `copyright` | `boolean` | `true` | Show a small "Powered by Markdy" badge below the animation |
|
|
74
75
|
| `progressBar` | `boolean` | `true` | Deprecated compatibility flag for the rainbow scene-boundary progress bar |
|
|
75
76
|
| `sceneBoundaryProgress` | `boolean` | `progressBar ?? true` | Preferred flag for the rainbow scene-boundary progress bar |
|
|
76
|
-
| `playbackRate` | `number` | `1` |
|
|
77
|
+
| `playbackRate` | `number` | `1` | Normalized timeline speed multiplier; `1` is Markdy's normal pace |
|
|
78
|
+
| `interactiveViewport` | `boolean` | `false` | Enable wheel zoom and drag pan on the rendered viewport |
|
|
77
79
|
| `onWarning` | `(warning: Diagnostic) => void` | `console.warn` | Called for each soft parse warning |
|
|
78
80
|
| `onTimeUpdate` | `(seconds: number, durationSeconds: number) => void` | — | Called whenever playback or seek changes the current time |
|
|
79
81
|
| `onPlayStateChange` | `(playing: boolean) => void` | — | Called when playback starts or pauses |
|
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,10 @@ interface DiagramOptions {
|
|
|
20
20
|
progressBar?: boolean;
|
|
21
21
|
/** Show rainbow progress around scene boundary. Defaults to true. */
|
|
22
22
|
sceneBoundaryProgress?: boolean;
|
|
23
|
-
/** Playback speed multiplier. Defaults to 1. */
|
|
23
|
+
/** Playback speed multiplier. Defaults to 1, where 1 is Markdy's normal pace. */
|
|
24
24
|
playbackRate?: number;
|
|
25
|
+
/** Enable wheel zoom and drag pan on the rendered viewport. Defaults to false. */
|
|
26
|
+
interactiveViewport?: boolean;
|
|
25
27
|
onWarning?: (warning: Diagnostic) => void;
|
|
26
28
|
onTimeUpdate?: (seconds: number, durationSeconds: number) => void;
|
|
27
29
|
onPlayStateChange?: (playing: boolean) => void;
|
package/dist/index.js
CHANGED
|
@@ -1810,6 +1810,12 @@ function applyThemeToScene(scene, theme) {
|
|
|
1810
1810
|
}
|
|
1811
1811
|
|
|
1812
1812
|
// src/diagram.ts
|
|
1813
|
+
var NORMAL_PLAYBACK_RATE = 4 / 5;
|
|
1814
|
+
var DEFAULT_PLAYBACK_RATE = 1;
|
|
1815
|
+
var MIN_VIEWPORT_ZOOM = 0.5;
|
|
1816
|
+
var MAX_VIEWPORT_ZOOM = 3;
|
|
1817
|
+
var VIEWPORT_ZOOM_STEP = 15e-4;
|
|
1818
|
+
var DRAG_CLICK_THRESHOLD_PX = 4;
|
|
1813
1819
|
function createBeatCaptionLayer(doc, beats) {
|
|
1814
1820
|
const layer = doc.createElement("div");
|
|
1815
1821
|
layer.className = "markdy-beat-caption-layer";
|
|
@@ -1856,7 +1862,8 @@ function createDiagram(opts) {
|
|
|
1856
1862
|
assets,
|
|
1857
1863
|
progressBar,
|
|
1858
1864
|
sceneBoundaryProgress,
|
|
1859
|
-
playbackRate: initialPlaybackRate =
|
|
1865
|
+
playbackRate: initialPlaybackRate = DEFAULT_PLAYBACK_RATE,
|
|
1866
|
+
interactiveViewport = false,
|
|
1860
1867
|
onWarning = (w) => console.warn(`[markdy] line ${w.line}: ${w.message}`),
|
|
1861
1868
|
onTimeUpdate,
|
|
1862
1869
|
onPlayStateChange
|
|
@@ -1923,6 +1930,15 @@ function createDiagram(opts) {
|
|
|
1923
1930
|
}
|
|
1924
1931
|
ensureSceneStyles(document);
|
|
1925
1932
|
ensureNodeStyles(document);
|
|
1933
|
+
const viewportTransform = document.createElement("div");
|
|
1934
|
+
viewportTransform.className = "markdy-viewport-transform";
|
|
1935
|
+
Object.assign(viewportTransform.style, {
|
|
1936
|
+
position: "absolute",
|
|
1937
|
+
inset: "0",
|
|
1938
|
+
transformOrigin: "0 0",
|
|
1939
|
+
willChange: interactiveViewport ? "transform" : "auto"
|
|
1940
|
+
});
|
|
1941
|
+
viewport.appendChild(viewportTransform);
|
|
1926
1942
|
const scene = document.createElement("div");
|
|
1927
1943
|
scene.className = "markdy-scene-root";
|
|
1928
1944
|
Object.assign(scene.style, {
|
|
@@ -1936,7 +1952,7 @@ function createDiagram(opts) {
|
|
|
1936
1952
|
transformOrigin: "0 0"
|
|
1937
1953
|
});
|
|
1938
1954
|
applyThemeToScene(scene, plan.theme);
|
|
1939
|
-
|
|
1955
|
+
viewportTransform.appendChild(scene);
|
|
1940
1956
|
const sceneContent = document.createElement("div");
|
|
1941
1957
|
sceneContent.className = "markdy-scene-content";
|
|
1942
1958
|
Object.assign(sceneContent.style, { position: "absolute", inset: "0" });
|
|
@@ -2042,16 +2058,75 @@ function createDiagram(opts) {
|
|
|
2042
2058
|
anim.currentTime = 0;
|
|
2043
2059
|
}
|
|
2044
2060
|
let sceneMs = 0;
|
|
2045
|
-
let playbackRate = Number.isFinite(initialPlaybackRate) && initialPlaybackRate > 0 ? initialPlaybackRate :
|
|
2061
|
+
let playbackRate = Number.isFinite(initialPlaybackRate) && initialPlaybackRate > 0 ? initialPlaybackRate : DEFAULT_PLAYBACK_RATE;
|
|
2046
2062
|
let lastRafTs = null;
|
|
2047
2063
|
let isPlaying = false;
|
|
2048
2064
|
let rafId = null;
|
|
2065
|
+
let viewportScale = 1;
|
|
2066
|
+
let viewportPanX = 0;
|
|
2067
|
+
let viewportPanY = 0;
|
|
2068
|
+
let activePointerId = null;
|
|
2069
|
+
let dragStartX = 0;
|
|
2070
|
+
let dragStartY = 0;
|
|
2071
|
+
let dragLastX = 0;
|
|
2072
|
+
let dragLastY = 0;
|
|
2073
|
+
let dragMoved = false;
|
|
2074
|
+
let suppressNextClick = false;
|
|
2075
|
+
function applyViewportTransform() {
|
|
2076
|
+
viewportTransform.style.transform = `translate(${viewportPanX}px, ${viewportPanY}px) scale(${viewportScale})`;
|
|
2077
|
+
}
|
|
2078
|
+
function handleViewportWheel(event) {
|
|
2079
|
+
event.preventDefault();
|
|
2080
|
+
const rect = viewport.getBoundingClientRect();
|
|
2081
|
+
const pointerX = event.clientX - rect.left;
|
|
2082
|
+
const pointerY = event.clientY - rect.top;
|
|
2083
|
+
const nextScale = Math.min(MAX_VIEWPORT_ZOOM, Math.max(MIN_VIEWPORT_ZOOM, viewportScale * Math.exp(-event.deltaY * VIEWPORT_ZOOM_STEP)));
|
|
2084
|
+
if (nextScale === viewportScale) return;
|
|
2085
|
+
const sceneX = (pointerX - viewportPanX) / viewportScale;
|
|
2086
|
+
const sceneY = (pointerY - viewportPanY) / viewportScale;
|
|
2087
|
+
viewportScale = nextScale;
|
|
2088
|
+
viewportPanX = pointerX - sceneX * viewportScale;
|
|
2089
|
+
viewportPanY = pointerY - sceneY * viewportScale;
|
|
2090
|
+
applyViewportTransform();
|
|
2091
|
+
}
|
|
2092
|
+
function handleViewportPointerDown(event) {
|
|
2093
|
+
if (event.button !== 0 || activePointerId !== null) return;
|
|
2094
|
+
activePointerId = event.pointerId;
|
|
2095
|
+
dragStartX = event.clientX;
|
|
2096
|
+
dragStartY = event.clientY;
|
|
2097
|
+
dragLastX = event.clientX;
|
|
2098
|
+
dragLastY = event.clientY;
|
|
2099
|
+
dragMoved = false;
|
|
2100
|
+
viewport.setPointerCapture(event.pointerId);
|
|
2101
|
+
viewport.style.cursor = "grabbing";
|
|
2102
|
+
}
|
|
2103
|
+
function handleViewportPointerMove(event) {
|
|
2104
|
+
if (event.pointerId !== activePointerId) return;
|
|
2105
|
+
const deltaX = event.clientX - dragLastX;
|
|
2106
|
+
const deltaY = event.clientY - dragLastY;
|
|
2107
|
+
const totalX = event.clientX - dragStartX;
|
|
2108
|
+
const totalY = event.clientY - dragStartY;
|
|
2109
|
+
if (!dragMoved && Math.hypot(totalX, totalY) >= DRAG_CLICK_THRESHOLD_PX) dragMoved = true;
|
|
2110
|
+
dragLastX = event.clientX;
|
|
2111
|
+
dragLastY = event.clientY;
|
|
2112
|
+
viewportPanX += deltaX;
|
|
2113
|
+
viewportPanY += deltaY;
|
|
2114
|
+
applyViewportTransform();
|
|
2115
|
+
}
|
|
2116
|
+
function handleViewportPointerEnd(event) {
|
|
2117
|
+
if (event.pointerId !== activePointerId) return;
|
|
2118
|
+
if (dragMoved) suppressNextClick = true;
|
|
2119
|
+
if (viewport.hasPointerCapture(event.pointerId)) viewport.releasePointerCapture(event.pointerId);
|
|
2120
|
+
activePointerId = null;
|
|
2121
|
+
dragMoved = false;
|
|
2122
|
+
viewport.style.cursor = interactiveViewport ? "grab" : "pointer";
|
|
2123
|
+
}
|
|
2049
2124
|
function applyCurrentTime() {
|
|
2050
2125
|
for (const anim of allAnims) anim.currentTime = sceneMs;
|
|
2051
2126
|
onTimeUpdate?.(sceneMs / 1e3, durationSeconds);
|
|
2052
2127
|
}
|
|
2053
2128
|
function rafTick(timestamp) {
|
|
2054
|
-
if (lastRafTs !== null) sceneMs += (timestamp - lastRafTs) * playbackRate;
|
|
2129
|
+
if (lastRafTs !== null) sceneMs += (timestamp - lastRafTs) * playbackRate * NORMAL_PLAYBACK_RATE;
|
|
2055
2130
|
lastRafTs = timestamp;
|
|
2056
2131
|
if (totalDurationMs > 0 && sceneMs >= totalDurationMs) {
|
|
2057
2132
|
if (loop) sceneMs = sceneMs % totalDurationMs;
|
|
@@ -2122,8 +2197,20 @@ function createDiagram(opts) {
|
|
|
2122
2197
|
if (viewport.parentNode === container) container.removeChild(viewport);
|
|
2123
2198
|
}
|
|
2124
2199
|
};
|
|
2125
|
-
viewport.style.cursor = "pointer";
|
|
2200
|
+
viewport.style.cursor = interactiveViewport ? "grab" : "pointer";
|
|
2201
|
+
if (interactiveViewport) {
|
|
2202
|
+
viewport.style.touchAction = "none";
|
|
2203
|
+
viewport.addEventListener("wheel", handleViewportWheel, { passive: false });
|
|
2204
|
+
viewport.addEventListener("pointerdown", handleViewportPointerDown);
|
|
2205
|
+
viewport.addEventListener("pointermove", handleViewportPointerMove);
|
|
2206
|
+
viewport.addEventListener("pointerup", handleViewportPointerEnd);
|
|
2207
|
+
viewport.addEventListener("pointercancel", handleViewportPointerEnd);
|
|
2208
|
+
}
|
|
2126
2209
|
viewport.addEventListener("click", () => {
|
|
2210
|
+
if (suppressNextClick) {
|
|
2211
|
+
suppressNextClick = false;
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2127
2214
|
if (isPlaying) diagram.pause();
|
|
2128
2215
|
else {
|
|
2129
2216
|
if (!loop && sceneMs >= totalDurationMs) sceneMs = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.15",
|
|
4
4
|
"description": "Browser renderer for diagram-native animated MarkdyScript architecture diagrams, built on the Web Animations API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@markdy/core": "0.8.
|
|
47
|
+
"@markdy/core": "0.8.15"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"jsdom": "^29.1.1",
|
|
51
51
|
"tsup": "^8.5.1",
|
|
52
52
|
"typescript": "^5.9.3",
|
|
53
53
|
"vitest": "^4.1.7",
|
|
54
|
-
"@markdy/stdlib-systems": "0.8.
|
|
54
|
+
"@markdy/stdlib-systems": "0.8.15"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|