改造OpenSeadragon用于360展示
本节主要介绍改造OpenSeadragon,使其适用于360度展示。
过去的一年,我曾经对360展示的插件进行选型,商用的插件,我认为目前最成熟的是:
http://www.ajax-zoom.com/examples/,我用它做了一个项目实施,虽然遇到一些官网例程之外的麻烦,
总的来说,只要官网例子已经有的,依葫芦画瓢就好。官网的例子已经比较丰富了,作者的售后也很给力。
而开源方面情况就比较让人灰心了,我甚至没有找到一款同时具备360度旋转和无级缩放的开源插件。
OpenSeadragon Sequence Mode
OpenSeadragon在无级缩放方面已经做到足够好了,能不能再进一步,让它成为我的360展示插件呢,
我开始浏览官方的example,当看到这个例子之后,信心大增,心里想它离我要的那个目标已经不远了。
这就是:Sequence Mode,而其中这个例子最接近我的要求:
Preserving the Viewport Zoom Level and Position for Image Sequences
改造策略
对比下我最终想要的效果:
http://v.youku.com/v_show/id_XMTM5ODE0MjI0NA==.html
即:既然OpenSeadragon已经能够做到:在加载系列帧时,保持住缩放局部的设定,那么需要做的就是:
不断优化加载系列帧的性能,做到在加载连续帧对应的切片时流畅显示。——这个就是我改造OpenSeadragon的原则。
前端缓存
缓存策略涉及前端缓存,和服务端缓存两部分,先讨论前端缓存。
OpenSeadragon本身对于当前加载的切片是进行了缓存处理的,它在进行缩放和平移时,如果不是利用缓存中的image直接进行绘制,是不可能做到平滑的。
OpenSeadragon在tiledImage层次进行缓存,相关代码如下:
写入缓存:
function completionCallback() { increment--; if (increment === 0) { tile.loading = false; tile.loaded = true; if (!tile.context2D) { tiledImage._tileCache.cacheTile({ image: image, tile: tile, cutoff: cutoff, tiledImage: tiledImage }); } tiledImage._needsDraw = true; } }
获取缓存:
if (!tile.loaded) { if (tile.context2D) { setTileLoaded(tiledImage, tile); } else { var imageRecord = tiledImage._tileCache.getImageRecord(tile.url); if (imageRecord) { var image = imageRecord.getImage(); setTileLoaded(tiledImage, tile, image); } } }
然而不幸的是,在加载新的一帧影像时,这个缓存被清除了(该reset在tiledImage的destroy时被调用。):
reset: function() { this._tileCache.clearTilesFor(this); this.lastResetTime = $.now(); this._needsDraw = true; },
对于OpenDragon的功能定位来说,这是非常合理的处理,载入下一帧影像时,当然应该清除当前帧所占用的内存,否则随着加载的帧不断增加,内存开销会越来越大。
而对于360展示来说,为了实现连续帧之间的平滑切换,需要预先将所有的帧加载到内存,当然代价是:内存开销会达到所有帧的总和。
针对上述分析,我们实施的第一个改动是:
加载下一帧保持缓存
虽然涉及到的代码还不少,但清楚其逻辑之后,只需要注释掉reset函数的两行即可:
reset: function() { //c4w commet 加载下一张图时并不清除上一张缓存 //this._tileCache.clearTilesFor(this); //this.lastResetTime = $.now(); this._needsDraw = true; },
由于缓存部分篇幅较长,就此结束本节,下节继续。