画布绘制函数以异步方式运行

时间:2016-07-15 11:02:19

标签: javascript jquery html5 google-chrome-extension html5-canvas

我在这里做的是我覆盖了加载了画布层的整个网页。现在,在该画布上,用户单击并单击该按钮创建一个点。此时调用createDot()函数。

createDot()内,点被绘制到画布上,然后屏幕截图请求被发送到后台脚本。

现在的问题是,当我点击画布并拍摄截图时,屏幕截图中不会出现点。

现在奇怪的是,当我在同一个画布上点击第二个点并且屏幕截图到来时,它现在是我点击的第一个点而不是第二个点。

所以发生的事情是屏幕截图不捕获当前点,而只捕获前面的点。

我检查了画布绘图功能是否全部阻塞,因此在绘图完成之前无法将请求发送到后台脚本。我也通过登录控制台确认了相同的内容。

内容脚本:

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...
}

后台脚本:

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;
});

更新

如果我使用1ms的setTimeout来调用takeDotScreenshot函数,一切正常。为什么!

setTimeout(takeDotScreenshot, 1);

2 个答案:

答案 0 :(得分:0)

屏幕截图是用户可以看到的快照。在渲染函数内部时,在执行堆栈为空(从函数中一直返回)之前,画布不会显示以供显示。

根据渲染方式(使用requestAnimationFrame或直接从鼠标,键盘,计时器事件),画布仍然需要时间呈现给显示器。

当您将超时设置为零时,您可以在将画布呈现给显示之前运行的调用堆栈上添加一个调用。您运行的任何代码都将阻止页面,从而阻止显示画布,因此无法进行屏幕截图。

我会将渲染时的超时设置为至少17ms(超过60fps)。没有人会注意到这种延迟,但是有足够的时间将画布呈现给显示器

答案 1 :(得分:0)

有一个非常详细的好答案,为什么setTimeout在这里有帮助: https://stackoverflow.com/a/4575011/10574621

画布的DOM更新事件(实际上使点可见)可能在拍摄屏幕事件的后面,即使画布从stroke()事件中接收了所有需要的数据。