Incluir gráficos en Reporte PDF

186 views
Skip to first unread message

Juan Manuel

unread,
Nov 26, 2020, 6:50:35 AM11/26/20
to djan...@googlegroups.com
Buenas!, tengo una página en html que usa JS Highcharts, imágenes, tablas, etc. y estaba buscando exportar todo a un reporte PDF (con tablas, imágenes, etc.). El problema es que dado que Highcharts (y otros gráficos JS) se renderiza en el navegador, no aparece en el pdf generado. Probé JSPdf y PhantomJS pero con esos generadores de "capturas de pantalla" estoy perdiendo todo el estilo y el formato que he creado con xhtml2pdf (portada y contraportada, marcas de agua, etc.). ¿Alguna idea?

Saludos, Juan Manuel Jacquet

________________________________________________________________

  

Joni Bekenstein

unread,
Nov 26, 2020, 7:18:56 AM11/26/20
to django-ar
Te recomiendo usar chrome headless que te permite invocar chrome y pedirle que te guarde en PDF una URL, te produce prácticamente el mismo output que si abrís esa URL a mano, pones imprimir y guardás como PDF.

También podés usar puppeteer, es un wrapper alrededor de chrome headless con una API en NodeJS que te permite configurar varias cosas adicionales que vía el CLI de chrome headless no podes (por ejemplo los márgenes), o hacer cosas más avanzadas como esperar a que aparezca algún div en la página antes de generar el PDF, evaluar JS dentro del contexto de la página cargada, etc. Para usar puppeteer tendrías que armar un script en JS y ejecutarlo con NodeJS desde Python (por ejemplo usando el módulo subprocess), o armarlo como un servidorcito http y hacer un request desde Python, o incluso si buscás en google ya hay varios que armaron un puppeteer "as a service", quizás podes usar eso para empezar.

Juan Manuel

unread,
Nov 26, 2020, 7:49:53 AM11/26/20
to djan...@googlegroups.com
Gracias por la rta! pero la idea no es ejecutarlo con una librería dependiente de JS sino hacerlo desde Python/Django (me parece demasiado entreverado tener que ejecutar NodeJS en un subproceso para hacer un gráfico sencillo en un PDF)
--
Has recibido este mensaje porque estás suscrito al grupo "django-ar" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a django-ar+...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/django-ar/57cc8579-0e6f-4df3-aa98-ffe195975188n%40googlegroups.com.

Javier Viola

unread,
Nov 26, 2020, 7:56:37 AM11/26/20
to djan...@googlegroups.com
Hola Juan, podes usar algo como https://pypi.org/project/pyppeteer/ que es un port de puppeteer.

Saludos!

Joni Bekenstein

unread,
Nov 26, 2020, 10:12:02 AM11/26/20
to djan...@googlegroups.com
pyppeteer parece prometedor!

Más allá de cómo ejecutar chrome headless (que fijate que también lo podes hacer por línea de comando sin necesidad de usar puppeteer ni JS), a mi me simplificó muchísimo la vida generar PDFs de esta forma (puntualmente con chrome headless), ya que es un PDF a partir del render de chrome, y eso significa que podes usar todo lo último de HTML/CSS/JS para generar el contenido.

Incluso dependiendo de tu setup, podrías reutilizar el mismo rendering que ya estás usando para el frontend. Por ejemplo si tenes una webapp en React y tenes que generar un PDF de algo que ya está disponible en la webapp, de esta forma no tenes que armar otro maquetado aparte para el PDF, reusas lo que ya tenes hecho con React y con todo el tooling que uses para los estilos y demás.

Juan Manuel

unread,
Nov 26, 2020, 7:42:18 PM11/26/20
to djan...@googlegroups.com
Ahí pude resolverlo. Les comparto por si a alguno le sirve:
.- Tengo el Template con los gráficos en HighchartsJS.
.- Levanto el canvas del gráfico y lo guardo en un input oculto del formulario :
(function (H) {
    H.Chart.prototype.createCanvas = function (divId) {
        var svg = this.getSVG(),
            width = parseInt(svg.match(/width="([0-9]+)"/)[1]),
            height = parseInt(svg.match(/height="([0-9]+)"/)[1]),
            canvas = document.createElement('canvas');
        canvas.setAttribute('width', width);
        canvas.setAttribute('height', height);
        if (canvas.getContext && canvas.getContext('2d')) {
            canvg(canvas, svg);
            return canvas.toDataURL("image/jpeg");
        }
        else {
            alert("Your browser doesn't support this feature, please use a modern browser");
            return false;
        }
    }
}(Highcharts));
var imageData = $("#ausentismo_tot").highcharts().createCanvas();  
$('#aus_tot_image').val(imageData); //Hidden Input del Formulario

.- Viaja con el submit del Form y lo proceso en el views.py:
aus_tot_image = request.POST['aus_tot_image']
.- Imprimo el pdf y en el template del pdf (procesado con xhtml2pdf) pongo en <img src="{{ aus_inc_image }}" >
Reply all
Reply to author
Forward
0 new messages