Html2canvas: Cómo renderizar por completo la parte oculta en 'overflow: auto' div

Creado en 22 feb. 2012  ·  34Comentarios  ·  Fuente: niklasvh/html2canvas

Tengo un div que contiene todos los elementos que deben convertirse en una imagen. Y ese div está configurado en ' overflow: auto '. Quiero saber cómo puedo exportar todos los elementos (incluso los ocultos en el desplazamiento) a una imagen. Agradezco y agradezco todos sus comentarios y respuestas ... Gracias de antemano ...

Comentario más útil

@ruthraprakash , tuve un problema similar. Esto funciona para mis propósitos simples en la última versión:

function fullhtml2canvas(el) {
    return new Promise(resolve => {
        html2canvas(el, {
            width: el.scrollWidth,
            height: el.scrollHeight,
        }).then(canvas => {
            resolve(canvas);
        });
    });
}

Todos 34 comentarios

Actualmente no existe una opción para representar la página con opciones específicas, por lo que deberá modificar la página para que se vea como desea que se muestre.

En otras palabras, si elimina el límite de alto / ancho, ejecuta html2canvas y luego establece el alto / ancho de nuevo al valor que tenía, debería lograr lo que está buscando.

Muchas gracias ... intentaré lo que dijiste ...

Lo intenté durante mucho tiempo ... Pero crea muchos problemas ... No pude lograr lo que dijiste. Descubrí que funciona bien cuando es 'cuerpo' incluso si hay desplazamiento ... Quiero lograr lo mismo para un div que tiene elementos con desplazamiento ... Si pudiera ayudarme con este problema, sería de gran ayuda para mí ... Espero sus comentarios ...

@niklasvh , estoy teniendo el mismo problema, y ​​las únicas soluciones que tengo son reducir el ancho del elemento de destino antes de la llamada a html2canvas (no siempre es una opción), o llamar a html2canvas dos veces seguidas en el mismo elemento. Aquí hay un violín para demostrar el problema:

http://jsfiddle.net/fMeRC/1/ (este ejemplo en particular funciona solo para Chrome; tienes que jugar con el ancho para ver el problema en otros navegadores)

Básicamente, esto solo ocurre cuando el elemento es más ancho que la ventana o (document.width - 8) , no estoy seguro de cuál tiene la relevancia más importante / directa, y esto puede cambiar en otros navegadores).

Probablemente relacionado: # 199 y # 108.

¿Intentó childElement o configuró "overflow = visible" y luego configuró "overflow = auto | hidden | heredar"?

childElement sin estilo, solo para recibir el contenido del div con desbordamiento:

<div id="main"><!--// main div -->
<div class="mainContent"><!--// div without style (height: auto, width: auto, margin: 0, padding: 0) -->
...content...
html2canvas([$("#main div.mainContent").get(0)],...)

Gracias por las sugerencias, @brcontainer. Probé el enfoque overflow: visible -> html2canvas( ... ) -> overflow: [old overflow] , aunque el destello del contenido oculto / no oculto / oculto de nuevo era demasiado notable (posiblemente porque mi elemento de destino es relativamente complejo). Aunque se me ocurrió una variante ligeramente optimizada de la solución que parece marcar la diferencia en ese sentido:

html2canvas( targetElement, {
  onpreloaded: function(){ /* set parent overflow to visible */},
  onparsed: function(){  /* reset parent overflow */ },
  // ... onrendered, etc.
});

Esto establece el desbordamiento en 'visible' solo durante (lo que creo que es) la menor cantidad de tiempo necesaria para que h2c analice correctamente el objetivo, eliminando así el flash casi por completo, al menos en mi caso. Es decir, ya no tenemos que esperar a que finalice el paso de renderizado del lienzo antes de restablecer / volver a ocultar el desbordamiento. No tengo idea de si este enfoque modificado funcionará para todos, pero creo que es una mejor solución que llamar a html2canvas( ... ) dos veces seguidas o agregar cosas adicionales al DOM para envolver el contenido de destino.

