adds tween and easing classes (with algorithms from Robert Penner) to handle animation

git-svn-id: http://svn.openlayers.org/trunk/openlayers@6097 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
pgiraud
2008-02-08 13:09:58 +00:00
parent 1847986723
commit f6fe7d48d3
7 changed files with 468 additions and 36 deletions

View File

@@ -1,36 +1,39 @@
OpenLayers contributors:
Seb Benthall
Howard Butler
Bertil Chaupis
John Cole
Jeff Dege
Roald de Wit
Schuyler Erle
Christian López Espínola
John Frank
Sean Gilles
Pierre Giraud
Andreas Hocevar
Ian Johnson
Eric Lemoine
Philip Lindsay
Martijn van Oosterhout
Corey Puffault
Gregers Rygg
Tim Schaub
Christopher Schmidt
Cameron Shorter
Paul Spencer
Glen Stampoultzis
James Stembridge
Erik Uzureau
Ivan Willig
Bill Woodall
Steve Woodbridge
Some portions of OpenLayers are used under the Apache 2.0 license, available
in doc/licenses/APACHE-2.0.txt.
Some portions of OpenLayers are used under the MIT license, availabie in
doc/licenses/MIT-LICENSE.txt.
OpenLayers contributors:
Seb Benthall
Howard Butler
Bertil Chaupis
John Cole
Jeff Dege
Roald de Wit
Schuyler Erle
Christian López Espínola
John Frank
Sean Gilles
Pierre Giraud
Andreas Hocevar
Ian Johnson
Eric Lemoine
Philip Lindsay
Martijn van Oosterhout
Corey Puffault
Gregers Rygg
Tim Schaub
Christopher Schmidt
Cameron Shorter
Paul Spencer
Glen Stampoultzis
James Stembridge
Erik Uzureau
Ivan Willig
Bill Woodall
Steve Woodbridge
Some portions of OpenLayers are used under the Apache 2.0 license, available
in doc/licenses/APACHE-2.0.txt.
Some portions of OpenLayers are used under the MIT license, availabie in
doc/licenses/MIT-LICENSE.txt.
Some portions of OpenLayers are Copyright 2001 Robert Penner, and are used
under the BSD license, available in doc/licenses/BSD-LICENSE.txt

View File

@@ -0,0 +1,28 @@
Redistribution and use of this software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of Yahoo! Inc. nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of Yahoo! Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -79,6 +79,7 @@
"OpenLayers/BaseTypes/Pixel.js",
"OpenLayers/BaseTypes/Size.js",
"OpenLayers/Console.js",
"OpenLayers/Tween.js",
"Rico/Corner.js",
"Rico/Color.js",
"OpenLayers/Ajax.js",

256
lib/OpenLayers/Tween.js Normal file
View File

