1

What I am doing here is that I am covering the entire web page loaded with the layer of a canvas. Now on that canvas user clicks and that click creates a dot. At that point createDot() function gets called.

Inside createDot() the dot is drawn on to the canvas and then the screenshot request is sent to the background script.

Now the problem is that when I click on the canvas and the screenshot is taken, the dot does not appear in the screenshot.

Now what's weird is that when i click a 2nd dot onto the same canvas and when the screenshot comes, it has now the first dot that I clicked but not the 2nd one.

So what is happening is that screenshot is not capturing the current dot but only the previous dots.

I checked that the canvas drawing functions are all blocking so the request cannot be sent to the background script before the drawing is complete. I also confirmed the same by logging to the console.

content script:

function createDot(canvas) {
    var context = canvas.getContext("2d");

    var canvasOffset = $("#canvas").offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;

    var pointX , pointY;
    var point_X,point_Y;

    function handleMouseDown(e) {
        //coordinates of the click in dom.
        pointX = parseInt(e.pageX - offsetX);
        pointY = parseInt(e.pageY - offsetY);

        //making the dot
        var radius = 10;
        context.beginPath();
        context.arc(pointX, pointY, radius, 0, 2 * Math.PI);
        context.fillStyle = 'red';
        context.fill();
        context.lineWidth = 2;
        context.strokeStyle = '#003300';
        context.stroke();

        console.log("drawn everything");

        takeDotScreenshot();  //gets called when the canvas has finished its job of drawing.
    }

    $("#canvas").mousedown(function (e) {
        handleMouseDown(e);
    });
}

function takeDotScreenshot() {
    console.log("sending request to Background script");
    chrome.runtime.sendMessage({"capture":true},function(response) {
        var img_src=response.screenshot;
    });

    //logic for using that screenshot and appending it on to the content page...
}

Background script:

chrome.runtime.onMessage.addListener(function(request,sender,sendResponse) {
    if(request.capture) {
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.captureVisibleTab(null, {}, function(dataUrl) {
                if(dataUrl) {
                    sendResponse({"screenshot":dataUrl});           
                }
            });
        });
    }
    return true;
});

UPDATE:

If I use setTimeout of 1ms for calling the takeDotScreenshot function, everything works fine. WHY!

setTimeout(takeDotScreenshot, 1);
Mohit Bhardwaj
  • 9,650
  • 3
  • 37
  • 64
Ninja Turtle
  • 156
  • 2
  • 18
  • @wOxxOm I tried zero but it doesn't work, it runs when i put delay of 1ms. I still don't understand why this is happening. – Ninja Turtle Jul 15 '16 at 12:12
  • 1
    Possible duplicate of [Why is setTimeout(fn, 0) sometimes useful?](http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful) – wOxxOm Jul 15 '16 at 12:17

2 Answers2

1

There is a very detailed, great answer why setTimeout helps here: https://stackoverflow.com/a/4575011/10574621

The DOM-Update-Event for your canvas (which actually make the dot visible) could be behind your take-screenshot-event, even if the canvas recieved all data needed from your stroke()-event.

Marty
  • 11
  • 2
0

Screen shot is a snap shot of what the user can see. When inside a rendering function the canvas is not presented for display until the execution stack is empty (returned all the way out of the functions)

Depending on how you render (using requestAnimationFrame or directly from mouse, keyboard, timer events) the canvas will still take time to be presented to the display.

When you set the timeout to zero you can add a call onto the call stack that runs before the canvas is presented to the display. Any code you run will block the page thus preventing the canvas from being displayed and hence no screen shot.

I would set the timeout from render to capture at at least 17ms (just over 60fps). Nobody can notice that delay but gives plenty of time for the canvas to be presented to the display

Blindman67
  • 51,134
  • 11
  • 73
  • 136