使用JavaScript将svg导出为png或具有样式的其他图像
我在这里尝试了以下建议: 以及将我的c3(基于d3)绘图导出到图像文件-.png的步骤 在浏览器中,图像文件如下所示: 但是,使用JavaScript将svg导出为png或具有样式的其他图像,javascript,css,d3.js,svg,c3.js,Javascript,Css,D3.js,Svg,C3.js,我在这里尝试了以下建议: 以及将我的c3(基于d3)绘图导出到图像文件-.png的步骤 在浏览器中,图像文件如下所示: 但是,将svg另存为png节点模块会产生以下结果: 上述SO post中的脚本在新选项卡中生成以下内容: 正如您所看到的,路径是关闭的,然后填充,就好像.css被忽略一样 以下是生成绘图的代码: # plotMultiline.js import * as c3 from 'c3'; import * as d3 from 'd3'; import { saveSvgA
将svg另存为png
节点模块会产生以下结果:
上述SO post中的脚本在新选项卡中生成以下内容:
正如您所看到的,路径是关闭的,然后填充,就好像.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;
到
然后saveSvgAsPng
生成以下图像文件:
这修复了闭合形状填充问题,但背景实际上是透明的,而不是白色的,如以下屏幕截图所示:
但就我的目的而言,这实际上已经足够好了。这是因为c3从父div容器设置了一些规则,父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;
}
规则。
因此,您可能需要自己设置它,并将其转换为例如.c3svg、svg.c3{…
或者,您可以
getComputedStyle
您的svg的所有节点,并过滤掉默认的节点,但是对于浏览器来说,这仍然需要做很多工作…谢谢您的建议。我发现svg.classList.add
不起作用,但是svg对象上的.classed('c3',true)
确实起作用(请参阅我对“我的问题”的编辑)。我不需要修改任何css来获得我想要的效果(到目前为止)。@ShafiqueJamal yessvg.classList.add
希望svg
是一个SVGSVGElement(即直接是DOM节点)。在您的情况下,它是一个d3对象。要获得DOM节点,您可以调用它的.node()
方法,但正如您所发现的,您也可以直接使用d3.classed
方法。对于白色背景,默认情况下,即使在c3上它也是透明的。您可以始终在svg节点上添加样式(svg.style(
)。
.c3 path, .c3 line {
fill: none;
stroke: rgb(0, 0, 0);
}
svg.classList.add('c3');
.c3 svg {
font: 10px sans-serif;
-webkit-tap-highlight-color: transparent;
}