正在生成 canvas 个元素冻结动画

Generating canvas element freezing animations

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

使用

Ajax 并且一旦图像可用,在 canvas 呈现时会出现明显的暂停。为了掩盖这一点,我放入了一个占位符图像,它是一个动画 gif。 除了这个动画 gif,我还使用 greensock.js 和 css3 变换使加载 gif 从 0 比例放大,一旦主图像准备就绪,在主图像出现之前缩小回 0 比例。

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

我想我可以通过将导致它的任何东西移动到网络工作者线程来解决这个问题。 然而,经过多次试验(通过单独删除部分代码或在特定代码运行之前停止所有动画无法实现的地方)我发现呈现 canvas 的代码行是导致的原因它。

var canvas = tiff.toCanvas();

不幸的是,我无法将其移至 webworker,因为它是 DOM 操作。 我也无法在 webworker 上呈现 image/canvas 内容(没有制作 canvas 元素本身),然后将其粘贴到主线程的 canvas 元素中,因为我正在使用的库不提供此类功能。

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

我已经尝试过一个提供虚拟 DOM 的 JS 库,但这只会导致我从未深入了解的依赖地狱。

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

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

主线程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);

你说得对,你不能从 web worker 操作文档。您必须找到一种方法在 Web Worker 中完成大部分转换,然后仅将转换后的数据传回主线程。

This demo from the tiff.js library appears to be doing exactly what you want. The worker it uses 明确避免使用 tiff.toCanvas()。他们传递给工作人员的消息包括要使用的总内存以及图像的 URL。然后他们使用 tiff.readRGBAImage() 获取数据,并将 post 信息返回到主线程以进行实际渲染。

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

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

它将数组中的 image 作为第二个参数传递,以利用数组对 Transferrable interface 的实现。长话短说,这意味着数据不会在工作线程和主线程之间复制。对于可能很大的数据集(如图像),传输数据而不是复制数据效率更高。