layerchart icon indicating copy to clipboard operation
layerchart copied to clipboard

Download as PNG / SVG / etc

Open techniq opened this issue 1 year ago • 5 comments

  • Mixing rendering contexts (<Svg>, <Canvas>, etc) will make some options more difficult / impossible
  • Download as PNG
    • If using only <Canvas>, should be able to use:
    • html2canvas
      • https://dev.to/bibekkakati/take-screenshot-of-html-element-using-javascript-13b7
    • html-to-image
    • Possible use navigator.mediaDevices.getDisplayMedia() (will prompt)
      • https://stackoverflow.com/questions/49605681/are-there-any-browser-provided-apis-to-capture-a-screenshot-of-the-dom-of-a-page
    • https://github.com/w3c/mediacapture-screen-share/issues/105
    • https://github.com/w3c/mediacapture-screen-share/issues/107
    • https://observablehq.com/@fil/canvas-plot
    • https://observablehq.com/@jcolot/observable-plot-canvas
    • https://github.com/qq15725/modern-screenshot
  • Leverage puppeteer (backend, round trip)
  • Download as SVG
    • If using only <Svg>, should be able to use:
      • new XMLSerializer().serializeToString(svg)
      • see also: https://stackoverflow.com/questions/28226677/save-inline-svg-as-jpeg-png-svg
  • Upscaling Canvas
    • Maybe provide a dedicated DownloadCanvas or create a new Canvas offscreen with higher container width/height overridden
    • See some discussion

techniq avatar May 20 '24 11:05 techniq

SVG reproduction when using CSS classes / variables will require some extra processing to fully reproduce visual.

image

techniq avatar May 20 '24 12:05 techniq

Mike Bostock's examples of serialize() and rasterize() for SVG look straight forward (using document.createTreeWalker().

Likely how Download SVG and Download PNG are implemented (or at least the basics).

image

see also: https://talk.observablehq.com/t/svg-to-png/6957

techniq avatar May 20 '24 12:05 techniq

See discussion for approach with SVG

function downloadSVG() {
    const svgEl = document.querySelector('.lc-layout-svg');
    if (svgEl) {
        svgEl?.setAttribute('xmlns', 'http://www.w3.org/2000/svg');

        svgEl.querySelector('.svg_text')?.classList.remove('hidden');

        const svgString = new XMLSerializer().serializeToString(svgEl);

        const a = document.createElement('a');
        a.href = window.URL.createObjectURL(new Blob([svgString]));
        a.download = 'download.svg';
        a.click();

        a.remove();

        svgEl?.removeAttribute('xmlns');
        svgEl.querySelector('.svg_text')?.classList.add('hidden');
    }
};

techniq avatar Jun 27 '24 16:06 techniq

See discussion for approach with Canvas

function downloadPNG() {
    const canvas = document.querySelector('.lc-layout-canvas') as HTMLCanvasElement;
    const ctx = canvas.getContext('2d');
    const dataUrl = ctx?.canvas.toDataURL('image/png', 1);

    const a = document.createElement('a');
    a.href = dataUrl;
    a.download = 'download.png';
    a.click();
    a.remove();
};

techniq avatar Jul 18 '24 13:07 techniq

save as svg and png looks good to me...

meta-cretin avatar Aug 19 '24 12:08 meta-cretin