API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/animation/cameraFollowAnimation.js

/**
 A **CameraFollowAnimation** makes the {{#crossLink "Scene"}}{{/crossLink}}'s {{#crossLink "Camera"}}{{/crossLink}} dynamically follow a
 target component in order to keep it entirely in camera.

 <a href="../../examples/#animation_camera_follow_entity"><img src="http://i.giphy.com/l0HlHcuzAjhMQ8YSY.gif"></img></a>

 ## Overview

 * A target can be an instance or ID of any {{#crossLink "Component"}}{{/crossLink}} subtype that provides a World-space AABB.
 * Can be configured to either fly or jump to each updated position of the target.
 * Can be configured to automatically adjust the distance between the {{#crossLink "Camera"}}{{/crossLink}}'s {{#crossLink "Lookat"}}{{/crossLink}}'s {{#crossLink "Lookat/eye:property"}}{{/crossLink}} and {{#crossLink "Lookat/look:property"}}{{/crossLink}} to keep the target fitted to the view volume.

 ## Examples

 * [Following an Mesh with the Camera](../../examples/#animation_camera_follow_entity)
 * [Following an Mesh with the Camera, keeping Mesh fitted to view volume](../../examples/#animation_camera_follow_entity_fitToView)

 ## Usage

 In the example below, we'll use a CameraFollowAnimation to automatically follow an {{#crossLink "Mesh"}}{{/crossLink}}. Our CameraFollowAnimation's
 {{#crossLink "CameraFollowAnimation/fit:property"}}{{/crossLink}} property is set ````true````, which causes it to automatically
 keep the {{#crossLink "Mesh"}}{{/crossLink}} fitted to the view volume. Although we can orbit the
 {{#crossLink "Mesh"}}{{/crossLink}} using the {{#crossLink "CameraControl"}}{{/crossLink}}, we you can't control the
 distance of the {{#crossLink "Camera"}}{{/crossLink}} from the {{#crossLink "Mesh"}}{{/crossLink}} because our CameraFollowAnimation
 automatically controls that distance in order to do the automatic fitting.

 ````javascript
 // Create a red torus Mesh with a Translate modelling transform
 // that allows it to move around in World-space
 var mesh = new xeogl.Mesh({
     geometry: new xeogl.TorusGeometry(),
     material: new xeogl.PhongMaterial({
          diffuse: [1, 0.3, 0.3]
     }),
     transform: new xeogl.Translate({
         xyz: [0,0,0]
     })
 });

 // Create a CameraFollowAnimation that makes the Scene's Camera's Lookat follow the Mesh while keeping it
 // fitted to the view volume. The CameraFollowAnimation will jump to each new location, and since an update will occur on every frame,
 // the effect will be as if we're smoothly flying after the Mesh. If the updates occur sporadically,
 // then we would probably instead configure it to fly to each update, to keep the animation smooth.
 var cameraFollowAnimation = new xeogl.CameraFollowAnimation({
     target: mesh,
     fit: true,   // Fit target to view volume
     fitFOV: 35,  // Target will occupy 35 degrees of the field-of-view
     fly: false // Jump to each updated boundary extents
 });

 // Create a SplineCurve along which we'll animate our Mesh
 var curve = new xeogl.SplineCurve({
     points: [
         [-10, 0, 0],
         [-5, 15, 0],
         [20, 15, 0],
         [10, 0, 0]
     ]
 });

 // Bind the Mesh Translate to a point on the SplineCurve
 curve.on("point", function(point) {
     mesh.transform.xyz = point;
 });

 // Animate the point along the SplineCurve using the Scene clock
 curve.scene.on("tick", function(e) {
     curve.t = (e.time - e.startTime) * 0.01;
 });

 // Allow user control of the Camera with mouse and keyboard
 // (zooming will be overridden by the auto-fitting configured on our CameraFollowAnimation)
 new xeogl.CameraControl();
 ````

 @class CameraFollowAnimation
 @module xeogl
 @submodule animation
 @constructor
 @param [scene] {Scene} Parent {{#crossLink "Scene"}}Scene{{/crossLink}} - creates this CameraFollowAnimation within xeogl's default {{#crossLink "Scene"}}Scene{{/crossLink}} by default.
 @param [cfg] {*} Configs
 @param [cfg.id] {String} Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted.
 @param [cfg.meta] {*} Optional map of user-defined metadata to attach to this CameraFollowAnimation.
 @param [cfg.target] {Number|String|Camera} ID or instance of a {{#crossLink "Component"}}{{/crossLink}} to follow.
 Must be within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this CameraFollowAnimation. Defaults to the
 parent {{#crossLink "Scene"}}Scene{{/crossLink}}.
 @param [cfg.fly] {Boolean}  Indicates whether this CameraFollowAnimation will either fly or jump to each updated position of the
 target {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}}.
 @param [cfg.fit] {Boolean} When true, will ensure that this CameraFollowAnimation automatically adjusts the distance between the {{#crossLink "Camera"}}{{/crossLink}}'s {{#crossLink "Lookat"}}{{/crossLink}}'s {{#crossLink "Lookat/eye:property"}}{{/crossLink}} and {{#crossLink "Lookat/look:property"}}{{/crossLink}} to keep the target {{#crossLink "Boundary3D"}}{{/crossLink}} fitted to the view volume.
 @param [cfg.fitFOV=45] {Number} How much of field-of-view, in degrees, that a target {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}} should
 fill the canvas when fitting to camera.
 @param [cfg.trail] {Boolean} When true, will cause this CameraFollowAnimation to point the camera in the direction that it is travelling.
 @extends Component
 */
