我试图遵循这里的建议:
以及将我的c3(基于d3)的this npm module图表导出到图像文件 - .png现在。
在浏览器中,图像文件如下所示:
然而,save-svg-as-png
节点模块产生了这个:
上述SO帖子中的脚本在新标签中生成以下内容:
如您所见,路径已关闭然后填充,就好像忽略.css一样。
以下是生成图表的代码:
# plotMultiline.js
import * as c3 from 'c3';
import * as d3 from 'd3';
import { saveSvgAsPng } from 'save-svg-as-png';
import createImageFromSVG from './createImageFromSVG';
const plotMultiline = (
chartID, dataToPlot,
headingsAndLabels,
xHeading,
nTicks,
xRange,
xLines = [],
title,
xAxisTitle,
note,
yTitle = 'Frequency of occurrence',
inset = null,
) => {
d3.select('body').append('div')
.attr('id', chartID);
const yDatas = Object.entries(headingsAndLabels).map(([columnName, newLabel]) =>
[newLabel, ...dataToPlot.map(d => d[columnName])]);
const firstKey = Object.keys(dataToPlot[0])[0];
const secondKey = Object.keys(dataToPlot[0])[1];
const xMin = +dataToPlot[0][firstKey];
const xMax = +[...dataToPlot].pop()[secondKey];
const xTickValuesAll = [...dataToPlot.map(d => +d[firstKey])];
const nXTickValuesAll = xTickValuesAll.length;
const xTickValuesIndices =
[...Array(nTicks).keys()].map(d => d * Math.ceil(nXTickValuesAll / nTicks))
.filter(d => d <= nXTickValuesAll - 1);
let xTickValues = [];
if (nTicks) {
if (typeof nTicks === 'number') {
xTickValues = [...xTickValuesIndices.map(i => +xTickValuesAll[i]), xMax];
} else if (nTicks === 'integer') {
xTickValues = [...xTickValuesAll, xMax].filter(d => Math.round(d) === d);
}
} else {
xTickValues = [...xTickValuesAll, xMax];
}
const rightPadding = (xTickValues[1] - xTickValues[0]) / 5;
const chart = c3.generate({
bindto: `#${chartID}`,
title: {
text: title,
},
point: {
show: false,
},
size: {
width: 960,
height: 500,
},
padding: {
bottom: 20,
top: 20,
},
data: {
x: xHeading,
columns: yDatas,
},
legend: {
position: 'inset',
inset,
},
axis: {
x: {
tick: {
outer: false,
values: xTickValues,
},
min: xMin,
max: xMax,
padding: { left: 0, right: rightPadding },
label: {
text: xAxisTitle || xHeading,
position: 'outer-center',
},
height: 50,
},
y: {
padding: { top: 0, bottom: 0 },
label: {
text: yTitle,
position: 'outer-middle',
},
},
},
grid: {
x: {
show: true,
lines: xLines,
},
y: {
show: true,
},
},
});
d3.select(`#${chartID} svg`).attr('id', `svg-${chartID}`);
if (note) {
d3.select(`#${chartID} svg`).append('text')
.attr('x', 630)
.attr('y', 485)
.classed('note', true)
.text(note);
}
if (xRange) {
const xRangeMin = xRange[0];
const xRangeMax = xRange[1];
chart.axis.range({
min: {
x: xRangeMin,
},
max: {
x: xRangeMax,
},
});
}
setTimeout(() => {
d3.select(`#${chartID}`)
.append('button')
.on('click', () => saveSvgAsPng(d3.select(`#svg-${chartID}`)[0]['0'], `#svg-${chartID}.png`))
.classed('btn btn-success', true)
.attr('id', 'button-library');
d3.select(`#${chartID}`)
.append('button')
.on('click', () => createImageFromSVG(`#svg-${chartID}`))
.classed('btn btn-success', true)
.attr('id', 'button-so-script');
}, 1000);
};
export default plotMultiline;
和(从上述SO帖子中复制):
# createImageFromSVG
import * as d3 from 'd3';
const createImageFromSVG = (selectorForSVG) => {
// get styles from all required stylesheets
// http://www.coffeegnome.net/converting-svg-to-png-with-canvg/
let style = '\n';
for (let i = 0; i < document.styleSheets.length; i++) {
const sheet = document.styleSheets[i];
if (sheet.href) {
const { rules } = sheet;
if (rules) {
for (let j = 0; j < rules.length; j++) {
style += (`${rules[j].cssText}\n`);
}
}
}
}
const svg = d3.select(selectorForSVG);
const img = new Image();
const serializer = new XMLSerializer();
// prepend style to svg
svg.insert('defs', ':first-child');
d3.select('svg defs')
.append('style')
.attr('type', 'text/css')
.html(style);
// generate IMG in new tab
const svgStr = serializer.serializeToString(svg.node());
img.src = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;
const popUp = window.open();
if (popUp) {
popUp.document.write(`<img src="${img.src}"/>`);
}
};
export default createImageFromSVG;
我还使用此代码将示例项目上传到github:
https://github.com/shafiquejamal/export-svg-to-png
有人可以建议如何使导出的文件看起来像在浏览器中呈现的内容?谢谢!
更新#1:按照https://stackoverflow.com/users/3702797/kaiido的建议,在plotMultiline.js
我改变了
d3.select(`#${chartID} svg`).attr('id', `svg-${chartID}`)
到
d3.select(`#${chartID} svg`).attr('id', `svg-${chartID}`)
.classed('c3', true);
然后saveSvgAsPng
生成以下图像文件:
这修复了封闭形状填充问题,但背景实际上是透明的,而不是白色,如下面的屏幕截图所示:
但这实际上足以满足我的目的。
答案 0 :(得分:2)
这是因为c3从父div容器设置了一些规则,该容器具有class="c3"
属性。
特别是,你会找到一个
.c3 path, .c3 line {
fill: none;
stroke: rgb(0, 0, 0);
}
规则。
当您将svg转换为独立版时,此规则将不再匹配。
要解决此问题,您可以简单地在父svg
节点上设置此类。
svg.classList.add('c3');
但你会松开
.c3 svg {
font: 10px sans-serif;
-webkit-tap-highlight-color: transparent;
}
规则。
因此,您可能需要自己设置,并将其转换为例如.c3 svg, svg.c3 {...
或者,您可以getComputedStyle
svg的所有节点,并过滤掉默认节点,但这仍然需要为浏览器做很多工作......