This is the final write up.
Project Overview:
The domain of this project is animation in web pages. Specifically with regard to jQuery. The problem with jQuery animation is that the animation function is closely tied to the dom elements that you query. This prevents animations from being reused or composed - making more complex animations difficult.
Our project - essentially an internal domain language built on top of jQuery and javascript - separates the animation calls from the dom elements and abstracts them into anim Objects. These animObjects are composable, and can be reused in newer animations. The idea is that web animators would be able to use our plugin to have more flexibility and power when working on larger more complex animations.
Example Demonstration of our Code:
Here, we have an example program written in jQuery. Assume #one, #two, #three, #four, and #five refer to divs already created and existing in the html code. For one reason or another, we want to have #one move right and then left, #two move down and then up, and then #three and #four move right, left, down, and then up. #five does the animation done by #three and #four but twice. Here is how it would look like in jQuery, using jQuery's animate function.
jQuery Animation Code
$('#one').animate({top:"+=200px"}).animate({top:"-=200px"});
$('#two').animate({left:"+=200px"}).animate({left:"-=200px"});
$('#three').animate({top:"+=200px"}).animate({top:"-=200px"})animate({left:"+=200px"}).animate({left:"-=200px"});
$('#four').animate({top:"+=200px"}).animate({top:"-=200px"})animate({left:"+=200px"}).animate({left:"-=200px"});
$('#five')animate({top:"+=200px"}).animate({top:"-=200px"})animate({left:"+=200px"}).animate({left:"-=200px"})animate({top:"+=200px"}).animate({top:"-=200px"})animate({left:"+=200px"}).animate({left:"-=200px"});
Two things stand out about jQuery's coding syntax for animations. For one, the dom element selected and the animation to use are closely tied together. The consequence is that although #three and #four both use the same animation, they need to spell it out both times. Furthermore, #five acts out the animation performed by #three and #four but twice. This means it needs to call animate 8 times. So this gets quite messy. And when animations get longer and more complex, can quickly become unmanageable. It would be much better if we could reuse the animations that we've created.
And thus enters the inspiration for our project. Here we have code that does the same thing as the code above.
Our Code
moveDU = createAnim({top:"+=200px"}, {top:"-=200px"});
moveRL = createAnim({left:"+=200px"}, {left:"-=200px"});
moveAround = createAnim(moveDownUp, moveRightLeft);
$('#one').execAnim(moveDU);
$('#two').execAnim(moveRL);
$('#three').execAnim(moveAround);
$('#four').execAnim(moveAround);
$('#five').execAnim(moveAround, moveAround);
Composability and Reuseability
Here, we created two animation sequences and stored them in containers. We then create a new animation sequence from the first two that we've created. Now we can proceed to use them on the divs. The animation sequences that we create can then be reused over and over on new dom elements. The animation sequences that we create are composable and can become the building blocks in newer animations.
Furthermore, we have created new operator methods that could act on animation sequences to give the user even more expressive power. For example:
moveDiagonal = combineAnim(moveDU, moveRL);
This animation sequence is created by combining our previous two animations and merging/splicing them together. The resulting animation moves right and down at the same time, resulting in a new behavior.
Expressabiliy. As we were creating our language, we thought, wouldn't it be neat if instead of constantly having to specify the CSS params to tweak each attribute when we animate, we could just tell it to move with a word? With that in mind, we decided to to implement expressability.
$('#one').createAnim("moveRight", "moveDown")
The idea behind expressability is that you just pass strings to createAnim, based on how you want the dom element to act, and createAnim would smartly translate the string into an executable animObject. This idea was unfortunately not explored further because it hampered expressability and due to the difficulty of predicting what a user would want to type.
The Three Demos
Demo 1
Since our plugin is focused on animation, demo 1 is about what kinds of operations our plugin will allow. We will perform simple animations on div squares. At each step, we animate the next square. And each square animation, as we will see, is really the result of previous animations composed, combined, or squash together. We show a short demonstration of each of the animation operator functions.
composeAnim() - takes animObjs, animArrays, or "strings" - returns one animArray
squashAnim() - takes an animArray, and compacts it all into one animObj. the animObj has the keys of all the animObjs in animArray as well as their values smartly combined.
combineAnim() - takes multiple animArrays, and merges animObjs of the same index together
These do all the dirty work of appending, mixing, and merging the animation arrays together. Finally, we have the three key execution functions.
execAnim() - takes arbitrary number of animArrays
execAnimLoop() - takes on animArray and a number of how many times to repeat it
execAnimCall() - takes an animArray and a function. Upon finishing, it calls the function
Demo 2
Demo 2 shows you the general pipeline of how someone who was using our plugin would probably create a complex animation. After the divs, each containing a .png image, are arranged on the html, we animate them.
However, the way we animate them isn't done by multiple tedious calls to animate. Instead we create a few animation sequences, and those sequences are used and reused to make new animation sequences. What started as a short animation in the end, becomes an animation sequence up to 4 anim objects long (longer ones are possible, but this is a demo). We use our execAnimLoop function to call that 4x as well. If this were done with just animate, the animate chain would be 16 calls long. Finally, we use some timers and some looping to achieve a nice looping animation.
Demo 3
This demonstration shows the usage of execAnimLoop and execAnimCall in an html page. It also shows the usage of createimg function that is included in the jQuery plugin that dynamically creates img elements in the scene so that we do not need hard code the images in the body of the html page. createimg function call will take in attributes of that image being defined and will use inline css to change the attributes. As for execAnimLoop, its purpose was stated in the first demonstration, is that it takes an animArray and a number of how many times to repeat it. The purpose of this function call is to create a continuous sequence of animations for an object.As for the other function, execAnimCall, it is best to understand the input that this function takes before knowing what it does. Since it takes an animArray and a function (which is a drawback call that calls the function after evaluating that animArray), it is able to interrupt the flow of movement of an object in a scene. The demonstration shows mario as he moves towards the blocks and suddenly reappears as a different type of mario character with a cape. This was made possible by the execAnimLoop that let mario continuously change his position to the right, and execAnimCall which made possible the changing of mario's img source and changing his movement to move left. Basically, the function of these two functions is move and change movement respectively.
This demonstration also shows the usage of javascripts timer functions: setInterval and clearInterval. setInterval's function is to allow a function call continuously without interruption. This function takes in a function and an integer n representing time in milliseconds. setInterval calls the function every n milliseconds. This function returns a variable id and with this id one is able to interrupt the function and halt it. This continuous interruption of calls will continue until it is disabled by the call to clearInterval. The usage of these two functions created the possibility of having two objects in the scene move continuously in parallel. If one wants an object move continuously without being interrupted, never call clearInterval on the variable id that setInterval returns, after executing a function after n milliseconds.
Studying a Language that Solves a Similar Problem:
In studying a language that solves a similar problem, we take a look at how the class for JavaScript class Animator.js animates objects, a brief description of it is as follows.
In the class Animator.js animations are implemented using composition in which the programmer employs several classes that interact with each other to provide complex behaviour. Furthermore, parameterisation classes accept arguments that alter their behaviour" instead of recurring to the usual inheritance.
We want to achieve a similar effect in jQuery by using this syntactic sugar:
$("#div").execAnimLoop([{left: "-=25px"}], 5);
$("#div").execAnimCall([{left: "-=25px"}, {left:; "+=10px"}],function() {
...
//body of drawback function call
...
);
We used execAnimLoop repeats executes the same animation the given number of times.
On the other hand, execAnimCall can be used to interrupt the movement of an object
by using a drawbackCall function whenever the given animation has ended. e.g. {left:; "+=10px"}
This interrupt is important because if we want to change the direction of an object in the
scene we would have to change the animation given into execAnimLoop.
An example of Animator.js solution to our problem is this:
Suppose we want to create an animator prototype in Animator.js the code would work as follows:
// This object controls the progress of the animation
ex1 = new Animator()
// the Animator's subjects define its behaviour
ex1.addSubject(updateButton);
function updateButton(value) {
$('ex1Button').innerHTML = "Progress: " + Math.round(value * 100) + "%";
}
The language basically creates an object that control animations. Once the control xis created a method is called (addSubject) with an object parameter. This parameter is a div that can be modified.
One limitation of the language is that since it is written in JavaScript there is no rotation. Aside from that limitation there is no other limitations except for 3D animations which are really difficult to do.
Implementation
For our implementation in jQuery, we implement animation effectively by translating jQuery's animate function calls. In order to separate the query from the animate call, we abstract away the argument that jQuery's animate would normally take into objects, which we call animObjects. We abstract away the call to the jQuery's animate function by wrapping it inside "execAnim" functions, which can operate on arrays of animObjects. Then by making various operators for merging and concatenating different animArrays, we effectively achieve animative composability. animObjs could be saved, reused, and spliced smartly together, and execAnim would be able to carry out the animation.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment