Friday, 15 September 2023

How to dynamically adjust the dimensions of a canvas based on the content inside a scrollable div?

I'm using PDF JS in a Vue3 project and I want to overlay a <canvas id="draw_canvas"> on the rendered pdf document. Thus, allowing me to programmatically draw rectangles over the pdf document as an attempt to place a marker on certain places.

The way PDF JS renders a pdf file is by placing the content of each page inside individual <canvas> elements. I have 2 Vue SFCs called App and Child. The Child component loads and renders the pages of the pdf document (3 pages) inside a <div id="pages_container">. This div is enclosed inside another one, <div id="doc_container">, which is made scrollable.

To adjust the height of <canvas id="draw_canvas"> whenever <div id="pages_container"> grows, I'm using a ResizeObserver. This observes the <div id="pages_container"> for changes in size and then adjusts the height of the <canvas id="draw_canvas"> to match its offsetHeight.

// Child.vue

<script setup>
import { onMounted } from 'vue';

// function to load pdf file and render its pages
const loadDoc = () => {
   pdfjsLib.getDocument("doc.pdf").promise.then((pdfDoc) => {
      const pageCount = pdfDoc._pdfInfo.numPages;
      
      for (let i = 1; i <= pageCount; i++) {
         pdfDoc.getPage(i)
            .then((page) => {
               // get the viewport object of the page in the pdf
               const viewport = page.getViewport({ scale: 1.25, });

               // create a new canvas to place the content of this page
               const newPageCanvas = document.createElement("canvas");
               newPageCanvas.setAttribute("id", "page_" + i);
               newPageCanvas.setAttribute("class", "pdf-page-canvas");
               newPageCanvas.width = viewport.width;
               newPageCanvas.height = viewport.height;

               // add the page canvas to the DOM
               document.getElementById("pages_container").appendChild(newPageCanvas);

               // render page
               const renderContext = {
                  canvasContext: newPageCanvas.getContext("2d"),
                  viewport: viewport
               };
               page.render(renderContext);
            });
      }
   });
}

// function to place a marker on the pdf document
const placeBox = (x, y, width, height) => {
   console.log("Draw box with attributes: ", x, y, width, height);

   const drawCanvasContext = document.querySelector("#draw_canvas").getContext("2d");
   drawCanvasContext.strokeStyle = "red";
   drawCanvasContext.strokeRect(x, y, width, height);
}

defineExpose({placeBox,});

onMounted(() => {
   loadDoc();

   const observer = new ResizeObserver(entries => {
      console.log("Height changed!");

      const drawCanvas = document.querySelector("#draw_canvas");
      const offsetHeight = document.querySelector("#pages_container").offsetHeight;
      
      console.log(`Div offset height: ${offsetHeight}`);
      console.log(`Canvas old height: ${drawCanvas.height}`);

      drawCanvas.height = offsetHeight;

      console.log(`canvas new height: ${drawCanvas.height}`);
   });

   observer.observe(document.querySelector("#pages_container"));
});
</script>


<template>
   <div id="doc_container">
      <div id="pages_container">
         <!-- the canvases that contain the pdf pages will be placed in here -->
      </div>
      <canvas id="draw_canvas"></canvas>
   </div>
</template>


<style scoped>
#doc_container {
   position: relative;
   width: 100%;
   height: 100vh;
   overflow-y: scroll;
   border: 1px solid green;
}

#pages_container {
   border: 2px dashed red;
}

#draw_canvas {
   position: absolute;
   top: 0;
   left: 0;
   z-index: 1;
   width: 100%;
   background-color: gray;
   opacity: 0.6;
}
</style>

By printing out the offsetHeight of <div id="pages_container"> whenever changed, I noted the max height it grows to is 3171px. So, the max height <canvas id="draw_canvas"> must also be 3171px, but it is not. It appears to be exceeding that value.

screenshot

I have given the <div id="pages_container"> a dashed red border and the <canvas id="drawCanvas"> a gray background colour with an opacity of 0.6. In the screenshot above, we can see that the canvas exceed the div in height. I don't understand why. How do I adjust the height of this canvas so that it matches the height of <div id="pages_container"> ?



from How to dynamically adjust the dimensions of a canvas based on the content inside a scrollable div?

No comments:

Post a Comment