@markdy/renderer-dom 0.8.25 → 0.8.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -2
- package/dist/index.js +131 -48
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,17 @@ interface SvgExportOptions {
|
|
|
81
81
|
}
|
|
82
82
|
declare function exportDiagramAsVectorSvg(containerEl: HTMLElement, options?: SvgExportOptions): string;
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* packages/renderer-dom/src/export/png-exporter.ts
|
|
86
|
+
* High-DPI raster PNG export with 2x retina scaling.
|
|
87
|
+
* Zero external dependencies.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
interface PngExportOptions extends SvgExportOptions {
|
|
91
|
+
pixelRatio?: number;
|
|
92
|
+
}
|
|
93
|
+
declare function exportDiagramAsPng(containerEl: HTMLElement, options?: PngExportOptions): Promise<Blob>;
|
|
94
|
+
|
|
84
95
|
/**
|
|
85
96
|
* packages/renderer-dom/src/presentation-controller.ts
|
|
86
97
|
* Interactive Beat Navigation & Keyboard-driven presentation controller.
|
|
@@ -95,13 +106,17 @@ declare class DiagramPresentationController {
|
|
|
95
106
|
private diagram;
|
|
96
107
|
private plan;
|
|
97
108
|
private currentBeatIndex;
|
|
109
|
+
private options;
|
|
110
|
+
private isDestroyed;
|
|
98
111
|
constructor(diagram: Diagram, plan: RenderPlan, options?: ControllerOptions);
|
|
99
112
|
nextBeat(): void;
|
|
100
113
|
prevBeat(): void;
|
|
114
|
+
private applyCurrentBeat;
|
|
101
115
|
getCurrentBeatIndex(): number;
|
|
102
116
|
togglePlay(): void;
|
|
103
117
|
setSpeed(rate: number): void;
|
|
104
|
-
private
|
|
118
|
+
private onKeyDown;
|
|
119
|
+
destroy(): void;
|
|
105
120
|
}
|
|
106
121
|
|
|
107
|
-
export { type AnimationRecordFrame, type ControllerOptions, type Diagram, type DiagramOptions, DiagramPresentationController, type GifExportOptions, ICON_REGISTRY, type IconSpec, type SvgExportOptions, createDiagram, encodeGifSequence, exportDiagramAsVectorSvg };
|
|
122
|
+
export { type AnimationRecordFrame, type ControllerOptions, type Diagram, type DiagramOptions, DiagramPresentationController, type GifExportOptions, ICON_REGISTRY, type IconSpec, type PngExportOptions, type SvgExportOptions, createDiagram, encodeGifSequence, exportDiagramAsPng, exportDiagramAsVectorSvg };
|
package/dist/index.js
CHANGED
|
@@ -2694,7 +2694,7 @@ function lzwCompress(pixels, minCodeSize = 8) {
|
|
|
2694
2694
|
if (nextCode === 1 << codeSize && codeSize < 12) {
|
|
2695
2695
|
codeSize++;
|
|
2696
2696
|
}
|
|
2697
|
-
if (nextCode >=
|
|
2697
|
+
if (nextCode >= 4096) {
|
|
2698
2698
|
codes.push(clearCode);
|
|
2699
2699
|
dict = /* @__PURE__ */ new Map();
|
|
2700
2700
|
for (let j = 0; j < clearCode; j++) dict.set(String(j), j);
|
|
@@ -2785,31 +2785,96 @@ function encodeGifSequence(frames, options = {}) {
|
|
|
2785
2785
|
|
|
2786
2786
|
// src/export/svg-exporter.ts
|
|
2787
2787
|
function exportDiagramAsVectorSvg(containerEl, options = {}) {
|
|
2788
|
-
const
|
|
2789
|
-
if (!
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2788
|
+
const sceneEl = containerEl.classList?.contains("markdy-scene-root") ? containerEl : containerEl.querySelector(".markdy-scene-root") || containerEl.querySelector("svg") || (containerEl.tagName?.toLowerCase() === "svg" ? containerEl : null);
|
|
2789
|
+
if (!sceneEl) throw new Error("No Markdy scene element found in container");
|
|
2790
|
+
if (sceneEl.tagName?.toLowerCase() === "svg") {
|
|
2791
|
+
const clonedSvg = sceneEl.cloneNode(true);
|
|
2792
|
+
if (!clonedSvg.getAttribute("xmlns")) {
|
|
2793
|
+
clonedSvg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
2794
|
+
}
|
|
2795
|
+
const serializer2 = new XMLSerializer();
|
|
2796
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2797
|
+
${serializer2.serializeToString(clonedSvg)}`;
|
|
2798
|
+
}
|
|
2799
|
+
const clonedScene = sceneEl.cloneNode(true);
|
|
2800
|
+
const widthStr = clonedScene.style.width || String(sceneEl.clientWidth || 800);
|
|
2801
|
+
const heightStr = clonedScene.style.height || String(sceneEl.clientHeight || 400);
|
|
2802
|
+
let width = parseFloat(widthStr);
|
|
2803
|
+
let height = parseFloat(heightStr);
|
|
2804
|
+
if (isNaN(width)) width = 800;
|
|
2805
|
+
if (isNaN(height)) height = 400;
|
|
2806
|
+
const scale = options.scale || 1;
|
|
2807
|
+
const scaledWidth = width * scale;
|
|
2808
|
+
const scaledHeight = height * scale;
|
|
2809
|
+
clonedScene.style.transform = `scale(${scale})`;
|
|
2810
|
+
clonedScene.style.transformOrigin = "0 0";
|
|
2811
|
+
clonedScene.style.position = "relative";
|
|
2812
|
+
clonedScene.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
2798
2813
|
if (options.transparentBackground) {
|
|
2799
|
-
|
|
2800
|
-
if (bgRect) bgRect.remove();
|
|
2814
|
+
clonedScene.style.background = "transparent";
|
|
2801
2815
|
}
|
|
2816
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
2817
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
2818
|
+
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
|
2819
|
+
svg.setAttribute("width", String(scaledWidth));
|
|
2820
|
+
svg.setAttribute("height", String(scaledHeight));
|
|
2821
|
+
svg.setAttribute("viewBox", `0 0 ${scaledWidth} ${scaledHeight}`);
|
|
2802
2822
|
if (options.includeThemeStyles !== false) {
|
|
2803
2823
|
const styleEl = document.createElementNS("http://www.w3.org/2000/svg", "style");
|
|
2804
|
-
|
|
2805
|
-
|
|
2824
|
+
let combinedStyles = `
|
|
2825
|
+
foreignObject { width: 100%; height: 100%; }
|
|
2806
2826
|
.markdy-node { transition: opacity 0.3s ease; }
|
|
2807
2827
|
`;
|
|
2808
|
-
|
|
2809
|
-
|
|
2828
|
+
if (typeof document !== "undefined") {
|
|
2829
|
+
const styles = document.querySelectorAll("style[id^='markdy-']");
|
|
2830
|
+
for (let i = 0; i < styles.length; i++) {
|
|
2831
|
+
combinedStyles += styles[i].textContent + "\n";
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
styleEl.textContent = combinedStyles;
|
|
2835
|
+
svg.appendChild(styleEl);
|
|
2836
|
+
}
|
|
2837
|
+
const foreignObject = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
|
|
2838
|
+
foreignObject.setAttribute("width", "100%");
|
|
2839
|
+
foreignObject.setAttribute("height", "100%");
|
|
2840
|
+
foreignObject.appendChild(clonedScene);
|
|
2841
|
+
svg.appendChild(foreignObject);
|
|
2810
2842
|
const serializer = new XMLSerializer();
|
|
2811
2843
|
return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2812
|
-
` + serializer.serializeToString(
|
|
2844
|
+
` + serializer.serializeToString(svg);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
// src/export/png-exporter.ts
|
|
2848
|
+
async function exportDiagramAsPng(containerEl, options = {}) {
|
|
2849
|
+
const svgXml = exportDiagramAsVectorSvg(containerEl, options);
|
|
2850
|
+
const pixelRatio = options.pixelRatio || 2;
|
|
2851
|
+
const blob = new Blob([svgXml], { type: "image/svg+xml;charset=utf-8" });
|
|
2852
|
+
const url = URL.createObjectURL(blob);
|
|
2853
|
+
const img = new Image();
|
|
2854
|
+
await new Promise((resolve, reject) => {
|
|
2855
|
+
img.onload = () => resolve();
|
|
2856
|
+
img.onerror = () => reject(new Error("Failed to rasterize SVG into Image for PNG export"));
|
|
2857
|
+
img.src = url;
|
|
2858
|
+
});
|
|
2859
|
+
const width = img.naturalWidth || 800;
|
|
2860
|
+
const height = img.naturalHeight || 400;
|
|
2861
|
+
const canvas = document.createElement("canvas");
|
|
2862
|
+
canvas.width = width * pixelRatio;
|
|
2863
|
+
canvas.height = height * pixelRatio;
|
|
2864
|
+
const ctx = canvas.getContext("2d");
|
|
2865
|
+
if (!ctx) {
|
|
2866
|
+
URL.revokeObjectURL(url);
|
|
2867
|
+
throw new Error("Could not get 2D canvas context for PNG export");
|
|
2868
|
+
}
|
|
2869
|
+
ctx.scale(pixelRatio, pixelRatio);
|
|
2870
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
2871
|
+
URL.revokeObjectURL(url);
|
|
2872
|
+
return new Promise((resolve, reject) => {
|
|
2873
|
+
canvas.toBlob((b) => {
|
|
2874
|
+
if (b) resolve(b);
|
|
2875
|
+
else reject(new Error("Canvas toBlob failed for PNG export"));
|
|
2876
|
+
}, "image/png");
|
|
2877
|
+
});
|
|
2813
2878
|
}
|
|
2814
2879
|
|
|
2815
2880
|
// src/presentation-controller.ts
|
|
@@ -2817,60 +2882,77 @@ var DiagramPresentationController = class {
|
|
|
2817
2882
|
diagram;
|
|
2818
2883
|
plan;
|
|
2819
2884
|
currentBeatIndex = 0;
|
|
2885
|
+
options;
|
|
2886
|
+
isDestroyed = false;
|
|
2820
2887
|
constructor(diagram, plan, options = {}) {
|
|
2821
2888
|
this.diagram = diagram;
|
|
2822
2889
|
this.plan = plan;
|
|
2890
|
+
this.options = options;
|
|
2823
2891
|
if (options.enableKeyboard !== false && typeof window !== "undefined") {
|
|
2824
|
-
this.
|
|
2892
|
+
window.addEventListener("keydown", this.onKeyDown);
|
|
2825
2893
|
}
|
|
2826
2894
|
}
|
|
2827
2895
|
nextBeat() {
|
|
2828
2896
|
if (this.currentBeatIndex < this.plan.beats.length - 1) {
|
|
2829
2897
|
this.currentBeatIndex++;
|
|
2830
|
-
|
|
2831
|
-
this.diagram.seek(beat.start);
|
|
2898
|
+
this.applyCurrentBeat();
|
|
2832
2899
|
}
|
|
2833
2900
|
}
|
|
2834
2901
|
prevBeat() {
|
|
2835
2902
|
if (this.currentBeatIndex > 0) {
|
|
2836
2903
|
this.currentBeatIndex--;
|
|
2837
|
-
|
|
2838
|
-
|
|
2904
|
+
this.applyCurrentBeat();
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
applyCurrentBeat() {
|
|
2908
|
+
const beat = this.plan.beats[this.currentBeatIndex];
|
|
2909
|
+
this.diagram.seek(beat.start);
|
|
2910
|
+
if (this.options.onBeatChange) {
|
|
2911
|
+
this.options.onBeatChange(beat.name, this.currentBeatIndex);
|
|
2839
2912
|
}
|
|
2840
2913
|
}
|
|
2841
2914
|
getCurrentBeatIndex() {
|
|
2842
2915
|
return this.currentBeatIndex;
|
|
2843
2916
|
}
|
|
2844
2917
|
togglePlay() {
|
|
2845
|
-
this.diagram.
|
|
2918
|
+
if (this.diagram.isPlaying()) {
|
|
2919
|
+
this.diagram.pause();
|
|
2920
|
+
} else {
|
|
2921
|
+
this.diagram.play();
|
|
2922
|
+
}
|
|
2846
2923
|
}
|
|
2847
2924
|
setSpeed(rate) {
|
|
2848
2925
|
this.diagram.setPlaybackRate(rate);
|
|
2849
2926
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2927
|
+
onKeyDown = (e) => {
|
|
2928
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
2929
|
+
switch (e.key) {
|
|
2930
|
+
case "ArrowRight":
|
|
2931
|
+
case "PageDown":
|
|
2932
|
+
this.nextBeat();
|
|
2933
|
+
break;
|
|
2934
|
+
case "ArrowLeft":
|
|
2935
|
+
case "PageUp":
|
|
2936
|
+
this.prevBeat();
|
|
2937
|
+
break;
|
|
2938
|
+
case " ":
|
|
2939
|
+
e.preventDefault();
|
|
2940
|
+
this.togglePlay();
|
|
2941
|
+
break;
|
|
2942
|
+
case "1":
|
|
2943
|
+
this.setSpeed(1);
|
|
2944
|
+
break;
|
|
2945
|
+
case "2":
|
|
2946
|
+
this.setSpeed(2);
|
|
2947
|
+
break;
|
|
2948
|
+
}
|
|
2949
|
+
};
|
|
2950
|
+
destroy() {
|
|
2951
|
+
if (this.isDestroyed) return;
|
|
2952
|
+
this.isDestroyed = true;
|
|
2953
|
+
if (typeof window !== "undefined") {
|
|
2954
|
+
window.removeEventListener("keydown", this.onKeyDown);
|
|
2955
|
+
}
|
|
2874
2956
|
}
|
|
2875
2957
|
};
|
|
2876
2958
|
export {
|
|
@@ -2878,5 +2960,6 @@ export {
|
|
|
2878
2960
|
ICON_REGISTRY,
|
|
2879
2961
|
createDiagram,
|
|
2880
2962
|
encodeGifSequence,
|
|
2963
|
+
exportDiagramAsPng,
|
|
2881
2964
|
exportDiagramAsVectorSvg
|
|
2882
2965
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.26",
|
|
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.26"
|
|
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.26"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|