【问题标题】:Recharts component to PNG将组件重新绘制为 PNG
【发布时间】:2021-07-20 22:17:00
【问题描述】:

我目前有一个想要导出为 PNG 文件的 Recharts 组件。

<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>;

但我不确定这个库是否直接支持。

我有一个想法,涉及使用画布和 2D 渲染上下文来让我接近解决方案,如 MDN 中所述

但是,我不确定将 HTML 元素(或 React 组件)呈现为画布以实现此解决方案的通用方法。

我可能在这一切都错了,我将不胜感激!

【问题讨论】:

    标签: javascript reactjs canvas recharts


    【解决方案1】:

    此函数将 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;
        });
    };
    

    以及如何访问 Recharts SVG 元素?这段代码 sn-p 允许您在当前可见 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);
    }
    

    【讨论】:

    • 我无法使用 pngData 创建 blob,有什么帮助吗?我需要 blob,以便我可以下载 png 图像
    • @AlbertMunichMar 我相信,您可以尝试通过从画布下载 pdf 图像来修改解决方案。见这里:stackoverflow.com/questions/8126623/…
    【解决方案2】:

    我能够通过深入研究 Recharts 组件来解决我的问题。 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");
        }
    }
    

    我正在使用FileSaver.js 作为保存提示。

    【讨论】:

    • 嗨,这里的currentChart 是什么?
    • 嗨,@Bajal ref={(chart) =&gt; this.currentChart = chart}
    • 在哪里将 svg 转换为 png?
    • 是否可以添加一个codepen、jsfiddle来全面了解当前示例?
    • 任何将svg转换为png的方法
    【解决方案3】:

    @brammitch 为此创建了一个包(灵感来自此处的答案):

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

    【讨论】:

      【解决方案4】:

      书面回答对我帮助很大。非常感谢。尽管如此,我还是错过了下载为 png 的“开箱即用”解决方案,我想在这里弥补。即使为时已晚,也许它会帮助别人。

      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;
          };
      
      

      【讨论】:

        【解决方案5】:

        这是一篇旧帖子,但可能会对某人有所帮助

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-08
          • 2014-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-27
          相关资源
          最近更新 更多