生成画布元素冻结动画

时间:2017-03-14 15:57:46

标签: javascript html5-canvas tiff web-worker greensock

我正在使用第三方Javascript在所有浏览器中呈现TIFF(只有safari本身支持它们) 该库的工作原理是将图像打印到HTML 5画布(不涉及img标签)

使用Ajax,一旦图像可用,画布呈现时会有明显的暂停。为了掩盖这一点,我添加了一个占位符图像,这是一个GIF动画。 除了这个动画gif,我还使用了greensock.js和css3变换来使加载gif从0刻度放大,一旦主图像准备就绪,在主图像出现之前缩小到0刻度。

问题是动画暂停的时刻总是暂停(greensock / css动画动画和动画gif)。

我认为我可以通过将导致它的任何内容移动到webworker线程来解决这个问题。 但经过多次实验(通过单独删除部分代码或通过在特定代码运行之前停止所有动画而无法实现),我发现渲染画布的代码行是导致它的原因。

var canvas = tiff.toCanvas();

不幸的是,我无法将其转移到webworker,因为它是一个DOM操作。 我也无法在webworker上呈现图像/画布内容(没有制作画布元素本身),然后将其粘贴到主线程的canvas元素中,因为我使用的库不提供这样的功能。

我能做的最好的事情就是运行运行AJAX的代码并在webworker中接收图像,然后将原始图像数据返回到主线程来完成剩下的工作。

我已经尝试过一个提供虚拟DOM的JS库,但这只会导致依赖性地狱,我从来没有深入到底。

最后,我决定在Web工作人员返回包含图像的数据而不是渲染完成后立即进行缩小动画。这可以防止任何可见的动画暂停,但这意味着在加载图像消失后,在图像出现之前会有一个暂停(画布正在渲染)。

我的代码如下。我有什么想法可以解决这个问题吗?

主线程JS

var worker = new Worker('/javascript/task.js');
worker.addEventListener('message', function(e) {

TweenMax.to(placeHolderImage,0.5,{scale:0,     transformOrigin:"centre",onComplete:function(){
                document.getElementById("pic").removeChild(placeHolderImage);
                var tiff = new Tiff({buffer: e.data});
                var canvas = tiff.toCanvas();
                document.getElementById("pic").appendChild(canvas);
                canvas.className = "canvasReady";
                TweenMax.from(canvas,0.2,{rotationY:90,     transformOrigin:"left"})
            }}
        );

    }, false);

    //Call the worker and send the cover image URL to it.
    var src = /*[[${CoverImageURL}]]*/;
    worker.postMessage(src);

工作者线程JS

self.addEventListener('message', function(e) {

importScripts("tiff.js-master/tiff.min.js");

var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open('GET', e.data);
xhr.onload = function (e) {

    self.postMessage(xhr.response);
}

xhr.send();


}, false);

1 个答案:

答案 0 :(得分:1)

您是正确的,您无法操作Web工作者的文档。您必须找到一种方法在Web worker中执行大部分转换,然后只将转换后的数据传递回主线程。

来自This demo

tiff.js library似乎正在按照您的意愿行事。 The worker it uses明确避免使用tiff.toCanvas()。它们传递给worker的消息包括要使用的总内存以及映像的URL。然后,他们使用tiff.readRGBAImage()获取数据,并将信息发回主线程以进行实际渲染。

另请注意,在worker中调用将数据传递回主线程:

var image = tiff.readRGBAImage();
self.postMessage({ image: image, width: tiff.width(), height: tiff.height() }, [image]);

它将数组中的image作为第二个参数传递,以利用数组的Transferrable interface实现。简而言之,这意味着数据不会在工作线程和主线程之间复制。对于潜在的大型数据集(如图像),传输数据而不是复制数据要高效得多。