Tween. Js: Hello,tween.js

What is tween? How to use it? Why do you want to use it?

Tween (animation) (from in-between) is a concept that allows you to change the properties of an object in a smooth manner. You just tell it which properties to change, what final values they should have when the tween finishes running, and how long it will take, and the tween engine will take care of calculating the values from the start point to the end point.

For example, the Position object has x and Y coordinates:

var position = { x: 100, y: 0 }Copy the code

If you want to change the value of the x-coordinate from 100 to 200, you should do this:

Var tween = new tween.Tween(position); var tween = new tween. // Then tell tween we want to animate x in 1000 milliseconds tween. To ({x: 200}, 1000);Copy the code

Usually this is not enough. The tween is already created, but it is not yet active. You need to start it like this:

/ / start tween. Start ();Copy the code

Finally, to do this successfully, you need to call tween. update in the main function, as follows:

animate(); function animate() { requestAnimationFrame(animate); / / [...].  TWEEN.update(); / / [...]. }Copy the code

This will run the tween animation every time you update the frame; Position. x will become 200 after 1 second (1000 ms).

Unless you print out the value of x in the console, you won’t see it change. You may want to use the onUpdate callback:

tween.onUpdate(function(object) {
    console.log(object.x);
});Copy the code

Tips: You may not get object.x here, see the issue I mentioned for details

This function will be called every time the animation is updated; How often this happens depends on a number of factors – for example, how fast (and how busy) the computer or device is.

So far, we’ve only used the tween animation to output values to the console, but you can combine it with the three.js object:

var tween = new TWEEN.Tween(cube.position)
        .to({ x: 100, y: 100, z: 100 }, 10000)
        .start();

animate();

function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();

    threeRenderer.render(scene, camera);
}Copy the code

In this case, because the three.js renderer will see the position of the object before rendering, there is no need to use an explicit onUpdate callback.

You might also notice something different: Tween.js can be chain-called! Each tween function returns a tween instance, so you can rewrite the following code:

var tween = new TWEEN.Tween(position);
tween.to({ x: 200 }, 1000);
tween.start();Copy the code

Change it to this:

var tween = new TWEEN.Tween(position)
    .to({ x: 200 }, 1000)
    .start();Copy the code

You’ll see lots of examples here, so it’s good to get familiar with it! So let’s say 04-Css.

The animation of the tween. Js

Tween.js will not run by itself. You need to explicitly call the update method to tell it when to run. The recommended method is to do this in an active draw loop. This loop is called with requestAnimationFrame for best graphics performance.

Take this example from before:

animate(); function animate() { requestAnimationFrame(animate); / / [...].  TWEEN.update(); / / [...]. }Copy the code

If no arguments are passed when called, UPDATE will determine the current point in time to determine how long it has been since the last run.

Of course, you can also pass an explicit time parameter to update

TWEEN.update(100);Copy the code

Update time = 100 ms You can use it to ensure that all time-dependent functions in your code use the same time value. For example, suppose you have a player and want to run tween synchronously. Your animate function might look something like this:

var currentTime = player.currentTime;
TWEEN.update(currentTime);Copy the code

We use explicit time values for unit tests. You can take a look at the tests.js example to see how we can simulate time passing by calling tween.update () with different values.

Control a tween

The start and stop

So far, we’ve seen the tween.start method, but there are more ways to control individual Tween’s. Perhaps the most important one is the star counterpart: stop. If you want to cancel a tween, just call this method through a separate tween:

tween.stop();Copy the code

Stopping a tween that has never started or stopped has no effect. No errors are thrown.

The start method takes a parameter time. If you use it, the TWEEN will not start immediately until a certain moment, or it will start as soon as possible (i.e., in the next call to Tween.update).

update

The TWEEN also has an update method – this is actually called by tween.update. You don’t usually need to call it directly unless you’re a crazy hacker.

chain

Things get interesting when you order different tems, such as starting another tween immediately after the last one has ended. We call this a chain tween, and we do it using the chain method. So, to get tweenB started on tewwnA:

tweenA.chain(tweenB);Copy the code

Or, for an infinite chain, set tweenA to start as soon as tweenB is done:

tweenA.chain(tweenB);
tweenB.chain(tweenA);Copy the code

View Hello World about infinite chain.

In other cases, you may need to link multiple tween to another tween so that they (linked tween) start animation at the same time:

tweenA.chain(tweenB,tweenC);Copy the code

Warning: Calling tweena.chain (tweenB) actually modifies tweenA, so tweenA always starts when tweenA is done. The return value of chain is just tweenA, not a new tween.

repeat

If you want a tween to repeat forever, you can link to yourself, but it’s better to use the repeat method. It takes an argument describing how many repeats are required after the first tween is completed

tween.repeat(10); // loop 10 times tween.repeat(Infinity); // Infinite loopCopy the code

The total number of tween will be repeated parameters plus an initial tween. To check the Repeat.

yoyo

This feature only works if you use repeat alone. When active, the tween will behave like yoyo, i.e., it will jump between the starting and ending values, rather than repeating the same order from the beginning.

