将组件重新绘制为 PNG
Recharts component to PNG
我目前有一个 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>;
但我不确定库是否直接支持它。
我有一个想法,涉及使用 canvas 和 2D 渲染上下文来接近解决方案,如 MDN
中所述
但是,我不确定将 HTML 元素(或 React 组件)呈现为 canvas 以实现此解决方案的通用方法。
我可能做错了,非常感谢您的指正!
我能够通过深入研究 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 作为保存提示。
此函数将 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 元素?此代码片段允许您在当前可见 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);
}
@brammitch 为此创建了一个包(灵感来自这里的答案):
书面回答对我帮助很大。非常感谢。尽管如此,我还是缺少一个用于下载为 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;
};
这是旧的 post 但这可能对某人有帮助
let pngData = await getPngData(this.ref);
FileSaver.saveAs(pngData, filename);
使用 recharts-to-png 和文件保护 npm 模块
我目前有一个 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>;
但我不确定库是否直接支持它。
我有一个想法,涉及使用 canvas 和 2D 渲染上下文来接近解决方案,如 MDN
中所述但是,我不确定将 HTML 元素(或 React 组件)呈现为 canvas 以实现此解决方案的通用方法。
我可能做错了,非常感谢您的指正!
我能够通过深入研究 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 作为保存提示。
此函数将 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 元素?此代码片段允许您在当前可见 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);
}
@brammitch 为此创建了一个包(灵感来自这里的答案):
书面回答对我帮助很大。非常感谢。尽管如此,我还是缺少一个用于下载为 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;
};
这是旧的 post 但这可能对某人有帮助
let pngData = await getPngData(this.ref);
FileSaver.saveAs(pngData, filename);
使用 recharts-to-png 和文件保护 npm 模块