Add existing to tracked
This commit is contained in:
+592
@@ -0,0 +1,592 @@
|
||||
import clone from "../Core/clone.js";
|
||||
import Frozen from "../Core/Frozen.js";
|
||||
import defined from "../Core/defined.js";
|
||||
import DeveloperError from "../Core/DeveloperError.js";
|
||||
import EasingFunction from "../Core/EasingFunction.js";
|
||||
import getTimestamp from "../Core/getTimestamp.js";
|
||||
import TimeConstants from "../Core/TimeConstants.js";
|
||||
import { Tween as TweenJS } from "@tweenjs/tween.js";
|
||||
|
||||
/**
|
||||
* A tween is an animation that interpolates the properties of two objects using an {@link EasingFunction}. Create
|
||||
* one using {@link Scene#tweens} and {@link TweenCollection#add} and related add functions.
|
||||
*
|
||||
* @alias Tween
|
||||
* @constructor
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function Tween(
|
||||
tweens,
|
||||
tweenjs,
|
||||
startObject,
|
||||
stopObject,
|
||||
duration,
|
||||
delay,
|
||||
easingFunction,
|
||||
update,
|
||||
complete,
|
||||
cancel,
|
||||
) {
|
||||
this._tweens = tweens;
|
||||
this._tweenjs = tweenjs;
|
||||
|
||||
this._startObject = clone(startObject);
|
||||
this._stopObject = clone(stopObject);
|
||||
|
||||
this._duration = duration;
|
||||
this._delay = delay;
|
||||
this._easingFunction = easingFunction;
|
||||
|
||||
this._update = update;
|
||||
this._complete = complete;
|
||||
|
||||
/**
|
||||
* The callback to call if the tween is canceled either because {@link Tween#cancelTween}
|
||||
* was called or because the tween was removed from the collection.
|
||||
*
|
||||
* @type {TweenCollection.TweenCancelledCallback}
|
||||
*/
|
||||
this.cancel = cancel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.needsStart = true;
|
||||
}
|
||||
|
||||
Object.defineProperties(Tween.prototype, {
|
||||
/**
|
||||
* An object with properties for initial values of the tween. The properties of this object are changed during the tween's animation.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {object}
|
||||
* @readonly
|
||||
*/
|
||||
startObject: {
|
||||
get: function () {
|
||||
return this._startObject;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* An object with properties for the final values of the tween.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {object}
|
||||
* @readonly
|
||||
*/
|
||||
stopObject: {
|
||||
get: function () {
|
||||
return this._stopObject;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
duration: {
|
||||
get: function () {
|
||||
return this._duration;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The delay, in seconds, before the tween starts animating.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
delay: {
|
||||
get: function () {
|
||||
return this._delay;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the curve for animtion.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {EasingFunction}
|
||||
* @readonly
|
||||
*/
|
||||
easingFunction: {
|
||||
get: function () {
|
||||
return this._easingFunction;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The callback to call at each animation update (usually tied to the a rendered frame).
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {TweenCollection.TweenUpdateCallback}
|
||||
* @readonly
|
||||
*/
|
||||
update: {
|
||||
get: function () {
|
||||
return this._update;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The callback to call when the tween finishes animating.
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @type {TweenCollection.TweenCompleteCallback}
|
||||
* @readonly
|
||||
*/
|
||||
complete: {
|
||||
get: function () {
|
||||
return this._complete;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* @memberof Tween.prototype
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
tweenjs: {
|
||||
get: function () {
|
||||
return this._tweenjs;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Cancels the tween calling the {@link Tween#cancel} callback if one exists. This
|
||||
* has no effect if the tween finished or was already canceled.
|
||||
*/
|
||||
Tween.prototype.cancelTween = function () {
|
||||
this._tweens.remove(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A collection of tweens for animating properties. Commonly accessed using {@link Scene#tweens}.
|
||||
*
|
||||
* @alias TweenCollection
|
||||
* @constructor
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function TweenCollection() {
|
||||
this._tweens = [];
|
||||
}
|
||||
|
||||
Object.defineProperties(TweenCollection.prototype, {
|
||||
/**
|
||||
* The number of tweens in the collection.
|
||||
* @memberof TweenCollection.prototype
|
||||
*
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
length: {
|
||||
get: function () {
|
||||
return this._tweens.length;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a tween for animating between two sets of properties. The tween starts animating at the next call to {@link TweenCollection#update}, which
|
||||
* is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {object} options.startObject An object with properties for initial values of the tween. The properties of this object are changed during the tween's animation.
|
||||
* @param {object} options.stopObject An object with properties for the final values of the tween.
|
||||
* @param {number} options.duration The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
|
||||
* @param {number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
|
||||
* @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
|
||||
* @param {TweenCollection.TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
|
||||
* @param {TweenCollection.TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
|
||||
* @param {TweenCollection.TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
|
||||
* @returns {Tween} The tween.
|
||||
*
|
||||
* @exception {DeveloperError} options.duration must be positive.
|
||||
*/
|
||||
TweenCollection.prototype.add = function (options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options.startObject) || !defined(options.stopObject)) {
|
||||
throw new DeveloperError(
|
||||
"options.startObject and options.stopObject are required.",
|
||||
);
|
||||
}
|
||||
|
||||
if (!defined(options.duration) || options.duration < 0.0) {
|
||||
throw new DeveloperError(
|
||||
"options.duration is required and must be positive.",
|
||||
);
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
if (options.duration === 0.0) {
|
||||
if (defined(options.complete)) {
|
||||
options.complete();
|
||||
}
|
||||
return new Tween(this);
|
||||
}
|
||||
|
||||
const duration = options.duration / TimeConstants.SECONDS_PER_MILLISECOND;
|
||||
const delayInSeconds = options.delay ?? 0.0;
|
||||
const delay = delayInSeconds / TimeConstants.SECONDS_PER_MILLISECOND;
|
||||
const easingFunction = options.easingFunction ?? EasingFunction.LINEAR_NONE;
|
||||
|
||||
const value = options.startObject;
|
||||
const tweenjs = new TweenJS(value);
|
||||
tweenjs.to(clone(options.stopObject), duration);
|
||||
tweenjs.delay(delay);
|
||||
tweenjs.easing(easingFunction);
|
||||
if (defined(options.update)) {
|
||||
tweenjs.onUpdate(function () {
|
||||
options.update(value);
|
||||
});
|
||||
}
|
||||
tweenjs.onComplete(options.complete ?? null);
|
||||
tweenjs.repeat(options._repeat ?? 0.0);
|
||||
|
||||
const tween = new Tween(
|
||||
this,
|
||||
tweenjs,
|
||||
options.startObject,
|
||||
options.stopObject,
|
||||
options.duration,
|
||||
delayInSeconds,
|
||||
easingFunction,
|
||||
options.update,
|
||||
options.complete,
|
||||
options.cancel,
|
||||
);
|
||||
this._tweens.push(tween);
|
||||
return tween;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a tween for animating a scalar property on the given object. The tween starts animating at the next call to {@link TweenCollection#update}, which
|
||||
* is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {object} options.object The object containing the property to animate.
|
||||
* @param {string} options.property The name of the property to animate.
|
||||
* @param {number} options.startValue The initial value.
|
||||
* @param {number} options.stopValue The final value.
|
||||
* @param {number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
|
||||
* @param {number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
|
||||
* @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
|
||||
* @param {TweenCollection.TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
|
||||
* @param {TweenCollection.TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
|
||||
* @param {TweenCollection.TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
|
||||
* @returns {Tween} The tween.
|
||||
*
|
||||
* @exception {DeveloperError} options.object must have the specified property.
|
||||
* @exception {DeveloperError} options.duration must be positive.
|
||||
*/
|
||||
TweenCollection.prototype.addProperty = function (options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const object = options.object;
|
||||
const property = options.property;
|
||||
const startValue = options.startValue;
|
||||
const stopValue = options.stopValue;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(object) || !defined(options.property)) {
|
||||
throw new DeveloperError(
|
||||
"options.object and options.property are required.",
|
||||
);
|
||||
}
|
||||
if (!defined(object[property])) {
|
||||
throw new DeveloperError(
|
||||
"options.object must have the specified property.",
|
||||
);
|
||||
}
|
||||
if (!defined(startValue) || !defined(stopValue)) {
|
||||
throw new DeveloperError(
|
||||
"options.startValue and options.stopValue are required.",
|
||||
);
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
function update(value) {
|
||||
object[property] = value.value;
|
||||
}
|
||||
|
||||
return this.add({
|
||||
startObject: {
|
||||
value: startValue,
|
||||
},
|
||||
stopObject: {
|
||||
value: stopValue,
|
||||
},
|
||||
duration: options.duration ?? 3.0,
|
||||
delay: options.delay,
|
||||
easingFunction: options.easingFunction,
|
||||
update: update,
|
||||
complete: options.complete,
|
||||
cancel: options.cancel,
|
||||
_repeat: options._repeat,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a tween for animating the alpha of all color uniforms on a {@link Material}. The tween starts animating at the next call to {@link TweenCollection#update}, which
|
||||
* is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {Material} options.material The material to animate.
|
||||
* @param {number} [options.startValue=0.0] The initial alpha value.
|
||||
* @param {number} [options.stopValue=1.0] The final alpha value.
|
||||
* @param {number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
|
||||
* @param {number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
|
||||
* @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
|
||||
* @param {TweenCollection.TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
|
||||
* @param {TweenCollection.TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
|
||||
* @param {TweenCollection.TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
|
||||
* @returns {Tween} The tween.
|
||||
*
|
||||
* @exception {DeveloperError} material has no properties with alpha components.
|
||||
* @exception {DeveloperError} options.duration must be positive.
|
||||
*/
|
||||
TweenCollection.prototype.addAlpha = function (options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const material = options.material;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(material)) {
|
||||
throw new DeveloperError("options.material is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const properties = [];
|
||||
|
||||
for (const property in material.uniforms) {
|
||||
if (
|
||||
material.uniforms.hasOwnProperty(property) &&
|
||||
defined(material.uniforms[property]) &&
|
||||
defined(material.uniforms[property].alpha)
|
||||
) {
|
||||
properties.push(property);
|
||||
}
|
||||
}
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (properties.length === 0) {
|
||||
throw new DeveloperError(
|
||||
"material has no properties with alpha components.",
|
||||
);
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
function update(value) {
|
||||
const length = properties.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
material.uniforms[properties[i]].alpha = value.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
return this.add({
|
||||
startObject: {
|
||||
alpha: options.startValue ?? 0.0, // Default to fade in
|
||||
},
|
||||
stopObject: {
|
||||
alpha: options.stopValue ?? 1.0,
|
||||
},
|
||||
duration: options.duration ?? 3.0,
|
||||
delay: options.delay,
|
||||
easingFunction: options.easingFunction,
|
||||
update: update,
|
||||
complete: options.complete,
|
||||
cancel: options.cancel,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a tween for animating the offset uniform of a {@link Material}. The tween starts animating at the next call to {@link TweenCollection#update}, which
|
||||
* is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {Material} options.material The material to animate.
|
||||
* @param {number} options.startValue The initial alpha value.
|
||||
* @param {number} options.stopValue The final alpha value.
|
||||
* @param {number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
|
||||
* @param {number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
|
||||
* @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
|
||||
* @param {TweenCollection.TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
|
||||
* @param {TweenCollection.TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
|
||||
* @returns {Tween} The tween.
|
||||
*
|
||||
* @exception {DeveloperError} material.uniforms must have an offset property.
|
||||
* @exception {DeveloperError} options.duration must be positive.
|
||||
*/
|
||||
TweenCollection.prototype.addOffsetIncrement = function (options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const material = options.material;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(material)) {
|
||||
throw new DeveloperError("material is required.");
|
||||
}
|
||||
if (!defined(material.uniforms.offset)) {
|
||||
throw new DeveloperError("material.uniforms must have an offset property.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const uniforms = material.uniforms;
|
||||
return this.addProperty({
|
||||
object: uniforms,
|
||||
property: "offset",
|
||||
startValue: uniforms.offset,
|
||||
stopValue: uniforms.offset + 1,
|
||||
duration: options.duration,
|
||||
delay: options.delay,
|
||||
easingFunction: options.easingFunction,
|
||||
update: options.update,
|
||||
cancel: options.cancel,
|
||||
_repeat: Infinity,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a tween from the collection.
|
||||
* <p>
|
||||
* This calls the {@link Tween#cancel} callback if the tween has one.
|
||||
* </p>
|
||||
*
|
||||
* @param {Tween} tween The tween to remove.
|
||||
* @returns {boolean} <code>true</code> if the tween was removed; <code>false</code> if the tween was not found in the collection.
|
||||
*/
|
||||
TweenCollection.prototype.remove = function (tween) {
|
||||
if (!defined(tween)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const index = this._tweens.indexOf(tween);
|
||||
if (index !== -1) {
|
||||
tween.tweenjs.stop();
|
||||
if (defined(tween.cancel)) {
|
||||
tween.cancel();
|
||||
}
|
||||
this._tweens.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all tweens from the collection.
|
||||
* <p>
|
||||
* This calls the {@link Tween#cancel} callback for each tween that has one.
|
||||
* </p>
|
||||
*/
|
||||
TweenCollection.prototype.removeAll = function () {
|
||||
const tweens = this._tweens;
|
||||
|
||||
for (let i = 0; i < tweens.length; ++i) {
|
||||
const tween = tweens[i];
|
||||
tween.tweenjs.stop();
|
||||
if (defined(tween.cancel)) {
|
||||
tween.cancel();
|
||||
}
|
||||
}
|
||||
tweens.length = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether this collection contains a given tween.
|
||||
*
|
||||
* @param {Tween} tween The tween to check for.
|
||||
* @returns {boolean} <code>true</code> if this collection contains the tween, <code>false</code> otherwise.
|
||||
*/
|
||||
TweenCollection.prototype.contains = function (tween) {
|
||||
return defined(tween) && this._tweens.indexOf(tween) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the tween in the collection at the specified index. Indices are zero-based
|
||||
* and increase as tweens are added. Removing a tween shifts all tweens after
|
||||
* it to the left, changing their indices. This function is commonly used to iterate over
|
||||
* all the tween in the collection.
|
||||
*
|
||||
* @param {number} index The zero-based index of the tween.
|
||||
* @returns {Tween} The tween at the specified index.
|
||||
*
|
||||
* @example
|
||||
* // Output the duration of all the tweens in the collection.
|
||||
* const tweens = scene.tweens;
|
||||
* const length = tweens.length;
|
||||
* for (let i = 0; i < length; ++i) {
|
||||
* console.log(tweens.get(i).duration);
|
||||
* }
|
||||
*/
|
||||
TweenCollection.prototype.get = function (index) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(index)) {
|
||||
throw new DeveloperError("index is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
return this._tweens[index];
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the tweens in the collection to be at the provide time. When a tween finishes, it is removed
|
||||
* from the collection.
|
||||
*
|
||||
* @param {number} [time=getTimestamp()] The time in seconds. By default tweens are synced to the system clock.
|
||||
*/
|
||||
TweenCollection.prototype.update = function (time) {
|
||||
const tweens = this._tweens;
|
||||
|
||||
let i = 0;
|
||||
time = defined(time)
|
||||
? time / TimeConstants.SECONDS_PER_MILLISECOND
|
||||
: getTimestamp();
|
||||
while (i < tweens.length) {
|
||||
const tween = tweens[i];
|
||||
const tweenjs = tween.tweenjs;
|
||||
|
||||
if (tween.needsStart) {
|
||||
tween.needsStart = false;
|
||||
tweenjs.start(time);
|
||||
} else if (tweenjs.update(time)) {
|
||||
i++;
|
||||
} else {
|
||||
// there's a chance that the update callback has side effects that clear the list of tweens and/or adds new tweens
|
||||
// if it's the case that the update callback 1) clears all tweens held in the scene, then 2) adds new tweens
|
||||
// the splice operation below will not be operating on the original tween, but one of the unprocessed tweens added
|
||||
// from the update callback
|
||||
if (tweens[i]?.needsStart) {
|
||||
continue;
|
||||
}
|
||||
tweenjs.stop();
|
||||
tweens.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that will execute when a tween completes.
|
||||
* @callback TweenCollection.TweenCompleteCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that will execute when a tween updates.
|
||||
* @callback TweenCollection.TweenUpdateCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that will execute when a tween is cancelled.
|
||||
* @callback TweenCollection.TweenCancelledCallback
|
||||
*/
|
||||
export default TweenCollection;
|
||||
Reference in New Issue
Block a user