delay

More complex arrangements may require the tween to be delayed before it actually starts running. You can do this using the delay method

tween.delay(1000);
tween.start();Copy the code

Execution will begin 1 second after the start method is called.

Control all tween

You can find the following methods in the TWEEN global object, most of which you don’t normally need to use except for update.

TWEEN.update(time)

We’ve talked about this approach. It is used to update the tween for all activities. If time is not specified, it uses the current time.

TWEEN.getAll and TWEEN.removeAll

Use to get a reference to the active Tweens array and remove them all from the array from just one call each

TWEEN.add(tween) and TWEEN.remove(tween)

Use to add tween to the list of active tween or to remove specific tween from the list separately.

These methods are usually only used internally, but are exposed if you want to do something interesting.

Control tween group

Using the TWEEN singleton to manage TWEEN can cause problems in large applications with many components. In these cases, you may want to create your own smaller tween groups.

Example: Cross component conflicts

Conflicts can occur if you have multiple components using TWEEN and each component wants to manage its own set of TWEEN’s. If one component calls tween.update () or tween.removeall (), the TWEEN of the other components will also be updated or removed.

Create your own tween group

To solve this problem, each component can create its own tween.group instance (which is used internally by the global TWEEN object). These groups can be passed as a second optional argument when instantiating a new tween:

var groupA = new TWEEN.Group(); var groupB = new TWEEN.Group(); var tweenA = new TWEEN.Tween({ x: 1 }, groupA) .to({ x: 10 }, 100) .start(); var tweenB = new TWEEN.Tween({ x: 1 }, groupB) .to({ x: 10 }, 100) .start(); var tweenC = new TWEEN.Tween({ x: 1 }) .to({ x: 10 }, 100) .start(); groupA.update(); // Update only tweenA groupb.update (); // Only update tweenB tween.update (); // Update only tweenC groupa.removeall (); // Remove only tweenA groupb.removeall (); // Remove only tweenB tween.removeall (); // Remove only tweenCCopy the code

In this way, each component can handle creating, updating, and destroying its own set of tween.

Change the easing function

Tween.js will perform interpolation (that is, easing) between values in a linear fashion, so the change will be proportional to the elapsed time. It’s predictable, but it’s also pretty boring visually. Don’t worry – this behavior can be easily changed using the easing method. Such as:

tween.easing(TWEEN.Easing.Quadratic.In);Copy the code

This will lead to a slow start to the final value changes, to the middle speed, and then quickly reached its final value, on the contrary, TWEEN. Much. The Quadratic. Out to accelerate at the beginning, but with the approach of value eventually slowed.

Available Easing functions: tween.easing

Tween.js provides some of the existing easing features. They are grouped according to the equations they represent: linear, quadratic, cubic, quartic, quintic, sine, exponential, circular, elastic, back and bounce, and then the slow types: In, Out and InOut.

These names probably won’t say much to you unless you’re already familiar with the concepts, so you might want to look at the Graphs example, which graphically plots all the curves on a page to compare how they look at a glance.

These features are derived from the original equations Robert Penner generously provided as free software several years ago, but have been optimized to work well with JavaScript.

Use custom easing

You can not only use any of the existing features, but also provide your own, as long as you follow a few conventions:

  • It must accept one argument:
    • k: The easing process, or how long our tween is in place. The allowed values are in the range [0,1].
  • It must return a value based on the input parameter.

The Easing function is called only once per update, no matter how many properties are modified. The result is then used with the initial value and the difference (delta) between this value and the final value, as in this pseudo-code:

easedElapsed = easing(k);
for each property:
    newPropertyValue = initialPropertyValue + propertyDelta * easedElapsed;Copy the code

For the more performance-oriented: Incremental values are computed only when start() is called on the tween.

So, let’s assume that you want to use a custom buffer function that relieves values, but apply math.floor to the output, so that only integer parts are returned, resulting in a kind of stepped output:

function tenStepEasing(k) {
    return Math.floor(k * 10) / 10;
}Copy the code

You can use it by simply calling its easing method, as we saw earlier:

tween.easing(tenStepEasing);Copy the code

See the Graphs for Custom easing Functions example to see this action (and some metaprogramming for generating stepper functions).

The callback function

Another powerful feature is the ability to run its own functionality at specific times in the life cycle of each tween. This is often required when changing properties is not enough.

For example, suppose you’re trying to animate some object that doesn’t have direct access to properties, but requires you to call a setter. You can use the UPDATE callback to read the new update value and then call setters manually. All callback functions take a tween object as their only argument.

var trickyObjTween = new TWEEN.Tween({
    propertyA: trickyObj.getPropertyA(),
    propertyB: trickyObj.getPropertyB()
})
    .to({ propertyA: 100, propertyB: 200 })
    .onUpdate(function(object) {
        object.setA( object.propertyA );
        object.setB( object.propertyB );
    });Copy the code

Or imagine that you want to play sound when a tween starts. You can use the start callback:

var tween = new TWEEN.Tween(obj)
    .to({ x: 100 })
    .onStart(function() {
        sound.play();
    });Copy the code

The scope of each callback is a tween object — in this case, obJ.

onStart

Perform –i.e. before the calculation before the tween begins. Each tween can only be executed once, i.e., it will not run when the tween is repeated by repeat().

It’s great to synchronize to other events or trigger actions that you want to happen when you start a tween.

The tween object is passed in as the first argument.

onStop

Performed when the tween is explicitly stopped by stop(), but on normal completion and before stopping any possible chain tween.

The tween object is passed in as the first argument.

onUpdate

The actual updated value is executed each time the tween is updated.

The tween object is passed in as the first argument.

onComplete

Execute when the tween completes normally (that is, does not stop).

The tween object is passed in as the first argument.

Senior curation

relative

When using the to method, you can also use relative values. When tween is started, tween.js reads the current property value and applies relative values to find the new final value. But you need to use quotes, otherwise the values will be treated as absolute. Let’s look at an example:

// This will make the `x` property be 100, always
var absoluteTween = new TWEEN.Tween(absoluteObj).to({ x: 100 });

// Suppose absoluteObj.x is 0 now
absoluteTween.start(); // Makes x go to 100

// Suppose absoluteObj.x is -100 now
absoluteTween.start(); // Makes x go to 100

// In contrast...

// This will make the `x` property be 100 units more,
// relative to the actual value when it starts
var relativeTween = new TWEEN.Tween(relativeObj).to({ x: "+100" });

// Suppose relativeObj.x is 0 now
relativeTween.start(); // Makes x go to 0 +100 = 100

// Suppose relativeObj.x is -100 now
relativeTween.start(); // Makes x go to -100 +100 = 0Copy the code

View the 09_relative_values example.

An array of tween values

In addition to Tween being absolute or relative, you can also have Tween.js change properties across a series of values. To do this, you only need to specify the values of an array, not a single value of an attribute. Such as:

var tween = new TWEEN.Tween(relativeObj).to({ x: [0, -100, 100] });Copy the code

Will change x from the initial value to 0, -100, and 100.

These values are calculated as follows:

  • First, the tween progress is calculated as usual
  • Progress (0 to 1) is used as input to the interpolation function
  • Generates interpolation based on an array of progress and values

For example, when the tween is just started (progress 0), the interpolation function returns the first value in the array. When the tween is halfway through, the interpolating function returns a value roughly in the middle of the array, and when the tween is over, the interpolating function returns the last value.

You can change the interpolation function using the interpolation method. Such as:

tween.interpolation( TWEEN.Interpolation.Bezier );Copy the code

The following values are available:

  • TWEEN.Interpolation.Linear
  • TWEEN.Interpolation.Bezier
  • TWEEN.Interpolation.CatmullRom

The default is Linear.

Note that the interpolation function is global for all properties tween with arrays in the same tween. You cannot use arrays and linear functions to change property A, nor can you use the same tween to change property B of array B and Bezier functions; You should use two tween objects running on the same object, but modify different properties and use different interpolation functions.

See the 06_array_Interpolation example.

Achieve optimum performance

Tween.js tries to implement itself, but there’s nothing to stop you from using it in a counterproductive way. Here are some ways to avoid slowing your project down when using Tween.js (or when animating a web page).

Use high-performance CSS

When you try to set the position of elements in a page, the simplest solution is to animate the top and left properties, as follows:

var element = document.getElementById('myElement');
var tween = new TWEEN.Tween({ top: 0, left: 0 })
    .to({ top: 100, left: 100 }, 1000)
    .onUpdate(function(object) {
        element.style.top = object.top + 'px';
        element.style.left = object.left + 'px';
    });Copy the code

But this is actually inefficient, because changing these attributes forces the browser to recalculate the layout with each update, which is a very expensive operation. Instead, you should use transform, which does not invalidate the layout and will also be accelerated by hardware when possible, such as:

var element = document.getElementById('myElement'); var tween = new TWEEN.Tween({ top: 0, left: 0 }) .to({ top: 100, left: 100 }, 1000) .onUpdate(function(object) { element.style.transform = 'translate(' + object.left + 'px, ' + object.top + 'px); '; });Copy the code

If you want to learn more about this, check out this article.

However, if your animation needs are very simple, it may be better to use CSS animations or transformations where applicable so that the browser optimizes as much as possible. Tween.js is useful when your animations need to involve complex layouts, that is, you need to synchronize multiple Tween’s together, loop multiple times after completing some action, and so on.

For garbage collector (alias GC)

If you use the onUpdate callback, you need to be very careful with it. Because this function is called many times per second, if each update is expensive, you could end up blocking the main thread with terrible results, or if your operation involves memory allocation, the garbage collector runs too often, with terrible results. So just don’t do one of those things. Keep your onUpdate callbacks lightweight and make sure you use memory profilers as well.

Crazy tween

This is something you might not use very often, but you can use the Tween formula outside of tween.js. After all, they’re just features. So you can use them to compute smooth curves as input data. For example, they are used to generate audio data in this experiment.