xeogl.CameraFollowAnimation = class xeoglCameraFollowAnimation extends xeogl.Component {

    init(cfg) {

        super.init(cfg);

        this._cameraFlight = new xeogl.CameraFlightAnimation(this);

        this.target = cfg.target;
        this.fly = cfg.fly;
        this.fit = cfg.fit;
        this.fitFOV = cfg.fitFOV;
        this.trail = cfg.trail;
    }

    _update() {
        const target = this._attached.target;
        if (target && this._cameraFlight) { // This component might have been destroyed
            if (this._fly) {
                this._cameraFlight.flyTo({
                    aabb: target.aabb
                });
            } else {
                this._cameraFlight.jumpTo({
                    aabb: target.aabb
                });
            }
        }
    }

    /**
     * The World-space {{#crossLink "Boundary3D"}}{{/crossLink}} followed by this CameraFollowAnimation.
     *
     * Must be within the same {{#crossLink "Scene"}}{{/crossLink}} as this CameraFollowAnimation. Defaults to the parent
     * {{#crossLink "Scene"}}Scene{{/crossLink}} when set to a null or undefined value.
     *
     * @property target
     * @type Component
     */
    set target(value) {
        /**
         * Fired whenever this CameraFollowAnimation's {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}} property changes.
         *
         * @event target
         * @param value The property's new value
         */
        this._attach({
            name: "target",
            type: "xeogl.Component",
            component: value,
            sceneDefault: false,
            on: {
                boundary: {
                    callback: this._needUpdate,
                    scope: this
                }
            }
        });
        this._needUpdate();
    }

    get target() {
        return this._attached.target;
    }

    /**
     * Indicates whether this CameraFollowAnimation will either fly or jump to each updated position of the
     * {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}}.
     *
     * Leave this false if the target updates continuously, otherwise leave it true
     * if you want the camera to fly smoothly to each updated target extents
     * for a less disorientating experience.
     *
     * @property fly
     * @type Boolean
     * @default false
     */
    set fly(value) {
        this._fly = !!value;
    }

    get fly() {
        return this._fly;
    }

    /**
     * When true, will ensure that this CameraFollowAnimation always adjusts the distance between the {{#crossLink "Camera"}}
     * camera{{/crossLink}}'s {{#crossLink "Lookat/eye:property"}}eye{{/crossLink}} and {{#crossLink "Lookat/look:property"}}{{/crossLink}}
     * positions so as to ensure that the {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}} is always filling the view volume.
     *
     * When false, the eye will remain at its current distance from the look position.
     *
     * @property fit
     * @type Boolean
     * @default true
     */
    set fit(value) {
        this._cameraFlight.fit = value !== false;
        this._needUpdate();
    }

    get fit() {
        return this._cameraFlight.fit;
    }

    /**
     * When {{#crossLink "CameraFollowAnimation/fit:property"}}{{/crossLink}} is set, to fit the target
     * {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}} in view, this property indicates how much
     * of the total field-of-view, in degrees, that the {{#crossLink "CameraFollowAnimation/target:property"}}{{/crossLink}} should fill.
     *
     * @property fitFOV
     * @default 45
     * @type Number
     */
    set fitFOV(value) {
        this._cameraFlight.fitFOV = value;
        this._needUpdate();
    }

    get fitFOV() {
        return this._cameraFlight.fitFOV;
    }

    /**
     * When true, will cause this CameraFollowAnimation to point the {{#crossLink "Camera"}}{{/crossLink}}
     * in the direction that it is travelling.
     *
     * @property trail
     * @type Boolean
     * @default false
     */
    set trail(value) {
        this._cameraFlight.trail = value;
    }

    get trail() {
        return this._cameraFlight.trail;
    }
};