Search code examples
javascripthtmljquerycssscreenshot

Background image captures in half after using DomToImage


So I'm trying out Dom-to-Image but ran into a deadend. I have this div with a fixed width and height of 700px and 500px respectively. This is the div which I want to take a screenshot of with Dom-to-Image plugin.

When the div is left-aligned on the viewport, the screen capture is perfect and I can download the image. But if I make the div center with margin: 0 auto;, then I get one-third of the screenshot and not the full image.

Here's the issue when it is centered:

enter image description here

What I want:

No matter where my div is placed, I only want to take the screenshot of that full div. How can I do that?

Here's the code:

$(document).ready(() => {
    const imgDiv                    = document.querySelector('#div');
    const downloadBtn               = document.querySelector('#download');


   $(downloadBtn).click(() => {
          domtoimage.toBlob(imgDiv).then( blob => {
                saveAs(blob, 'myImage.png');
          });
   });
   
   
});
#div {
    width: 700px;
    height: 500px;
    background-image: url('https://img.glyphs.co/img?q=85&w=900&src=aHR0cHM6Ly9zMy5tZWRpYWxvb3QuY29tL3Jlc291cmNlcy9HZW9tZXRyaWMtQmFja2dyb3VuZC1QYXR0ZXJucy1QcmV2aWV3LTJiLmpwZw==');
    background-position: center center;
    background-size: cover;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0 auto;
}


.text-block {
    display: flex;
    flex-direction: column;
    z-index: 9999;
}

.text,
.name {
    color: #fff;
    text-align: center;
    margin: 0;
}

.text {
    padding: 0 40px;
    margin-bottom: 20px;
    font-size: 15px;
}

.name {
    font-size: 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div id="div">
     <div class="text-block">
          <p class="text">Booooooooooooooossss </p>
          <p class="name">s</p>
     </div>
</div>

<button id="download">Download</button>


Solution

  • As said in the docs:

    This library uses a feature of SVG that allows having arbitrary HTML content inside of the <foreignObject> tag.

    So it basically copies the element with the css applied to it and runs them again within the <foreignObject>.

    I assume this is done as such in case there's a background or some kind of coloration applied to the element, They probably didn't think much about the css properties that would alter placement or I just didn't read everything in the documentation.

    With that said, To avoid this You will have to nest your element.

    All your css property that alter the position of the element should be put on the container, everything else can stay on the DOM element you want to convert to an image.

    var NodeToImage = document.querySelector('[NodeToImage]');
    
    
    domtoimage.toPng(NodeToImage)
      .then(function(dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
      })
      .catch(function(error) {
        console.error('oops, something went wrong!', error);
      });
    /* Container to nest the DOM element */
    /* margin is applied to it instead*/
    [ctr] {
      width: 100px;
      height: 100px;
      margin: 20px;
    }
    
    
    /* This is the DOM element to be converted */
    [NodeToImage] {
      background: orange;
      height: 100%;
      /* To match the height */
    }
    
    img {
      border: 1px solid;/* For the preview*/
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js" integrity="sha512-01CJ9/g7e8cUmY0DFTMcUw/ikS799FHiOA0eyHsUWfOetgbx/t6oV4otQ5zXKQyIrQGTHSmRVPIgrgLcZi/WMA==" crossorigin="anonymous"></script>
    
    
    <div ctr>
      <div NodeToImage></div>
    </div>


    Side Note: I tried to look through the issues on Github, and couldn't find anything related to this, maybe i missed it. You might want to make one