En cualquier caso, este sigue siendo un error real que me gustaría que se corrigiera correctamente. (Especialmente porque ninguna de las soluciones parece funcionar correctamente para mí en IE9 y 10, al menos, no lo he probado en IE11).

_Nota: La solución alternativa mencionada anteriormente no funcionaría con la versión más reciente que se encuentra actualmente en master. No lo he probado, pero parece que necesitaría hacer uso de la opción oncloned lugar, y ahora se llamaría al reinicio principal de desbordamiento en su devolución de llamada a .then() . (También debería ser posible hacer visible exclusivamente el desbordamiento del padre dentro del documento clonado y no preocuparse por restablecer nada en absoluto). _

No entiendo por qué usarlo de esta manera que lo hizo, sería mejor así:

function SnapShotDOM(target,call){
    var data = {};

    //use jquery or getComputedStyle|style.overflow
    data.overflow = /*get overflow property*/;
    data.width = /*get width property*/;
    data.height = /*get height property*/;
    data.maxWidth = /*get maxWidth property*/;
    data.maxHeight = /*get maxHeight  property*/;

    target.style.overflow="visible !important";
    target.style.height="auto !important";
    target.style.maxHeight="auto !important";

    html2canvas(target, {
        "onrendered": function(canvas) {
            target.style.overflow = data.overflow;
            target.style.width = data.width;
            target.style.height = data.height;
            target.style.maxWidth = data.maxWidth;
            target.style.maxHeight = data.maxHeight;
            call(canvas);
        }
    });
}

SnapShotDOM(document.body,function(canvas){
    console.log(canvas);
});

o use la clase:

<style>
*.html2canvasreset{
    overflow: visible !important;
    width: auto !important;
    height: auto !important;
    max-height: auto !important;
}
</style>
<script>
function SnapShotDOM(target,call){
    var data = target.className;
    target.className += " html2canvasreset";//set className - Jquery: $(target).addClass("html2canvasreset");
    html2canvas(target, {
        "onrendered": function(canvas) {
            target.className = data;//old className - Jquery: $(target).removeClass("html2canvasreset");
            call(canvas);
        }
    });
}

SnapShotDOM(document.body,function(canvas){
    console.log(canvas);
});
</script>

La razón por la que no pongo nada relacionado con el desbordamiento en onrendered es porque el tiempo entre el análisis y la renderización puede ser notable, y es preferible restablecer el desbordamiento lo antes posible (es decir, justo después del análisis, antes de la renderización) para evitar un destello visible de contenido. Poner el reinicio de desbordamiento en onparsed lugar logra esto.

Me refería a "onpreloaded".

prueba esto:

function SnapShotDOM(target,call){
    var data = target.className;
    target.className += " html2canvasreset";//set className - Jquery: $(target).addClass("html2canvasreset");
    html2canvas(target, {
        "onparsed": function() {
            target.className = data;//old className - Jquery: $(target).removeClass("html2canvasreset");
        },
        "onrendered": function(canvas) {
            call(canvas);
        }
    });
}

SnapShotDOM(document.body,function(canvas){
    console.log(canvas);
});

Mi uso de onpreloaded es por la misma razón: es una optimización que me permite mover la parte de des-ocultar de desbordamiento al último momento posible, justo antes del paso de análisis, minimizando así la cantidad de tiempo durante el cual el contenido es completamente visible en la pantalla. Puedes ver cómo funciona esto en el código aquí y aquí .

@niklasvh , ¿este problema está relacionado con el TODO que se encuentra aquí ( options.useOverflow )?

¿Qué versión usaron ustedes? ... puedo encontrar el método onparsed y onpreloaded en mi versión ..
estoy usando html2canvas-0.5.0-alpha1

@ejlocop Este problema se presentó hace años para una versión anterior y puede no ser relevante para su caso de uso (# 511).

¿Resolvieron el problema? paraa solution Estoy buscando algo con mi diagrama de Gantt, te necesito completamente ...
overflow

@pkpatels ¿
También tuve este problema y la solución que funcionó para mí es la sugerida en: # 117

@uriklar Funciona para el desplazamiento horizontal, no para el vertical. Echa un vistazo a mi div. Allí hay tres elementos diferentes.

@uriklar, la solución que sugieres tampoco funciona cuando me desplazo hacia abajo en el div y hago clic en totalmente visible.
screen shot 2016-03-16 at 1 41 09 pm

¿Qué hay de establecer la altura de #text div en automático antes de renderizar y restablecerlo después? Que funcionará.

Seguía teniendo problemas de desbordamiento en la versión más reciente (0.5.0-beta4). Tomé la solución alternativa de @usmonster y la adapté a los cambios recientes en h2c y Promises (como se describe en la nota de @usmonster ):

Nota: La solución alternativa mencionada anteriormente no funcionaría con la versión más reciente que se encuentra actualmente en la versión maestra. No lo he probado, pero parece que necesitaría hacer uso de la opción oncloned en su lugar, y ahora se llamaría al reinicio principal de desbordamiento en su devolución de llamada a .then (). (También debería ser posible hacer visible exclusivamente el desbordamiento del padre dentro del documento clonado y no preocuparse por restablecer nada en absoluto).

Entonces, sin alterar el DOM real de su página web, puede alterar el documento clonado usado para renderizar por h2c utilizando la devolución onclone llamada

var renderingPromise = html2canvas($(item), {
    width: item.clientWidth,
    height: item.clientHeight,
    onclone: function(clone) {
            $(clone).find('.grid-stack-item-content')
                .css('overflow-x', 'auto')
                .css('overflow-y', 'auto');
        return true;
    }
}).then(
    function(c) {/* success */},
    function() {/* fail */}
);

Lo único que funcionó para mí fue poner el lienzo en un iframe, llamar a html2canvas dentro de eso, llamar a toDataURL () en el lienzo y luego pasar esa imagen a la ventana superior usando una devolución de llamada. Supongo que también podrías devolver un objeto de lienzo.

return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) { if (typeof(options.onrendered) === "function") { log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); options.onrendered(canvas); } return canvas; });
cambiar a
var width = options.width != null ? options.width : node.ownerDocument.defaultView.innerWidth; var height = options.height != null ? options.height+node.ownerDocument.defaultView.innerHeight : node.ownerDocument.defaultView.innerHeight; return renderDocument(node.ownerDocument, options, width, height, index).then(function (canvas) { if (typeof(options.onrendered) === "function") { log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); options.onrendered(canvas); } return canvas; });

Esto puede resolver la pregunta sobre el desbordamiento de la pantalla (tanto en ancho como en alto)

xzw123 tiene una mala solución: configurar ownerDocument.defaultView.innerHeight manualmente hace que se desvincule de los eventos de tamaño de ventana reales. Creo que sería mejor hacer esto en un iframe. Estoy interesado en probar la solución de Jordan.

Jordan, ¿cómo terminaste usando lienzo en un iframe? Lo estoy intentando ahora. Creo que esta debería ser la solución final en html2canvas ... la comunicación iframe debería hacerse invisible externa a la API.

Ah, sí, hacerlo en un iframe con window.postMessage(myData, ... ) funciona. Puede publicar la URL de datos completa de los píxeles renderizados. Simplemente puse mi código de renderizado en el HTML del iframe, pasé los datos necesarios para renderizar la fuente HTML, hice que se renderizara en el lienzo y luego escupiera los datos de toDataUrl.

+1

Hola. Después de buscar soluciones y observar cómo se ejecuta el código, escribo mi propia solución complicada.

https://gist.github.com/simonmysun/c6da13ce2827a374e71ccf07d9f08e2d

Funciona para mí y espero que ayude a alguien que lo necesite.

Sin embargo, todavía espero que pueda ser compatible con esta biblioteca en el futuro.

