This project is archived and is in readonly mode.

#668 ✓wontfix
Daniele C.

New Events for Fx

Reported by Daniele C. | May 12th, 2009 @ 04:42 PM | in 2.0 (closed)

Hi all, I was wondering why there are events only for start and complete (and cancel and chainComplete) events in Fx. I could find usefull also an onStep event, and onPause/onResume events, that are fired on the corrisponding methods.

I've write this:


var Fx = new Class({

	Implements: [Chain, Events, Options],

	options: {
		/*
		onStart: $empty,
		onCancel: $empty,
		onComplete: $empty,
		onStep: $empty,
		onPause: $empty,
		onResume:  $empty
		*/
		fps: 50,
		unit: false,
		duration: 500,
		link: 'ignore'
	},

	initialize: function(options){
		this.subject = this.subject || this;
		this.setOptions(options);
		this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
		var wait = this.options.wait;
		if (wait === false) this.options.link = 'cancel';
	},

	getTransition: function(){
		return function(p){
			return -(Math.cos(Math.PI * p) - 1) / 2;
		};
	},

	step: function(){
		var time = $time();
		if (time < this.time + this.options.duration){
			var delta = this.transition((time - this.time) / this.options.duration);
			//Call the event
			this.onStep(delta);
			this.set(this.compute(this.from, this.to, delta));
		} else {
			//Call the event
			this.onStep(1);
			this.set(this.compute(this.from, this.to, 1));
			this.complete();
		}
	},

	set: function(now){
		return now;
	},

	compute: function(from, to, delta){
		return Fx.compute(from, to, delta);
	},

	check: function(){
		if (!this.timer) return true;
		switch (this.options.link){
			case 'cancel': this.cancel(); return true;
			case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
		}
		return false;
	},

	start: function(from, to){
		if (!this.check(from, to)) return this;
		this.from = from;
		this.to = to;
		this.time = 0;
		this.transition = this.getTransition();
		this.startTimer();
		this.onStart();
		return this;
	},

	complete: function(){
		if (this.stopTimer()) this.onComplete();
		return this;
	},

	cancel: function(){
		if (this.stopTimer()) this.onCancel();
		return this;
	},

	onStart: function(){
		this.fireEvent('start', this.subject);
	},

	onComplete: function(){
		this.fireEvent('complete', this.subject);
		if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
	},

	onCancel: function(){
		this.fireEvent('cancel', this.subject).clearChain();
	},

	pause: function(){
		//Call the event
		if(this.stopTimer())this.onPause();
		return this;
	},

	resume: function(){
		//Call the event
		this.onResume();
		this.startTimer();
		return this;
	},
	//the event fired onPause
	onPause:  function(){
		this.fireEvent('pause', this.subject);
	},
	//the event fired onResume
	onResume:  function(){
		this.fireEvent('resume', this.subject);		
	},
	//the event fired onStep, it passes on second argument the delta (0..1) of work done)
	onStep:  function(delta){
		this.fireEvent('step', [this.subject, delta]);		
	},

	stopTimer: function(){
		if (!this.timer) return false;
		this.time = $time() - this.time;
		this.timer = $clear(this.timer);
		return true;
	},

	startTimer: function(){
		if (this.timer) return false;
		this.time = $time() - this.time;
		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
		return true;
	}

});

Using this class i can set:


onStep : function(elem, delta){
  var status = delta * 100; 
  //in status there is the percentage of the effect complete
}

I've attached a file with a morph effect using all the events.

Comments and changes to this ticket

  • Scott Kyle

    Scott Kyle May 12th, 2009 @ 08:54 PM

    I'm guessing for "step", it needs to be as efficient as possible or else the effects will lag.

  • Daniele C.

    Daniele C. May 12th, 2009 @ 09:42 PM

    I agree: in my example the duration is twice longer using the onStep event than not using it. But this is, IMHO, a Web Developer issue: it should be uses only for some little changes, not for big changes in the DOM.

  • Scott Kyle

    Scott Kyle May 12th, 2009 @ 10:18 PM

    Even if you don't attach a 'onStep' event, it would slow down Fx. Typically, Fx runs at 60 fps, or about once per 16ms. Now imagine if on each step this.onStep() was called, which then calls fireEvent('step', ...), which then calls Events.removeOn(type), which then creates a regular expression and runs a String replace on type. I hope you get the picture, it can get to be a lot to do in addition to all the animation stuff, especially if you have a few effects running at once.

  • Scott Kyle

    Scott Kyle May 12th, 2009 @ 10:40 PM

    I do agree that attaching events to pause and resume might be nice. Even if they don't decide the implement it, you can "do it yourself" :-)

    
    Fx.implement({
    	
    	pause: function(){
    		if (this.stopTimer()) this.fireEvent('pause', this.subject);
    		return this;
    	},
    
    	resume: function(){
    		this.fireEvent('resume', this.subject);
    		this.startTimer();
    		return this;
    	}
    
    });
    
  • Daniele C.

    Daniele C. May 13th, 2009 @ 08:20 AM

    mmm, my purpose was to create a way do attach a function that is fired to a certain extent of the transition. Probably you're right, an onStep event is really too intrusive, I think the best way to do my intent is a chain.

    Thank you, for your advices!

  • csuwldcat

    csuwldcat May 16th, 2009 @ 07:05 PM

    I believe that onPause and onResume are really great additions, think of custom js controls for flash media and audio players... But the onStep is a bit overboard, the effects are a great part of Moo and I think that until Google Chrome v9 we won't be able to process that fluidly with functions firing every small # of ms :)

    • Good ideas on the onPause, onResume though!!!
  • Nathan Kleyn

    Nathan Kleyn May 21st, 2009 @ 05:14 PM

    I think in terms of implementation, Scott's way of doing things is probably as far as this will get due to performance issues. If you want to attach a step event to Fx class, why not just extend it with the step, pause and resume events, and override the parent's implementation with a function which calls the original frame step code, and chains a step function event onto the end. You can get the time delta information by accessing the appropriate variables in this.parent.

    This leaves you with a way to use the Fx class without the overhead for operations with don't need to extended functionality.

  • Scott Kyle

    Scott Kyle September 4th, 2009 @ 03:45 AM

    • Assigned user set to “Scott Kyle”
    • State changed from “new” to “open”
  • Christoph Pojer

    Christoph Pojer September 5th, 2010 @ 02:03 PM

    • State changed from “open” to “wontfix”
    • Milestone order changed from “0” to “0”

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Shared Ticket Bins

Attachments

Tags

Pages