Ich habe versucht, hier den Rat zu folgen:exportieren SVG png oder andere Bild mit Styling, mit JavaScript
sowie die this npm module meine c3 zu exportieren (die auf d3 basiert) Plots zu einer Bilddatei - .png für jetzt.
im Browser sieht die Image-Datei wie folgt aus:
Der save-svg-as-png
Modulknoten erzeugt jedoch diese:
Das Skript aus der SO oben genannten post erzeugt folgendes in einer neuen Registerkarte:
Wie Sie sehen können, werden die Pfade geschlossen und dann ausgefüllt, als ob die .css ignoriert wird.
Hier ist der Code, die Plots zu erzeugen:
# 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;
und (kopiert aus der oben erwähnte SO post):
# 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;
Ich habe auch ein Beispielprojekt mit diesem Code hochgeladen github:
https://github.com/shafiquejamal/export-svg-to-png
könnte jemand beraten Wie sieht die exportierte Datei so aus, als würde sie im Browser gerendert? Vielen Dank!
Update # 1: Unter https://stackoverflow.com/users/3702797/kaiido ‚Anregung folgend, in plotMultiline.js
geändert I
d3.select(`#${chartID} svg`).attr('id', `svg-${chartID}`)
zu
d3.select(`#${chartID} svg`).attr('id', `svg-${chartID}`)
.classed('c3', true);
und erzeugt dann saveSvgAsPng
folgende Bild-Datei:
Dies behebt die geschlossene Form fill Problem, aber der Hintergrund ist tatsächlich transparent, nicht weiß, wie man aus dem folgenden Screenshot sehen:
Aber das ist eigentlich gut genug für meine Zwecke.
danke für Ihren Vorschlag. Ich fand, dass 'svg.classList.add' nicht funktionierte, aber' .classed ('c3', true) 'auf dem Svg-Objekt hat funktioniert (siehe meine Änderungen an der meine Frage). Ich musste keine CSS ändern, um den gewünschten Effekt zu erhalten (bisher). –
@ShafiqueJamal yes 'svg.classList.add' erwartet, dass' svg' ein SVGSVGElement ist (d. H. Der DOM-Knoten direkt). In deinem Fall ist es ein d3-Objekt. Um den DOM-Knoten zu erhalten, würden Sie seine '.node()' Methode aufrufen, aber wie Sie herausgefunden haben, können Sie auch direkt die d3 '.classed' Methode verwenden. Und für den weißen Hintergrund scheint es standardmäßig sogar auf c3 transparent zu sein. Sie können immer einen Stil auf Ihrem Svg-Knoten hinzufügen ('svg.style ('background-color', 'white');'). – Kaiido