简体   繁体   English

将组件重新绘制为 PNG

[英]Recharts component to PNG

I currently have a Recharts component that I would like to export as a PNG file.我目前有一个 Recharts 组件,我想将其导出为 PNG 文件。

<LineChart
  id="currentChart"
  ref={(chart) => (this.currentChart = chart)}
  width={this.state.width}
  height={this.state.height}
  data={this.testData}
  margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
  <XAxis dataKey="name" />
  <YAxis />
  <CartesianGrid strokeDasharray="3 3" />
  <Tooltip />
  <Legend />
  <Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
  <Line type="monotone" dataKey="uv" stroke="#82ca9d" />
</LineChart>;

but I'm unsure if this is directly supported by the library.但我不确定图书馆是否直接支持。

I have an idea that involves using a canvas and a 2D rendering context to get me close to a solution, as outlined on MDN我有一个想法,涉及使用画布和 2D 渲染上下文来让我接近解决方案,如MDN 上所述

However, I'm not sure of a generic way to render an HTML element (or React Component) as a canvas to implement this solution.但是,我不确定将 HTML 元素(或 React 组件)呈现为画布以实现此解决方案的通用方法。

I might be going about this all wrong, and I would appreciate the correction!我可能会在这一切都错了,我会很感激更正!

This function takes SVG element on input and transforms to image/png data:此函数在输入时采用 SVG 元素并转换为image/png数据:

export const svgToPng = (svg, width, height) => {

    return new Promise((resolve, reject) => {

        let canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        let ctx = canvas.getContext('2d');

        // Set background to white
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, width, height);

        let xml = new XMLSerializer().serializeToString(svg);
        let dataUrl = 'data:image/svg+xml;utf8,' + encodeURIComponent(xml);
        let img = new Image(width, height);

        img.onload = () => {
            ctx.drawImage(img, 0, 0);
            let imageData = canvas.toDataURL('image/png', 1.0);
            resolve(imageData)
        }

        img.onerror = () => reject();

        img.src = dataUrl;
    });
};

And how to access the Recharts SVG element?以及如何访问 Recharts SVG 元素? This code snippet allows you to render any Chart outside of your current visible DOM and use it's SVG:此代码片段允许您呈现当前可见 DOM 之外的任何图表并使用它的 SVG:

const exportChart = () => {

    // Output image size
    const WIDTH = 900;
    const HEIGHT = 250;

    const convertChart = async (ref) => {

        if (ref && ref.container) {
            let svg = ref.container.children[0];
            let pngData = await svgToPng(svg, WIDTH, HEIGHT);
            console.log('Do what you need with PNG', pngData);
        }
    };

    const chart = <LineChart data={...} width={WIDTH} height={HEIGHT}
        ref={ref => convertChart(ref)} />;

    // Render chart component into helper div
    const helperDiv = document.createElement('tmp');
    ReactDOM.render(chart, helperDiv);
}

I was able to solve my problem by delving into the Recharts component.我能够通过深入研究 Recharts 组件来解决我的问题。 Recharts renders as an SVG under a wrapper so all I had to do was convert properly to save as both HTML or SVG Recharts 在包装器下呈现为 SVG,所以我所要做的就是正确转换以另存为 HTML 或 SVG

// Exports the graph as embedded JS or PNG
exportChart(asSVG) {

    // A Recharts component is rendered as a div that contains namely an SVG
    // which holds the chart. We can access this SVG by calling upon the first child/
    let chartSVG = ReactDOM.findDOMNode(this.currentChart).children[0];

    if (asSVG) {
        let svgURL = new XMLSerializer().serializeToString(chartSVG);
        let svgBlob = new Blob([svgURL], {type: "image/svg+xml;charset=utf-8"});
        FileSaver.saveAs(svgBlob, this.state.uuid + ".svg");
    } else {
        let svgBlob = new Blob([chartSVG.outerHTML], {type: "text/html;charset=utf-8"});
        FileSaver.saveAs(svgBlob, this.state.uuid + ".html");
    }
}

I am using FileSaver.js for the save prompt.我使用FileSaver.js作为保存提示。

@brammitch created a package for this (inspired by answers here): @brammitch 为此创建了一个包(灵感来自这里的答案):

https://github.com/brammitch/recharts-to-png https://github.com/brammitch/recharts-to-png

The written answer helped me a lot.书面答复对我帮助很大。 Many thanks for that.非常感谢。 Nevertheless, I was missing an "out of the box" solution for the download as png, which I would like to make up for here.尽管如此,我还是缺少一个“开箱即用”的 png 下载解决方案,我想在这里弥补。 Even if it's too late, maybe it will help someone else.即使为时已晚,也许它会帮助其他人。

handleExportChart = () => {

        let chartSVG = ReactDOM.findDOMNode(this.currentChart).children[0];
        const width = chartSVG.clientWidth;
        const height = chartSVG.clientHeight;
        let svgURL = new XMLSerializer().serializeToString(chartSVG);
        let svgBlob = new Blob([svgURL], { type: "image/svg+xml;charset=utf-8" });
        let URL = window.URL || window.webkitURL || window;
        let blobURL = URL.createObjectURL(svgBlob);

        let image = new Image();
        image.onload = () => {
            let canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            let context = canvas.getContext('2d');
            context.drawImage(image, 0, 0, context.canvas.width, context.canvas.height);
            let png = canvas.toDataURL('image/png', 1.0);
            FileSaver.saveAs(png, "Test.png");
        };

        image.src = blobURL;
    };

This is an old post but this might help someone这是一个旧帖子,但这可能对某人有所帮助

 let pngData = await getPngData(this.ref); FileSaver.saveAs(pngData, filename);

using recharts-to-png and file-saver npm modules使用 recharts-to-png 和 file-saver npm 模块

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM