Html2canvas: Como renderizar cheio de partes ocultas em div 'overflow: auto'

Criado em 22 fev. 2012  ·  34Comentários  ·  Fonte: niklasvh/html2canvas

Eu tenho uma div que contém todos os elementos que precisam ser convertidos em uma imagem. E esse div é definido como ' overflow: auto '. Quero saber como posso exportar todos os elementos (mesmo ocultos na rolagem) para uma imagem. Agradeço e agradeço todos os seus comentários e respostas ...... Agradecemos antecipadamente ...

Comentários muito úteis

@ruthraprakash , tive um problema semelhante. Isso funciona para meus objetivos simples na versão mais recente:

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

Todos 34 comentários

Atualmente não há uma opção para renderizar a página com opções específicas, então você precisará modificar a página para ter a aparência que deseja renderizar.

Em outras palavras, se você remover o limite de altura / largura, executar html2canvas e, em seguida, definir a altura / largura de volta para o valor que estava, você deve alcançar o que está procurando.

Muito obrigado .... Vou tentar o que você disse ...

Eu tentei muito tempo ... Mas dá muito trabalho ... Não consegui o que você falou. Descobri que funciona bem quando é 'corpo' mesmo se houver rolagem ... Quero fazer o mesmo para uma div que tem elementos com rolagem ... Se você pudesse me ajudar com esse problema, seria de grande ajuda para mim ... Aguardo seus comentários ...

@niklasvh , estou tendo o mesmo problema e as únicas soluções alternativas que tenho são reduzir a largura do elemento de destino antes da chamada para html2canvas (nem sempre uma opção) ou chamar html2canvas duas vezes seguidas no mesmo elemento. Aqui está um violino para demonstrar o problema:

http://jsfiddle.net/fMeRC/1/ (este exemplo em particular funciona apenas para o Chrome; você precisa mexer na largura para ver o problema em outros navegadores)

Basicamente, isso só acontece quando o elemento é mais largo que a janela ou (document.width - 8) , não tenho certeza de qual tem a relevância mais importante / direta, e isso pode mudar em outros navegadores).

Provavelmente relacionado: # 199 e # 108.

ChildElement tentou ou definir "overflow = visible" e depois definir "overflow = auto | hidden | inherit"?

childElement sem estilo, apenas para receber o conteúdo da div com estouro:

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

Obrigado pelas sugestões, @brcontainer. Eu tentei a abordagem overflow: visible -> html2canvas( ... ) -> overflow: [old overflow] , embora o flash do conteúdo oculto / não oculto / oculto novamente fosse muito perceptível (possivelmente porque meu elemento de destino é relativamente complexo). Embora eu apenas tenha criado uma variante ligeiramente otimizada da solução alternativa que parece fazer a diferença nesse aspecto:

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

Isso define o estouro para 'visível' apenas por (o que eu acho) o menor período de tempo necessário para que o h2c analise corretamente o alvo, eliminando assim o flash quase que totalmente, pelo menos no meu caso. Ou seja, não precisamos mais esperar a etapa de renderização da tela terminar antes de redefinir / ocultar novamente o estouro. Não tenho ideia se essa abordagem modificada funcionará para todos, mas acho que é uma solução mais agradável do que chamar html2canvas( ... ) duas vezes seguidas ou adicionar coisas extras ao DOM para envolver o conteúdo de destino.

Em qualquer caso, este ainda é um bug real que eu gostaria de ver devidamente corrigido. (Especialmente porque nenhuma solução alternativa parece funcionar corretamente para mim no IE9 e 10, pelo menos - não tentei no IE11.)

_Observação: a solução alternativa mencionada anteriormente não funcionaria com a versão mais recente que está atualmente em master. Eu não testei, mas parece que você precisaria usar a opção oncloned vez disso, e a redefinição do pai de estouro agora seria chamada em seu retorno de chamada para .then() . (Também deve ser possível tornar exclusivamente o estouro do pai visível dentro do documento clonado e não se preocupar em redefinir nada.) _

Não estou entendendo porque usar dessa forma que você fez, seria melhor assim:

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 use a 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>

O motivo pelo qual não coloquei nada relacionado ao estouro em onrendered é porque o tempo entre a análise e a renderização pode ser perceptível, e redefinir o estouro o mais rápido possível (ou seja, logo após a análise, antes da renderização) é preferível para evitar um flash visível de conteúdo. Colocar a redefinição de estouro em onparsed vez disso, faz isso.

Eu estava me referindo a "onpreloaded".

tente isto:

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

Meu uso de onpreloaded é pelo mesmo motivo - é uma otimização que me permite mover a parte de não ocultar do overflow para o último momento possível, logo antes da etapa de análise, minimizando assim a quantidade de tempo para o qual o conteúdo é totalmente visível na tela. Você pode ver como isso funciona no código aqui e aqui .

@niklasvh , este problema está relacionado ao TODO encontrado aqui ( options.useOverflow )?

qual versão vocês usaram? .. posso encontrar o método onparsed e onpreloaded na minha versão ..
estou usando html2canvas-0.5.0-alpha1

@ejlocop Este problema foi registrado anos atrás para uma versão anterior e pode não ser relevante para o seu caso de uso (# 511).

Eles resolveram o problema? paraa solução Estou procurando algo com meu gráfico de Gantt, preciso de você completamente ...
overflow

não está funcionando.

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

@pkpatels Por que não está funcionando? Corri seu violino e as frases foram reproduzidas sem cortar ...
Eu também tive esse problema e a solução que funcionou para mim é a sugerida em: # 117

@uriklar Está funcionando para rolagem horizontal, não vertical. Verifique meu div. Existem três elementos diferentes aí.

@uriklar a solução que você sugeriu também não está funcionando quando eu role para baixo na div e clico em totalmente visível.
screen shot 2016-03-16 at 1 41 09 pm

Que tal definir a altura de #text div para automático antes de renderizar e redefini-la depois? Isso vai funcionar.

Eu ainda estava tendo problemas com estouro na versão mais recente (0.5.0-beta4). Peguei a solução alternativa de @usmonster ):

Observação: a solução alternativa mencionada anteriormente não funcionaria com a versão mais recente que está atualmente em master. Eu não testei, mas parece que você precisaria usar a opção oncloned em vez disso, e a redefinição do pai de estouro agora seria chamada em seu retorno de chamada para .then (). (Também deve ser possível tornar exclusivamente o estouro do pai visível dentro do documento clonado e não se preocupar em redefinir nada.)

Portanto, sem alterar o DOM real da sua página da web, você pode alterar o documento clonado usado para renderização por h2c utilizando o retorno de chamada onclone . Na verdade, é muito simples, aqui está minha chamada 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 */}
);

A única coisa que funcionou para mim foi colocar a tela em um iframe, chamar html2canvas dentro dele, chamar toDataURL () na tela e, em seguida, passar essa imagem de volta para a janela superior usando um retorno de chamada. Suponho que você também possa devolver um objeto de tela.

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

Isso pode resolver a questão sobre o estouro da tela (largura e altura)

xzw123 tem uma solução ruim: definir ownerDocument.defaultView.innerHeight manualmente faz com que ele se desvincule dos eventos de dimensionamento de janela reais. Acho que seria melhor fazer isso em um iframe. Estou interessado em tentar a solução de Jordan.

Jordan, como você acabou usando canvas em um iframe? Estou tentando agora. Acho que essa deve ser a solução final em html2canvas ... a comunicação iframe deve ser invisível externamente à API.

Ah, sim, fazer isso em um iframe com window.postMessage(myData, ... ) resolve. Você pode postar de volta todo o url de dados dos pixels renderizados. Acabei de colocar meu código de renderização no HTML do iframe, passei os dados necessários para renderizar o código-fonte HTML, fiz a renderização na tela e depois cuspi os dados toDataUrl de volta.

+1

Oi. Depois de pesquisar soluções e observar como o código é executado, escrevo minha própria solução complicada.

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

Funciona para mim e espero que ajude alguém que precise.

No entanto, ainda espero que possa ser suportado nesta biblioteca no futuro.

Ainda não entendi, mas meu problema é que a imagem foi cortada. ao usar o Chrome Versão 54.0.2840.99 m
(metade da imagem foi capturada, mas a outra metade ficou com a tela preta)

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

mas ao usar o Mozilla 50.0.2, está funcionando bem sem diminuir o zoom. (Imagem 100%),

eu não sei porque.

código:

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, resolvo esse problema adicionando

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

tão

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 isso resolva seu próprio problema.

onclone talvez seja o método correto. Você pode alterar o css para obter o que deseja ....

Olá, todos. Tenho div que pode ser rolado. Quando eu envio a entrada div como parâmetro de tela, ele apenas renderiza o que está disponível no visor. Passei por todas as soluções. Eu não entendi. Alguém pode dizer como tirar todo o conteúdo em div como captura de tela.

@ruthraprakash , tive um problema semelhante. Isso funciona para meus objetivos simples na versão mais recente:

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

Eu tenho um problema ao fazer uma captura de tela do gráfico de linha do tempo. Não estou obtendo o valor do eixo x. é apenas criar a imagem do gráfico de linha do tempo.
`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');
  });


}

`

Eu tentei muito tempo ... Mas dá muito trabalho ... Não consegui o que você falou. Descobri que funciona bem quando é 'corpo' mesmo se houver rolagem ... Quero fazer o mesmo para uma div que tem elementos com rolagem ... Se você pudesse me ajudar com esse problema, seria de grande ajuda para mim ... Aguardo seus comentários ...

Por favor, você pode me mostrar como você fez o corpo funcionar

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

yasergh picture yasergh  ·  5Comentários

koreanman picture koreanman  ·  4Comentários

stevencherry1 picture stevencherry1  ·  3Comentários

arzyu picture arzyu  ·  3Comentários

bishwapoudel picture bishwapoudel  ·  4Comentários