Todavía no lo entiendo, pero mi problema es que la imagen se corta. cuando se utiliza Chrome Versión 54.0.2840.99 m
(La mitad de la imagen se capturó, pero la otra mitad se quedó en negro)

// the timeline show up 100%, but cut off, cause its static and not dynamic.
// (its cut off from the screen,but the size, and picture show as normal, 100% show)
// after moving to the canvas, everthing that not in the screen will get blank in chrome  
// it depends to the user screen, if i zoom out my chrome, i get 100% image.

pero cuando se usa Mozilla 50.0.2, funciona bien sin alejarse. (Imagen 100%),

No sé por qué.

codigo:

var zenleft = $("#leftPanel").width();  //calculate left side
var zenright = $(".dataPanel").width();  //calculate right side
var after = zenright + zenleft + 250;  // add all

//add the css, even after add overflow still not working
$("#timelineTarget").css({"background-color":"white","width":after});   

 html2canvas(canvTimeline, {
    onrendered: function (canvas) {
            $("#previewImage").html(canvas);
            getCanvas = canvas;
   }
});

image

Finalmente resuelvo este problema agregando

$("body").css({"width": "+="+after}); //after is a total of the width of the element i want to view

asi que

var zenleft = $("#leftPanel").width();  //calculate left side
var zenright = $(".dataPanel").width();  //calculate right side
var after = zenright + zenleft + 250;  // add all
$("body").css({"width": "+="+after});  //add the body

//add the css
$("#timelineTarget").css({"background-color":"white","width":after});   

 html2canvas(canvTimeline, {
    onrendered: function (canvas) {
            $("#previewImage").html(canvas);
            $("#timelineTarget").css({"background-color":"white","width":old});   //turn it back
            $("body").css({"width": "-="+after});   //turn it back
            getCanvas = canvas;
   }
});

Espero que resuelva su propio problema.

onclone tal vez sea el método correcto. Puede cambiar css para obtener lo que desea ...

Hola a todos, tengo div que se puede desplazar. Cuando envío la entrada div como parámetro de lienzo, solo muestra lo que está disponible en la ventana gráfica. Pasé por todas las soluciones. No entendí. ¿Alguien puede decir cómo tomar todo el contenido en div como captura de pantalla?

@ruthraprakash , tuve un problema similar. Esto funciona para mis propósitos simples en la última versión:

function fullhtml2canvas(el) {
    return new Promise(resolve => {
        html2canvas(el, {
            width: el.scrollWidth,
            height: el.scrollHeight,
        }).then(canvas => {
            resolve(canvas);
        });
    });
}

Tengo un problema al tomar una captura de pantalla del gráfico de la línea de tiempo. No obtengo el valor del eje x. simplemente está creando la imagen del gráfico de línea de tiempo.
`demoFromHTML (e) {
e.preventDefault ();

  let input = window.document.getElementById('divToPDF');


  html2canvas(input)
  .then((canvas) => {

    const imgData = canvas.toDataURL('image/jpeg');

    const pdf = new pdfConverter("l", "pt");
    pdf.addImage(imgData, 'JPEG', 15, 110, 800, 250);
    pdf.save('test.pdf');
  });


}

'

Lo intenté durante mucho tiempo ... Pero crea muchos problemas ... No pude lograr lo que dijiste. Descubrí que funciona bien cuando es 'cuerpo' incluso si hay desplazamiento ... Quiero lograr lo mismo para un div que tiene elementos con desplazamiento ... Si pudiera ayudarme con este problema, sería de gran ayuda para mí ... Espero sus comentarios ...

Por favor, ¿puedes mostrarme cómo conseguiste que tu cuerpo funcionara?

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

kunal886496 picture kunal886496  ·  3Comentarios

celik75 picture celik75  ·  4Comentarios

wbarrantes picture wbarrantes  ·  3Comentarios

ABHIKSINGHH picture ABHIKSINGHH  ·  3Comentarios

tibewww picture tibewww  ·  4Comentarios