Pregunta Cómo generar correctamente lienzo desde svg complejo


Estoy tratando de exportar un bloque SVG complejo (generado con c3) desde mi sitio web como una imagen (ya sea png, svg, pdf, en este punto estoy abierto a cualquier cosa que lo resuelva, aunque el formato vectorial sería ideal) . He intentado html2canvas, canvg, jsPDF y todos los niños geniales de esa pandilla. El problema es: una de mis tramas se estropea. La línea se convierte en área, las áreas se invierten, los colores se arruinan, ... lo que quieras.

estoy bastante lejos De ser js experto. Acabo de llegar y estoy encontrando mi camino, algunos por favor tengan paciencia conmigo.

No sé si esto es un problema de CSS o qué. Sí, tenemos CSS detrás del html.

Mi solución temporal es usar jQuery.print.js para llamar a una copia de mi div. Esto está lejos de ser ideal por muchas razones:

  • No bbox. Genera un PDF con el tamaño de página definido por el usuario, no el tamaño de la imagen;

  • Estoy usando tarjetas de arranque con cambio de tamaño automático. Cada vez que se presiona la "imagen de impresión", la impresión utiliza el tamaño actual. He intentado ocultar tarjetas para cambiar la escala del objetivo, pero el cambio de tamaño solo tendrá lugar DESPUÉS de la llamada de impresión, por razones que desconozco. Si este problema se resuelve, esta solución temporal sería mejor, aunque todavía es una temperatura.

Entonces, una pregunta es:

  • ¿Cómo obtener el SVG como se muestra?
  • Alternativamente, ¿cómo cambiar el tamaño de la tarjeta ANTES de llamar a la impresión?
  • O, ¿cómo generar raster (png / jpeg) sin los errores de formato obtenidos de canvg / jsPDF?

La función que hace la llamada de impresión por ahora es:

function getscreenshot(div) {
  // Hide row pair:
  $('#map-card').addClass('hidden');

  // Temporarily change class attr to spawn all row:
  var divClass = $(div).attr('class');
  $(div).attr('class', 'col');

  // ****PROBLEM****
  // Div size is not upated before calling print()
  // causing the print to have the size as displayed on user screen
  // How to refresh it before print?
  // ********

  // jQuery.print solves it in a non-ideal way, since user has to set save as file and so on
  $(div).print();

  // This solution with jsPDF produces **ugly as hell** image:
  // var pdf = new jsPDF('landscape');
  // pdf.addHTML(document.getElementById(div), function() {
  //     pdf.save(name + 'pdf');
  // });

  // Recover original size after print:
  // Restore row pair and div original state:
  $('#map-card').removeClass('hidden');
  $(div).attr('class', divClass);
}

Aquí está la fila de tarjetas como se muestra en la página web: Cards row

La trama de la derecha es la que estoy enfocando en mis pruebas, y la que se está completando sin formatear. Verifique lo que sale usando html2canvas, jsPDF y resultados similares en la misma mala interpretación que aparece en el violín con SVG pegado, usando canvg.js

PD: si, busqué mucho. Así es como terminé probando html2canvas, canvg, jsPDF, jqprint, ...

¡Aclamaciones!


6
2018-06-07 21:29


origen


Respuestas:


Puedes resolver el problema con Mike Bostock (o quizás sea NY Times) SVG Crowbar. Use SVG Crowbar 2. Arrástrelo a la barra de marcadores y luego haga clic en él cuando esté en la página donde desea guardar el SVG. Si hay más de un SVG, tendrá que elegir cuál.

Probé SVG Crowbar 1 con c3.js y no guardó los estilos correctamente, así que asegúrate de usar SVG Crowbar 2. Probé SVG Crowbar 2 con c3.js y funcionó para mí.

Una vez que tienes un SVG, puedes usar Inkscape para hacer un PNG. Haga clic en: archivo> exportar imagen PNG. A continuación, elija las dimensiones deseadas para la salida. Luego haga clic en Exportar. Esta El sitio tiene un paso a paso de cómo hacer esto.

También hay sitios en línea que convierten SVG a PNG también, pero hay algunos, así que no publicaré los enlaces. Una búsqueda en google debe encontrar lo que necesitas.

Si quieres hacer todo esto de una manera programática, esa es otra historia.

Actualizar: SVG Crowbar (1 y 2) solo funciona en cromo.


1
2018-06-08 16:12



El resultado final utiliza la respuesta de @tgiachetti, con algunos ajustes. El problema con el svg-crowbar-2 original es que es un folleto y abre los botones de descarga a todos los SVG en el sitio web, que no es el resultado final deseado, y solo funciona en Chrome.

La solución presentada aquí funciona tanto en Chrome como en Firefox.

Así que terminé aplicando algunas modificaciones en svg-crowbar-2.js desde https://github.com/NYTimes/svg-crowbar :

  • Se utiliza como una función, no folleto;
  • Ciclos solo hasta la cuarta fuente SVG, ya que los restantes no son necesarios;
  • Recibe el número secuencial SVG para la descarga de una sola parcela;
  • Volver a cargar la página después de la descarga.

Los cambios se pueden encontrar como archivo js singledownload-svg-crowbar-2.js en: https://github.com/FluVigilanciaBR/fludashboard/blob/development/fludashboard/static/libs/svg-crowbar-2/singledownload-svg-crowbar-2.js

Para uso:

En primer lugar, insertado svg-crowbar-2 modificado como fuente:

<script src="./static/libs/svg-crowbar-2/singledownload-svg-crowbar-2.js"></script>

Luego, en cada tarjeta de parcela, inserté un botón con una llamada a la función getscreenshot que pasa el número secuencial del SVG deseado:

<div class="container">
 <button type="button" class="btn btn-link btn-sm no-print" onclick="getscreenshot(3);">Salvar imagem</button>
</div>

Esta función, ubicada en index.html, básicamente define el nombre del archivo SVG en función del número secuencial de la trama y llama a la única función de descarga SVG singleSVGcrowbar, definida en singledownload-svg-crowbar-2.js:

<script language="JavaScript" type="text/javascript">
  function getscreenshot(myplot) {
    var plotName = ['mapa', 'mapa-legenda', 'serie-temporal', 'distribuicao-etaria'];
    var myplotObj = {SVGid: myplot, SVGname: plotName[myplot]};

    singleSVGcrowbar(myplotObj);
  }
</script>

Si desea insertar esto en su propio sitio web, en primer lugar identifique el número secuencial del bloque SVG deseado ejecutando el svg-crowbar-2 original. Este es el número insertado en la llamada getscreenshot (myplot).


1
2018-06-14 14:03