LP13
LP13

Reputation: 34089

How to store and restore canvas to use it again?

I am using PDF.js to show PDF in browser. PDF.js uses canvas to render PDF. I have js scripts that draws the lines on the canvas when user double clicks on the canvas. It also adds X check mark to remove the already drawn line.

based on my research i cannot simply just remove the line from the canvas because underneath pixels are gone when you draw something on it. To get it working i have to store lines and then clear canvas and re-load canvas and re-draw lines

Issue I am not able to store canvas and restore canvas. When i click on X i was able to get lines re-drawn but canvas does not get restored. Canvas remains blank

Run the demo in full page

$(function () {
    var $canvas = $("#myCanvas");
    var canvasEl = $canvas.get(0);
    var ctx = canvasEl.getContext("2d");
    var lines = [];

    var backupCanvas = document.createElement("canvas");



    var loadingTask = pdfjsLib.getDocument('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf');
    loadingTask.promise.then(function (doc) {
        console.log("This file has " + doc._pdfInfo.numPages + " pages");
        doc.getPage(1).then(page => {
            var scale = 1;
            var viewPort = page.getViewport(scale);
            canvasEl.width = viewPort.width;
            canvasEl.height = viewPort.height;
            canvasEl.style.width = "100%";
            canvasEl.style.height = "100%";

            var wrapper = document.getElementById("wrapperDiv");
            wrapper.style.width = Math.floor(viewPort.width / scale) + 'px';
            wrapper.style.height = Math.floor(viewPort.height / scale) + 'px';
            page.render({
                canvasContext: ctx,
                viewport: viewPort
            });

            storeCanvas();
        });
    });


    function storeCanvas() {
        backupCanvas.width = canvasEl.width;
        backupCanvas.height = canvasEl.height;
        backupCanvas.ctx = backupCanvas.getContext("2d");
        backupCanvas.ctx.drawImage(canvasEl, 0, 0);
    }

    function restoreCanvas() {
        ctx.drawImage(backupCanvas, 0, 0);
    }

    $canvas.dblclick(function (e) {
        var mousePos = getMousePos(canvasEl, e);
        var line = { startX: 0, startY: mousePos.Y, endX: canvasEl.width, endY: mousePos.Y, pageY: e.pageY };
        lines.push(line);
        drawLine(line, lines.length - 1);
    });

    function drawLine(line, index) {

        // draw line        
        ctx.beginPath();
        ctx.strokeStyle = '#df4b26';
        ctx.moveTo(line.startX, line.startY);
        ctx.lineTo(line.endX, line.endY);
        ctx.closePath();
        ctx.stroke();

        // add remove mark
        var top = line.pageY;
        var left = canvasEl.width + 20;
        var $a = $("<a href='#' class='w-remove-line'>")
            .data("line-index", index)
            .attr("style", "line-height:0")
            .css({ top: top, left: left, position: 'absolute' })
            .html("x")
            .click(function () {
                var index = $(this).data("line-index");
                $(".w-remove-line").remove();
                ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
                // restore canvas
                restoreCanvas();
                lines.splice(index, 1);
                for (var i = 0; i < lines.length; i++) {
                    drawLine(lines[i], i);
                }

            });

        $("body").append($a);

    }

    function getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
            X: Math.floor(evt.clientX - rect.left),
            Y: Math.floor(evt.clientY - rect.top),
        };
    }
});
 canvas {
        border: 1px solid red;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<b> Double Click on PDF to draw line and then click on X to remove lines</b>
<div id="wrapperDiv">
   <canvas id="myCanvas"></canvas>
</div>

Upvotes: 2

Views: 990

Answers (1)

Synthetx
Synthetx

Reputation: 609

The PDF.js render() function is async so you need to store the canvas after the render has finished. Your code is firing storeCanvas() too early and storing a blank canvas. Easy fix, render() returns a promise so ...

  page.render({
    canvasContext: ctx,
    viewport: viewPort
  }).then( () => {
    storeCanvas();
  });

https://jsfiddle.net/fyLant01/1/

Reference: from https://github.com/mozilla/pdf.js/blob/master/src/display/api.js#L998

  /**
   * Begins the process of rendering a page to the desired context.
   * @param {RenderParameters} params Page render parameters.
   * @return {RenderTask} An object that contains the promise, which
   *                      is resolved when the page finishes rendering.
   */

Upvotes: 3

Related Questions