Recentemente, fui encarregado de implementar a lógica que captura componentes de reação com suas visualizações de dados na página da web e os exporta como uma imagem. Outras bibliotecas de visualização de dados (como Highcharts ) permitem que os gráficos sejam exportados como uma imagem. No entanto, precisávamos de um para exportar vários gráficos e tabelas em uma página de uma vez.
É aqui que o html2canvas se torna útil.
Este pacote gera uma “captura de tela” lendo os elementos DOM, seus estilos e, em seguida, gerando uma imagem de tela a partir desses dados. Ele opera puramente no lado do cliente, então você não precisa se preocupar com nenhuma solicitação / suporte do servidor.
Primeiro, instale o pacote npm.
npm i html2canvas
import html2canvas from "html2canvas";
const capture = () => {
  html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
  });
}
Essa biblioteca foi ótima para meu caso de uso, exceto por uma ressalva.
Se houvesse algum estouro horizontal , ele capturaria apenas o que estava visível. Qualquer parte do elemento DOM oculta por uma rolagem de estouro foi cortada.
Isso significava que eu precisava compensar quaisquer visualizações de dados que estavam ocultas quando a página foi redimensionada. Eu poderia simplesmente empilhar as visualizações verticalmente, mas isso pode ser complicado.
1. Expectativas de gerenciamento de projetos
Mudanças nas especificações acordadas durante um sprint normalmente não são ideais (a menos que não haja absolutamente nenhuma maneira de acomodar uma pergunta em um determinado período de tempo). Uma vez que a solicitação foi acordada, a alteração do layout seria prejudicial ao processo de desenvolvimento e exigiria mais discussão (mais reuniões, mais tempo) com a equipe de produto e designers.
2. Experiência do usuário
Há um bom motivo pelo qual a IU original foi projetada e aceita em primeiro lugar. Um layout puramente vertical não é ideal quando você tem várias visualizações, tabelas de acompanhamento, etc. em uma página e quando o aplicativo não é móvel primeiro. A comparação lado a lado é mais difícil e a imagem exportada acabará sendo muito alta e, portanto, nem sempre será o layout ideal para, digamos, apresentações do PowerPoint.
Então, como consegui manter a IU existente como está, ao mesmo tempo que capturava todos os dados pertinentes (mesmo que estivessem momentaneamente ocultos)? Minha solução é um pouco heterodoxa (e um pouco anti-padrão de reação), mas me inspirei em uma pergunta no Stack Overflow .
Basicamente, o que eu precisava fazer era temporariamente tornar as tags htmle bodygrandes o suficiente para acomodar as visualizações de dados sem que o contêiner ocultasse nada disso. Quando estiver grande o suficiente, capture os dados, gere a imagem da tela e, em seguida, defina as tags htmle de bodyvolta ao seu tamanho original.
O dimensionamento precisava ser dinâmico, em vez de apenas definir uma largura estática grande o suficiente para acomodar a maioria dos casos (não preciso que meu contêiner tenha 10.000 pixels de largura se eu tiver apenas dois itens para visualizar). Em alguns casos, o contêiner não precisará ser redimensionado. Então, como posso acomodar a largura de um, dois, dez ou mais itens que precisam ser visualizados?
Aqui está minha função.
const exportAsPicture = () => {
var html = document.getElementsByTagName('HTML')[0]
  var body =  document.getElementsByTagName('BODY')[0]
  var htmlWidth = html.clientWidth;
  var bodyWidth = body.clientWidth;
  var data = document.getElementById('exportContainer')
  var newWidth = data.scrollWidth - data.clientWidth
if (newWidth > data.clientWidth){
    htmlWidth += newWidth
    bodyWidth += newWidth
  }
html.style.width = htmlWidth + 'px'
  body.style.width = bodyWidth + 'px'
html2canvas(data).then((canvas)=>{
    var image = canvas.toDataURL('image/png', 1.0);
    var fileName = currentExport.split("Export")[0] + '.png'
    saveAs(image, fileName)
  })
}
scrollWidth é o valor igual à largura mínima que o elemento exigiria para caber todo o conteúdo na janela de visualização sem usar uma barra de rolagem horizontal (ou seja, a largura do meu contêiner se ele não estourasse).
Então, por que precisamos desses dois valores? Como quero que a mudança de largura seja dinâmica (em relação ao número de itens que precisam de visualizações), quero comparar o clientWidthcom o scrollWidthpara ver se preciso mesmo mudar a largura.
Se não clientWidth for menor do que (não há nenhuma parte do contêiner que está transbordando / oculta), então eu apenas mantenho a largura de e como está. Se é menos do que (não é uma parte do recipiente que está escondido) I vai precisar adicionar a diferença entre e com a largura de ambos os e .scrollWidthhtmlbodyclientWidth scrollWidthscrollWidthclientWidthhtmlbody
Uma vez que as larguras são grandes o suficiente, eu uso html2canvaspara capturar os elementos DOM dentro do contêiner, gerar um elemento de tela e, em seguida, crio um DataURL a partir do elemento de tela viacanvas.toDataURL(‘image/png’, 1.0).
canvasToDataURLretorna um URI de dados contendo uma representação da imagem no formato especificado pelo typeparâmetro (o padrão é PNG ). A imagem retornada está em uma resolução de 96 dpi. O 1.0que adicionei é uma opção de codificador para determinar a qualidade da imagem (entre 0 e 1). O valor retornado de canvasToDataURLserá parecido com o abaixo.
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABPMAAAXSCAYAAAB956qJAAAgAElEQVR4XuydB7QkRfWHi7jknDNIFgQEJAclCgiSRRABJSNBcpYcVCQoUaLkj...
const saveAs = (blob, fileName) =>{
  var elem = window.document.createElement('a');
  elem.href = blob
  elem.download = fileName;
  elem.style = 'display:none;';
  (document.body || document.documentElement).appendChild(elem);
  if (typeof elem.click === 'function') {
    elem.click();
  } else {
    elem.target = '_blank';
    elem.dispatchEvent(new MouseEvent('click', {
      view: window,
      bubbles: true,
      cancelable: true
    }));
  }
  URL.revokeObjectURL(elem.href);
  elem.remove()
}
E aí está. Agora você pode começar a baixar os componentes do Rea como imagens com html2canvase o código acima. O código que acompanha esta postagem está disponível no GitHub .
Referências
Mais conteúdo em plainenglish.io
Suggested posts
O que é Consciência: A Metáfora da Chama
O que é consciência? É uma questão que intriga filósofos e cientistas há séculos. Alguns dizem que é uma coisa efêmera que não podemos entender genuinamente, independente de nossos corpos.
Como se tornar um desenvolvedor Blockchain
O roteiro para se tornar um desenvolvedor de blockchain.
Com um salário médio de US$ 154 mil por ano e crescimento constante de empregos, agora é o momento ideal para aprender o desenvolvimento de blockchain. Para criar e melhorar as tecnologias blockchain, os desenvolvedores de blockchain exercitam várias habilidades, incluindo redes de computadores, criptografia, algoritmos e estruturas de dados.
Related posts
Basta um momento de silêncio para encontrar a felicidade – a perspectiva de um budista.
Este é o meu próprio insight pessoal sobre a natureza da felicidade e sua conexão com o silêncio. Por que não somos felizes? No mundo materialista em que vivemos hoje, constantemente nos encontramos sem energia, levando a estados mentais negativos ou apenas infelizes.
Pensamentos para canalizar seu processo criativo do livro “A Grande Magia”
aqui está como você pode fazer amizade com a criatividade e fazer o relacionamento durar muito…
Como criadores de conteúdo, um dos maiores desafios que enfrentamos é ser criativo. Quando se trata do campo da escrita, cada criador de conteúdo se distingue muito pela criatividade de seu processo de pensamento e pela exclusividade de seu conteúdo.
8 ideias simples de configuração de home office para aumentar a produtividade do seu trabalho
Dominando a arte da configuração do home office! Os desenvolvedores AppExert dominam a arte de trabalhar em casa, mesmo quando toda a família permanece junta. Isso nos levou de volta à memória de quando nossos avós ou bisavós viviam em famílias conjuntas.
Por que eu corro para a música?
Quantas pessoas dizem, “música heavy metal? Não é isso que faz você querer cortar os pulsos? Bem, na verdade, é o contrário. Pode ser sobre usar a música e a letra para converter emoções negativas em uma experiência mais positiva.