Html2canvas: Comment rendre plein de partie cachée dans 'overflow:auto' div

Créé le 22 févr. 2012  ·  34Commentaires  ·  Source: niklasvh/html2canvas

J'ai un div qui contient tous les éléments qui doivent être convertis en image. Et ce div est défini sur ' overflow:auto '. Je veux savoir comment je peux exporter tous les éléments (même cachés dans le défilement) vers une image. J'apprécie et accueille tous vos commentaires et réponses...... Merci d'avance...

Commentaire le plus utile

@ruthraprakash , j'ai eu un problème similaire. Cela fonctionne pour mes besoins simples sur la dernière version :

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

Tous les 34 commentaires

Il n'y a actuellement pas d'option pour rendre la page avec des options spécifiques, vous devrez donc modifier la page pour qu'elle ressemble à la façon dont vous souhaitez qu'elle s'affiche.

En d'autres termes, si vous supprimez la limite de hauteur/largeur, exécutez html2canvas, puis redéfinissez la hauteur/largeur à sa valeur, vous devriez obtenir ce que vous recherchez.

Merci beaucoup.... je vais essayer ce que vous m'avez dit...

J'ai essayé pendant longtemps... Mais ça fait beaucoup de problème... Je n'ai pas pu réaliser ce que vous avez dit. J'ai découvert que cela fonctionnait bien quand il s'agissait de "corps" même s'il y avait un défilement... Je veux obtenir la même chose pour un div qui a des éléments avec défilement... Si vous pouviez m'aider avec ce problème, ce serait d'une grande aide pour moi... J'attends vos commentaires avec impatience...

@niklasvh , j'ai le même problème, et les seules solutions de contournement que j'ai sont soit de réduire la largeur de l'élément cible avant l'appel à html2canvas (pas toujours une option), soit d'appeler html2canvas deux fois de suite sur le même élément. Voici un violon pour illustrer le problème :

http://jsfiddle.net/fMeRC/1/ (cet exemple particulier fonctionne uniquement pour Chrome ; vous devez jouer avec la largeur pour voir le problème dans d'autres navigateurs)

Cela ne se produit essentiellement que lorsque l'élément est plus large que la fenêtre ou (document.width - 8) , je ne sais pas lequel a la pertinence la plus importante/directe, et cela peut changer sur d'autres navigateurs).

Probablement liés : #199 et #108.

J'ai essayé childElement ou défini "overflow=visible" et après défini "overflow=auto|hidden|inherit" ?

childElement sans style, uniquement pour recevoir le contenu du div avec débordement :

<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)],...)

Merci pour les suggestions, @brcontainer. J'avais essayé l'approche overflow: visible -> html2canvas( ... ) -> overflow: [old overflow] , bien que le flash du contenu caché/non caché/à nouveau caché (peut-être parce que mon élément cible est relativement complexe). Bien que je viens de proposer une variante légèrement optimisée de la solution de contournement qui semble faire une différence à cet égard :

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

Cela définit le débordement sur « visible » uniquement pour (ce que je pense être) le temps le plus court nécessaire pour que h2c analyse correctement la cible, éliminant ainsi presque entièrement le flash, du moins dans mon cas. C'est-à-dire que nous n'avons plus à attendre la fin de l'étape de rendu du canevas avant de réinitialiser/masquer à nouveau le débordement. Je ne sais pas si cette approche modifiée fonctionnera pour tout le monde, mais je pense que c'est une solution de contournement plus intéressante que d'appeler html2canvas( ... ) deux fois de suite ou d'ajouter des éléments supplémentaires au DOM pour envelopper le contenu cible.

En tout cas, cela reste un vrai bug que j'aimerais voir correctement corrigé. (D'autant plus qu'aucune solution de contournement ne semble fonctionner correctement pour moi dans IE9 et 10, au moins - je n'ai pas essayé dans IE11.)

_Remarque : La solution de contournement susmentionnée ne fonctionnerait pas avec la version la plus récente actuellement en mode maître. Je n'ai pas testé, mais il semble que vous deviez utiliser l'option oncloned place, et la réinitialisation du parent de débordement serait désormais appelée dans votre rappel à .then() . (Il devrait également être possible de rendre exclusivement visible le débordement du parent dans le document cloné et de ne pas se soucier de réinitialiser quoi que ce soit.)_

Je ne comprends pas pourquoi tu l'utilises comme ça, ce serait mieux comme ça :

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);
});

ou utiliser la classe :

<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 raison pour laquelle je ne mets rien concernant le débordement dans onrendered est que le temps entre l'analyse et le rendu peut être perceptible, et il est préférable de réinitialiser le débordement dès que possible (c'est-à-dire juste après l'analyse, avant le rendu) pour éviter un flash visible de contenu. Mettre la réinitialisation de débordement dans onparsed accomplit cela à la place.

Je parlais de "onpreloaded".

essaye ça:

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);
});

Mon utilisation de onpreloaded est pour la même raison - c'est une optimisation qui me permet de déplacer la partie de démasquage de débordement au dernier moment possible, juste avant l'étape d'analyse, minimisant ainsi le temps pendant lequel le contenu est entièrement visible à l'écran. Vous pouvez voir comment cela fonctionne dans le code ici et ici .

@niklasvh , ce problème est-il lié au TODO trouvé ici ( options.useOverflow ) ?

quelle version avez-vous utilisé? .. je peux trouver la méthode onparsed et onpreloaded dans ma version ..
j'utilise html2canvas-0.5.0-alpha1

@ejlocop Ce problème a été

Ils ont résolu le problème ? paraa solution Je cherche quelque chose avec mon diagramme de Gantt , j'ai besoin de vous complètement ...
overflow

ça ne fonctionne pas.

http://jsfiddle.net/fMeRC/368/

@pkpatels Pourquoi ne pas travailler ? J'ai passé ton violon et les phrases ont été rendues sans coupure...
J'ai également eu ce problème et la solution qui a fonctionné pour moi est celle suggérée dans : 117

@uriklar Cela fonctionne pour le défilement horizontal et non pour le vertical. Consultez ma div. Il y a là trois éléments différents.

@uriklar, la solution que vous proposez ne fonctionne pas non plus lorsque je fais défiler le div et que je clique sur totalement visible.
screen shot 2016-03-16 at 1 41 09 pm

Qu'en est-il de la définition de la hauteur de #text div sur auto avant le rendu et de sa réinitialisation après ? Ça marchera.

J'avais toujours des problèmes de débordement dans la version la plus récente (0.5.0-beta4). J'ai pris la solution de contournement de @usmonster et je l' ai adaptée aux modifications récentes apportées à h2c et Promises (comme décrit dans la note de @usmonster ):

Remarque : La solution de contournement susmentionnée ne fonctionnerait pas avec la version la plus récente actuellement en mode maître. Je n'ai pas testé, mais il semble que vous deviez utiliser l'option oncloned à la place, et la réinitialisation du parent de débordement serait désormais appelée dans votre rappel à .then(). (Il devrait également être possible de rendre exclusivement le débordement du parent visible à l'intérieur du document cloné et de ne pas se soucier de réinitialiser quoi que ce soit.)

Ainsi, sans modifier le DOM réel de votre page Web, vous pouvez modifier le document cloné utilisé pour le rendu par h2c en utilisant le rappel onclone . C'est assez simple en fait, voici mon appel h2c :

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 */}
);

La seule chose qui a fonctionné pour moi a été de placer le canevas dans un iframe, d'appeler html2canvas à l'intérieur, d'appeler toDataURL() sur le canevas, puis de renvoyer cette image à la fenêtre supérieure à l'aide d'un rappel. Je suppose que vous pouvez également renvoyer un objet canvas.

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; });
changer pour
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; });

Cela peut résoudre la question du débordement de l'écran (largeur et hauteur)

xzw123 a une mauvaise solution : la définition manuelle de ownerDocument.defaultView.innerHeight provoque sa dissociation des événements réels de dimensionnement de la fenêtre. Je pense qu'il serait préférable de le faire dans un iframe. J'ai hâte d'essayer la solution de Jordan.

Jordan, comment en êtes-vous arrivé à utiliser canvas dans un iframe ? Je l'essaye maintenant. Je pense que cela devrait être la solution finale dans html2canvas... la communication iframe devrait être rendue invisible à l'extérieur de l'API.

Ah oui, le faire dans un iframe avec window.postMessage(myData, ... ) fait l'affaire. Vous pouvez publier l'intégralité de l'URL des données des pixels rendus. Je viens de mettre mon code de rendu dans le code HTML de l'iframe, de transmettre les données nécessaires au rendu de la source HTML, de le rendre sur canvas, puis de lui faire recracher les données toDataUrl.

+1

Salut. Après avoir recherché des solutions et observé le fonctionnement du code, j'écris ma propre solution délicate.

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

Cela fonctionne pour moi et j'espère que cela aidera quelqu'un qui en a besoin.

Cependant, j'espère toujours qu'il pourra être pris en charge dans cette bibliothèque à l'avenir.

Je ne comprends toujours pas, mais pour mon problème, l'image est coupée. lors de l'utilisation de Chrome Version 54.0.2840.99 m
(la moitié de l'image a été capturée, mais l'autre moitié a un écran noir)

// 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.

mais lors de l'utilisation de Mozilla 50.0.2, cela fonctionne bien sans zoom arrière. (100% images),

je ne sais pas pourquoi.

code :

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

Enfin, je résous ce problème en ajoutant

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

donc

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;
   }
});

espérons que cela résoudra votre propre problème.

onclone est peut-être la bonne méthode. Vous pouvez changer le css pour obtenir ce que vous voulez...

Salut à tous, j'ai div qui est scrollable. Lorsque j'envoie l'entrée div en tant que paramètre de toile, cela ne fait que rendre ce qui est disponible dans la fenêtre d'affichage. J'ai parcouru toutes les solutions. Je n'ai pas compris. Quelqu'un peut-il dire comment prendre tout le contenu en div comme capture d'écran.

@ruthraprakash , j'ai eu un problème similaire. Cela fonctionne pour mes besoins simples sur la dernière version :

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

J'ai un problème avec la capture d'écran du graphique chronologique. Je ne reçois pas la valeur de l'axe x. il crée simplement l'image du graphique de la chronologie.
` 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');
  });


}

`

J'ai essayé pendant longtemps... Mais ça fait beaucoup de problème... Je n'ai pas pu réaliser ce que vous avez dit. J'ai découvert que cela fonctionnait bien quand il s'agissait de "corps" même s'il y avait un défilement... Je veux obtenir la même chose pour un div qui a des éléments avec défilement... Si vous pouviez m'aider avec ce problème, ce serait d'une grande aide pour moi... J'attends vos commentaires avec impatience...

S'il te plait, peux-tu me montrer comment tu as réussi à faire travailler ton corps

Cette page vous a été utile?
0 / 5 - 0 notes