调用destroy()后重新创建Google Swiffy动画

时间:2013-06-17 11:53:16

标签: google-swiffy

我正在尝试删除Google swiffy(v 5.2.0)动画,然后在以后阅读它。

就运行动画而言,似乎没有任何问题,但代码会触发错误:TypeError:无法重新定义属性:Animation_fla.MainTimeline,此时影片中的所有AS3都停止工作。这似乎是因为destroy方法没有在swiffy运行时中删除对AS3代码的引用。我花了一些时间试图逐步完成代码,但这是非常难以理解的。

下面是我正在使用swiffy执行的所有操作的删除版本 - 在调用destroy之后再次调用init将触发此TypeError。我试图重新初始化swiffy运行时本身,但这会导致类似的错误。

var stage;

function init() {
    stage = new swiffy.Stage(domElement, swiffyJson);
    stage.start();
}

function destroy() {
    stage.destroy();
    stage = null;
} 

2 个答案:

答案 0 :(得分:1)

我提出的唯一解决方案是非常可怕的黑客攻击。看起来Swiffy并不想在它们被摧毁后重新制作动画。我已经取得了一些成功,将Swiffy从DOM中分离出来但保留了它在内存中的引用。然后,我不得不破解运行时以启用暂停和重新启动。然后我可以重新连接原始的Swiffy而不必破坏它。这是在通过jsbeautifier.org运行运行时从https://www.gstatic.com/swiffy/v5.2/runtime.js下载的v5.2.0中

M.releaseCapture函数之后的第5640行附近,我添加了以下函数:

M.hackPause = function (bool) {
    if(this.hackPaused === bool) return;

    if(this.hackPaused) {
        bi(ef(this.qh.yl, this.qh));
    }

    this.hackPaused = bool;
};

围绕第7137行,将AK[I].yl函数替换为以下内容:

Ak[I].yl = function () {
    if (this.bh) {
        var a = Date.now();
        a >= this.Mf && (this.tl.ei(), this.Mf += (s[Xb]((a - this.Mf) / this.sl) + 1) * this.sl);
        this.tl.lc();

        if(!this.tl.hackPaused) {
            bi(ef(this.yl, this))
        }
    }
};

这样做会阻止requestAnimationFrame或setTimeout触发,从而有效地暂停动画。

我也尝试在运行时中公开gotoAndStop函数,但我无法在代码中找到范围。与此同时,使用此帖子中的黑客 - Is it possible to pause/resume/manipulate a swiffyobject from JS?,我们可以通过向Flash电影添加输入帧事件并测试Flashvars中的更改,以蛮力方法执行此操作。以下是我们用于动画的文档类。值得注意的是,Swiffy似乎并不喜欢从同一个基类扩展的AS3类,它抛出同样的不能重新定义属性错误,因此我们在文档中重复了此处的代码每个Flash动画的类。我还有一个方法,允许从AS3调度事件到一个名为onSwiffyEvent的javascript函数:

package {

    import flash.display.MovieClip;
    import flash.net.URLRequest;
    import flash.net.navigateToURL;
    import flash.events.Event;
    import flash.utils.setTimeout;

    public class BaseAnimation extends MovieClip {

        private var _request:URLRequest;
        private var _pageName:String;
        private var _movieName:String;

        public function BaseAnimation() {
            _request = new URLRequest();

            _pageName = getFlashVar('pageName');
            _movieName = getFlashVar('movieName');

            addEventListener(Event.ENTER_FRAME, jsListen);
        }

        private function getFlashVar(name:String):String {
            var flashVar:String = stage.loaderInfo.parameters[name] || '';
            stage.loaderInfo.parameters[name] = '';

            return flashVar;
        }

        public function dispatchJSEvent(eventName:String, param:String = ''):void {
            _request.url = "javascript:onSwiffyEvent('" + eventName + "', '" + param + "', '" + _movieName + "', '" + _pageName + "');";
            navigateToURL(_request, "_self");
        }

        private function jsListen(e:Event):void {
            var mode:String = getFlashVar('mode');

            if(mode.length) {
                switch(mode) {
                    case 'stop':
                        stop();
                        break;

                    case 'play':
                        play();
                        break;

                    case 'gotoStart':
                        gotoAndStop('start');
                        break;
                }
            }
        }
    }
}

Swiffy似乎也不喜欢gotoAndStop(0)所以我必须设置一个框架标签“开始”#39在动画的第一帧。

有了这些可怕的hackery,我们就能够删除并重新启动Swiffy动画。我们发现的唯一问题是分离和重新附加导致嵌入式SVG字体出现问题,我们最终将所有文本转换为大纲。以上使用如下:

你可以像这样在漂亮的舞台上调用它:

var stage = new swiffy.Stage(domObject, swiffyObj);
stage.start();

// when reading to remove this element from the DOM do the following:
stage.setFlashVars('mode=gotoStart');

setTimeout(function () {
    // timeout is required to ensure that the enterframe listener has time to run
    stage.hackPause(true);   // paused animation
}, 100);

// you can then remove the containing div from the DOM, but retain it in memory

// after you reattach the div to the DOM, ensuring we've kept hold of our stage variable in memory, you can restart it like this:

stage.hackPause(false);             // resumes javascript requestAnimationFrame
stage.setFlashVars('mode=play');    // resumes flash animation

希望这对某人有所帮助,但我也非常希望Google开始向Swiffy运行时公开某种JS API或ExternalInterface,以便让我们更好地控制什么是非常棒的工具。

答案 1 :(得分:0)

尝试在将swiffy对象传递给swiffy.Stage()之前创建swiffyobject的副本。 Swiffy正在实例化时修改对象,因此使用副本只需在destroy()

之后重新创建