@@ -0,0 +1,256 @@
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* Namespace: OpenLayers.Tween
*/
OpenLayers.Tween = OpenLayers.Class({
/**
* Constant: INTERVAL
* {int} Interval in milliseconds between 2 steps
*/
INTERVAL: 10,
/**
* APIProperty: easing
* {<OpenLayers.Easing>(Function)} Easing equation used for the animation
* Defaultly set to OpenLayers.Easing.Expo.easeOut
*/
easing: null,
/**
* APIProperty: begin
* {Object} Values to start the animation with
*/
begin: null,
/**
* APIProperty: finish
* {Object} Values to finish the animation with
*/
finish: null,
/**
* APIProperty: duration
* {int} duration of the tween (number of steps)
*/
duration: null,
/**
* APIProperty: callbacks
* {Object} An object with start, eachStep and done properties whose values
* are functions to be call during the animation. They are passed the
* current computed value as argument.
*/
callbacks: null,
/**
* Property: time
* {int} Step counter
*/
time: null,
/**
* Property: interval
* {int} Interval id returned by window.setInterval
*/
interval: null,
/**
* Constructor: OpenLayers.Tween
* Creates a Tween.
*
* Parameters:
* easing - {<OpenLayers.Easing>(Function)} easing function method to use
*/
initialize: function(easing) {
this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
},
/**
* APIMethod: start
* Plays the Tween, and calls the callback method on each step
*
* Parameters:
* begin - {Object} values to start the animation with
* finish - {Object} values to finish the animation with
* duration - {int} duration of the tween (number of steps)
* options - {Object} hash of options (for example callbacks (start, eachStep, done))
*/
start: function(begin, finish, duration, options) {
this.begin = begin;
this.finish = finish;
this.duration = duration;
this.callbacks = options.callbacks;
this.time = 0;
if (this.interval) {
window.clearInterval(this.interval);
this.interval = null;
}
if (this.callbacks && this.callbacks.start) {
this.callbacks.start.call(this, this.begin);
}
this.interval = window.setInterval(
OpenLayers.Function.bind(this.play, this), this.INTERVAL);
},
/**
* APIMethod: stop
* Stops the Tween, and calls the finish callback
*/
stop: function() {
if (this.callbacks && this.callbacks.done) {
this.callbacks.done.call(this, this.finish);
}
window.clearInterval(this.interval);
this.interval = null;
},
/**
* Method: play
* Calls the appropriate easing method
*/
play: function() {
var value = {};
for (var i in this.begin) {
var b = this.begin[i];
var f = this.finish[i];
if (b == null || f == null || isNaN(b) || isNaN(f)) {
OpenLayers.Console.error('invalid value for Tween');
}
var c = f - b;
value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
}
this.time++;
if (this.callbacks && this.callbacks.eachStep) {
this.callbacks.eachStep.call(this, value);
}
if (this.time > this.duration) {
if (this.callbacks && this.callbacks.done) {
this.callbacks.done.call(this, this.finish);
}
window.clearInterval(this.interval);
this.interval = null;
}
},
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Tween"
});
/**
* Namespace: OpenLayers.Easing
*
* Credits:
* Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
*/
OpenLayers.Easing = {
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Easing"
};
/**
* Namespace: OpenLayers.Easing.Linear
*/
OpenLayers.Easing.Linear = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeIn: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeOut: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeInOut: function(t, b, c, d) {
return c*t/d + b;
},
CLASS_NAME: "OpenLayers.Easing.Linear"
};
/**
* Namespace: OpenLayers.Easing.Expo
*/
OpenLayers.Easing.Expo = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeIn: function(t, b, c, d) {
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeOut: function(t, b, c, d) {
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeInOut: function(t, b, c, d) {
if (t==0) return b;
if (t==d) return b+c;
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
},
CLASS_NAME: "OpenLayers.Easing.Expo"
};

View File

@@ -109,4 +109,5 @@
<li>Renderer/test_SVG.html</li>
<li>Renderer/test_VML.html</li>
<li>test_Map.html</li>
<li>test_Tween.html</li>
</ul>

81
tests/manual/tween.html Normal file
View File

@@ -0,0 +1,81 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Tween Example</title>
<style type="text/css">
#viewport {
width: 500px;
height: 300px;
border: 1px solid black;
}
#block {
width: 10px;
height: 10px;
background-color: red;
position: absolute;
}
</style>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
var tween, events;
function init(){
tween = new OpenLayers.Tween(OpenLayers.Easing.Linear.easeIn);
events = new OpenLayers.Events(null, OpenLayers.Util.getElement('viewport'), null, true);
events.register("mousedown", null, moveBlock);
changeTween();
}
function moveBlock(e) {
var block = OpenLayers.Util.getElement('block');
var viewport = OpenLayers.Util.getElement('viewport');
var blockPosition = OpenLayers.Util.pagePosition(block);
var viewportPosition = OpenLayers.Util.pagePosition(viewport);
e.xy = events.getMousePosition(e);
var from = {
x: blockPosition[0] - viewportPosition[0],
y: blockPosition[1] - viewportPosition[1]
};
var to = {
x: e.xy.x,
y: e.xy.y
}
var duration = OpenLayers.Util.getElement('duration').value;
var callbacks = {
eachStep: function(value) {
block.style.left = (value.x + viewportPosition[0]) + 'px';
block.style.top = (value.y + viewportPosition[1]) + 'px';
}
}
tween.start(from, to, duration, {callbacks: callbacks});
}
function changeTween() {
var transition = OpenLayers.Util.getElement('transition').value;
var easing = OpenLayers.Util.getElement('easing').value;
tween.stop();
tween.easing = OpenLayers.Easing[transition][easing];
}
</script>
</head>
<body onload="init()">
<div id="title">Tween Example</div>
<div id="tags"></div>
<div id="shortdesc">Show transition effects</div>
<select name="transition" id="transition" onchange="changeTween()">
<option value="Linear">Linear</option>
<option value="Expo">Expo</option>
</select>
<select name="easing" id="easing" onchange="changeTween()">
<option value="easeIn">EaseIn</option>
<option value="easeOut">EaseOut</option>
</select>
<input type="text" name="duration" id="duration" value="100"></input>
<div id="viewport">
<div id="block"></div>
</div>
<div id="docs">
This is an example of transition effects.
</div>
</body>
</html>

62
tests/test_Tween.html Normal file
View File

@@ -0,0 +1,62 @@
<html>
<head>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Tween_constructor(t) {
t.plan(3);
var tween = new OpenLayers.Tween();
t.ok(tween instanceof OpenLayers.Tween,
"new OpenLayers.Tween returns object" );
t.eq(typeof tween.easing, "function",
"constructor sets easing correctly");
t.eq(typeof tween.start, "function", "tween has a start function");
}
function test_Tween_start(t) {
t.plan(5);
var tween = new OpenLayers.Tween();
var start = {foo: 0, bar: 10};
var finish = {foo: 10, bar: 0};
var _start = false;
var _done = false;
var _eachStep = false;
var callbacks = {
start: function() {
_start = true;
},
done: function() {
_done = true;
},
eachStep: function() {
_eachStep = true;
}
}
tween.start(start, finish, 10, {callbacks: callbacks});
t.ok(tween.interval != null, "interval correctly set");
t.delay_call(0.8, function() {
t.eq(_start, true, "start callback called");
t.eq(_done, true, "finish callback called");
t.eq(_eachStep, true, "eachStep callback called");
t.eq(tween.time, 11, "Number of steps reached is correct");
});
}
function test_Tween_stop(t) {
t.plan(1);
var tween = new OpenLayers.Tween();
tween.interval = window.setInterval(function() {}, 10);
tween.stop();
t.eq(tween.interval, null, "tween correctly stopped");
}
</script>
</head>
<body>
<div id="map" style="width:500px;height:500px"></div>
</body>
</html>