diff options
author | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2015-12-16 01:54:53 +0100 |
---|---|---|
committer | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2015-12-16 01:54:53 +0100 |
commit | 5cb2010246154e3a5dfa753f14fb081cef5c2579 (patch) | |
tree | 856e0e2f59b4d7b492df8719c252b031c8a25902 /src | |
parent | 3260b94a26d033112ea9d027faa23152cf24c1ea (diff) | |
download | svg.js-5cb2010246154e3a5dfa753f14fb081cef5c2579.tar.gz svg.js-5cb2010246154e3a5dfa753f14fb081cef5c2579.zip |
added all fx methods, styles and attrs
Diffstat (limited to 'src')
-rw-r--r-- | src/fxnew.js | 411 | ||||
-rw-r--r-- | src/sugar.js | 4 |
2 files changed, 340 insertions, 75 deletions
diff --git a/src/fxnew.js b/src/fxnew.js index cdfebe1..377bde9 100644 --- a/src/fxnew.js +++ b/src/fxnew.js @@ -5,26 +5,19 @@ SVG.easing = { , '<': function(pos){return -Math.cos(pos * Math.PI / 2) + 1} } -SVG.Situation = SVG.invent({ - - create: function(o) { - - if(o instanceof SVG.Situation) return o - - o = o || {} +SVG.FX = SVG.invent({ - this._duration = o.duration || 1000 - this._delay = o.delay || 0 - this._start = +new Date + this._delay - this._end = this._start + this._duration + create: function(element) { - this.easing = SVG.easing[o.easing || '-'] || o.easing // when easing is a function, its not in SVG.easing this.pos = 0 // position before easing this.lastPos = 0 // needed for once callbacks this.paused = false this.finished = false this.active = false - this._fx = null + this.shared = {current:this} + this.target = element + this._next = null + this._prev = null this.animations = { // functionToCall: [morphable object, destination value] @@ -32,6 +25,14 @@ SVG.Situation = SVG.invent({ // this way its assured, that the start value is set correctly } + this.attrs = { + // todo: check if attr is present in animation before saving + } + + this.styles = { + + } + this._once = { // functions to fire at a specific position // e.g. "0.5": function foo(){} @@ -41,8 +42,71 @@ SVG.Situation = SVG.invent({ , extend: { + animate: function(o){ + o = o || {} + + this._duration = o.duration || 1000 + this._delay = o.delay || 0 + this._start = +new Date + this._delay + this._end = this._start + this._duration + + this.easing = SVG.easing[o.easing || '-'] || o.easing // when easing is a function, its not in SVG.easing + + return this + } + + , enqueue: function(o){ + // create new istance from o or use it directly + return this.next( + o instanceof SVG.FX ? o : + new SVG.FX(this.target).animate(o) + ).next().share(this.shared) + } + + // return the next situation object in the animation queue + , next: function(next){ + if(!next) return this._next + + this._next = next + next._prev = this // dont use function to prevent recursion + return this + } + + , prev: function(prev){ + if(!prev) return this._prev + + this._prev = prev + prev._next = this + return this + } + + , first: function(){ + var prev = this + while(prev.prev()){ + pref = prev.prev() + } + + return prev + } + + , last: function(){ + + var next = this + while(next.next()){ + next = next.next() + } + + return next + + } + + , share: function(shared){ + this.shared = shared + return this + } + // returns the position at a given time - timeToPos: function(timestamp){ + , timeToPos: function(timestamp){ return (timestamp - this._start) / (this._duration) } @@ -59,21 +123,25 @@ SVG.Situation = SVG.invent({ cancelAnimationFrame(this.animationFrame) } + , current: function(){ + return this.shared.current + } + , start: function(){ - if(this.fx().current() == this){ + /*if(this.fx().current() == this){ // morph values from the current position to the destination - maybe move this to another place for(var i in this.animations){ if(this.animations[i] instanceof Array){ - + this.animations[i] = new this.animations[i][0](this.fx().target[i]()).morph(this.animations[i][1]) console.log(i, this.animations[i]) } } - } - + }*/ + // dont start if already started - if(!this.active && this.fx().current() == this){ + if(!this.active && this.current() == this){ this._start = +new Date + this._delay this._end = this._start + this._duration this.active = true @@ -124,28 +192,24 @@ SVG.Situation = SVG.invent({ return this } - , push: function(method, args){ - this.animations[method] = args - return this + , push: function(method, args, type){ + this[type || 'animations'][method] = args + return this.start() } - , pop: function(method){ - var ret = this.animations[method] + , pop: function(method, type){ + var ret = this[type || 'animations'][method] this.drop(method) return ret } - , drop: function(method){ - delete this.animations[method] + , drop: function(method, type){ + delete this[type || 'animations'][method] return this } - , get: function(method){ - return this.animations[method] - } - - , getAt: function(method){ - return this.get(method).at(this.easing(this.pos)) + , get: function(method, type){ + return this[type || 'animations'][method] } , step: function(){ @@ -158,24 +222,26 @@ SVG.Situation = SVG.invent({ if(this.pos < 0) this.pos = 0 var eased = this.easing(this.pos) - + for(var i in this._once){ - if(i > this.lastPos && i < eased) this._once[i](this.pos, eased) + if(i > this.lastPos && i <= eased) this._once[i](this.pos, eased) } - - this.fx().target.fire('during', {pos: this.pos, eased: eased}) - + + this.target.fire('during', {pos: this.pos, eased: eased}) + this.eachAt(function(method, args){ - this.fx().target[method].apply(this.fx().target, args) + this.target[method].apply(this.target, args) }) if(this.pos == 1){ this.finished = true this.active = false - this.fx().target.fire('situationfinished') - this.fx().startNext() - //var next = this.fx().next() - //if(next)next.start() + + this.target.fire('situationfinished') + if(this == this.last()) this.target.fire('fxfinished') + + if(this.next())(this.shared.current = this.next()).start() + cancelAnimationFrame(this.animationFrame) }else{ this.startAnimFrame() @@ -187,30 +253,46 @@ SVG.Situation = SVG.invent({ } , eachAt: function(block){ + var i, at + + for(i in this.animations){ - for(var i in this.animations){ - - var at = [].concat(this.animations[i]).map(function(el){ - if(el.at) return el.at(this.easing(this.pos)) + at = [].concat(this.animations[i]).map(function(el){ + if(el.at) return el.at(this.easing(this.pos), this.pos) return el }.bind(this)) - + block.call(this, i, at) } + + for(i in this.attrs){ - } + at = [i].concat(this.attrs[i]).map(function(el){ + if(el.at) return el.at(this.easing(this.pos), this.pos) + return el + }.bind(this)) + + block.call(this, 'attr', at) - , fx: function(fx){ - if(fx){ - this._fx = fx - return this } + + for(i in this.styles){ + + at = [i].concat(this.styles[i]).map(function(el){ + if(el.at) return el.at(this.easing(this.pos), this.pos) + return el + }.bind(this)) + + block.call(this, 'style', at) + + } + + return this - return this._fx } - - + + , once: function(pos, fn, isEased){ if(!isEased)pos = this.easing(pos) @@ -219,11 +301,195 @@ SVG.Situation = SVG.invent({ return this } + + // with the help of key this function can be used to retrieve + , search: function(method, key) { + var situation = this + + while(situation = situation.prev()){ + + // get method of situation if present (always try animation object first before accessing attrs or styles) + var attr = situation.get(key || method) || this.styles[key] || this.attrs[key] + if(!attr) continue + + // return value from the morphed object + return attr.destination + + } + + // return the elements attribute as fallback + return this.target[method](key) + + } + + } + +, parent: SVG.Element + + // Add method to parent elements +, construct: { + // Get fx module or create a new one, then animate with given duration and ease + animate: function(o) { + return (this.fx || (this.fx = new SVG.FX(this))).animate(o) + } + , delay: function(delay){ + return (this.fx || (this.fx = new SVG.FX(this))).animate({delay:delay}) + } + } + +}) + + +SVG.MorphObj = SVG.invent({ + + create: function(from, to){ + // prepare color for morphing + if(SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) + // prepare number for morphing + if(SVG.regex.unit.test(to) || typeof from == 'number') return new SVG.Number(from).morph(to) + + // prepare for plain morphing + this.from = from + this.destination = to + } + +, extend: { + at: function(pos, real){ + return real < 1 ? this.from : this.destination + } + } + +}) + +SVG.extend(SVG.FX, { + // Add animatable attributes + attr: function(a, v) { + // apply attributes individually + if (typeof a == 'object') { + for (var key in a) + this.attr(key, a[key]) + + } else { + // get the current state + var from = this.search('attr', a) + + // detect format + if (a == 'transform') { + // merge given transformation with an existing one + if (this.attrs[a]) + v = this.attrs[a].multiply(v) + + // prepare matrix for morphing + this.push(a, (new SVG.Matrix(this.target)).morph(v), 'attrs') + + // add parametric rotation values + /*if (this.param) { + // get initial rotation + v = this.target.transform('rotation') + + // add param + this.attrs[a].param = { + from: this.target.param || { rotation: v, cx: this.param.cx, cy: this.param.cy } + , to: this.param + } + }*/ + + } else { + if(typeof this[a] == 'function'){ + return this[a](v) + } + + this.push(a, new SVG.MorphObj(from, v), 'attrs') + } + } + return this } + // Add animatable styles +, style: function(s, v) { + if (typeof s == 'object') + for (var key in s) + this.style(key, s[key]) + + else + this.push(s, new SVG.MorphObj(this.search('style', s), v), 'styles') + + return this + } + // Animatable x-axis +, x: function(x) { + return this.push('x', new SVG.Number(this.search('x')).morph(x)) + } + // Animatable y-axis +, y: function(y) { + return this.push('y', new SVG.Number(this.search('y')).morph(y)) + } + // Animatable center x-axis +, cx: function(x) { + return this.push('cx', new SVG.Number(this.search('cx')).morph(x)) + } + // Animatable center y-axis +, cy: function(y) { + return this.push('cy', new SVG.Number(this.search('cy')).morph(y)) + } + // Add animatable move +, move: function(x, y) { + return this.x(x).y(y) + } + // Add animatable center +, center: function(x, y) { + return this.cx(x).cy(y) + } + // Add animatable size +, size: function(width, height) { + if (this.target instanceof SVG.Text) { + // animate font size for Text elements + this.attr('font-size', width) + + } else { + // animate bbox based size for all other elements + var w = this.search('width') + , h = this.search('height') + , box + + if(!w || !h){ + box = this.target.bbox() + } + + this.push('width' , new SVG.Number(w || box.width).morph(width)) + .push('height', new SVG.Number(h || box.height).morph(height)) + } + + return this + } + // Add animatable plot +, plot: function(p) { + return this.push('plot', this.target.array().morph(p)) + } + // Add leading method +, leading: function(value) { + return this.target.leading ? + this.push('leading', new SVG.Number(this.search('leading')).morph(value)) : + this + } + // Add animatable viewbox +, viewbox: function(x, y, width, height) { + if (this.target instanceof SVG.Container) { + var box = this.target.viewbox() + this.push('viewbox', [ + new SVG.Number(box.x).morph(x), + new SVG.Number(box.y).morph(y), + new SVG.Number(box.width).morph(width), + new SVG.Number(box.height).morph(height) + ]) + } + + return this + } }) +/* SVG.FX = SVG.invent({ // Initialize FX object create: function(element) { @@ -254,23 +520,23 @@ SVG.FX = SVG.invent({ , last: function() { return this.get(this.queue().length-1) } - + , first: function() { return this.get(0) } - + , search: function(attr) { var current = this.queue().length-1 - + while(situation = this.get(--current)){ - + // get method of situation if present var attr = situation.get(attr) if(!attr) continue - + // if not yet morphed we extract the destination from the array //if(attr instanceof Array) return attr[1] - + // otherwise from the morphed object return attr.destination @@ -293,13 +559,13 @@ SVG.FX = SVG.invent({ if(!this._queue[i]) return null return this._queue[i] } - + , startNext: function() { - + var next = this.next() if(next) next.start() else this.finish() - + return this } @@ -313,10 +579,9 @@ SVG.FX = SVG.invent({ return this } - /* , resume: function() { this.active = true - }*/ + } , finish: function() { this.active = false @@ -399,12 +664,12 @@ SVG.FX = SVG.invent({ , dmove: function(x, y) { return this.dx(x).dy(y) } - /*, attr: function(a, v) { + , attr: function(a, v) { // apply attributes individually if (typeof a == 'object') { for (var key in a) this.attr(key, a[key]) - + } else { // get the current state //var from = this.target.attr(a) @@ -441,9 +706,9 @@ SVG.FX = SVG.invent({ { from: from, to: v } } } - + return this - }*/ + } } @@ -454,10 +719,10 @@ SVG.FX = SVG.invent({ , construct: { // Get fx module or create a new one, then animate with given duration and ease animate: function(o) { - return (this.fx || (this.fx = new SVG.FX(this))).enqueue(o) + return (this.fx || (this.fx = new SVG.Situation(this))).animate(o) } , delay: function(delay){ - return (this.fx || (this.fx = new SVG.FX(this))).enqueue({delay:delay}) + return (this.fx || (this.fx = new SVG.Situation(this))).animate({delay:delay}) } } -})
\ No newline at end of file +})*/
\ No newline at end of file diff --git a/src/sugar.js b/src/sugar.js index 2a0404c..0685a25 100644 --- a/src/sugar.js +++ b/src/sugar.js @@ -61,11 +61,11 @@ SVG.extend(SVG.Element, SVG.FX, { } // Relative move over x axis , dx: function(x) { - return this.x((this.target || this).x() + x) + return this.x((this.search ? this.search('x') : this.x()) + x) } // Relative move over y axis , dy: function(y) { - return this.y((this.target || this).y() + y) + return this.y((this.search ? this.search('x') : this.y()) + y) } // Relative move over x and y axes , dmove: function(x, y) { |