UNPKG

@egjs/view3d

Version:

Fast & Customizable glTF 3D model viewer, packed with full of features!

188 lines (157 loc) 4.65 kB
/* * Copyright (c) 2020 NAVER Corp. * egjs projects are licensed under the MIT license */ import View3D from "../View3D"; import Pose from "../core/Pose"; import Motion from "../core/Motion"; import * as DEFAULT from "../const/default"; import { lerp, circulate } from "../utils"; import CameraControl from "./CameraControl"; /** * Control that animates model without user input */ class AnimationControl implements CameraControl { // Options private _from: Pose; private _to: Pose; private _disableOnFinish: boolean; // Internal values private _view3D: View3D; private _motion: Motion; private _enabled: boolean = false; private _finishCallbacks: Array<(...args: any) => any> = []; public get element() { return null; } /** * Whether this control is enabled or not * @readonly */ public get enabled() { return this._enabled; } /** * Duration of the animation */ public get duration() { return this._motion.duration; } /** * Easing function of the animation */ public get easing() { return this._motion.easing; } /** * Whether this control is animating the camera * @readonly * @type {boolean} */ public get animating() { return this._motion.activated; } public set duration(val: number) { this._motion.duration = val; } public set easing(val: (x: number) => number) { this._motion.easing = val; } /** * Create new instance of AnimationControl * @param from Start pose * @param to End pose * @param {object} options Options * @param {number} [options.duration=500] Animation duration * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Animation easing function */ public constructor(view3D: View3D, from: Pose, to: Pose, { duration = DEFAULT.ANIMATION_DURATION, easing = DEFAULT.EASING, disableOnFinish = true } = {}) { this._view3D = view3D; this._motion = new Motion({ duration, range: DEFAULT.ANIMATION_RANGE, easing }); this._disableOnFinish = disableOnFinish; this.changeStartEnd(from, to); } /** * Destroy the instance and remove all event listeners attached * This also will reset CSS cursor to intial * @returns {void} */ public destroy(): void { this.disable(); } public changeStartEnd(from: Pose, to: Pose) { from = from.clone(); to = to.clone(); from.yaw = circulate(from.yaw, 0, 360); to.yaw = circulate(to.yaw, 0, 360); // Take the smaller degree if (Math.abs(to.yaw - from.yaw) > 180) { to.yaw = to.yaw < from.yaw ? to.yaw + 360 : to.yaw - 360; } this._from = from; this._to = to; } /** * Update control by given deltaTime * @param deltaTime Number of milisec to update * @returns {void} */ public update(deltaTime: number): void { if (!this._enabled) return; const camera = this._view3D.camera; const from = this._from; const to = this._to; const motion = this._motion; motion.update(deltaTime); // Progress that easing is applied const progress = motion.val; camera.yaw = lerp(from.yaw, to.yaw, progress); camera.pitch = lerp(from.pitch, to.pitch, progress); camera.zoom = lerp(from.zoom, to.zoom, progress); camera.pivot = from.pivot.clone().lerp(to.pivot, progress); if (progress >= 1) { if (this._disableOnFinish) { this.disable(); } this._finishCallbacks.forEach(callback => callback()); this.clearFinished(); } } /** * Enable this input and add event listeners * @returns {void} */ public enable(): void { if (this._enabled) return; this._enabled = true; this.reset(); } /** * Disable this input and remove all event handlers * @returns {void} */ public disable(): void { if (!this._enabled) return; this._enabled = false; } public reset() { this._motion.reset(0); this._motion.setEndDelta(1); } /** * Add callback which is called when animation is finished * @param callback Callback that will be called when animation finishes * @returns {void} */ public onFinished(callback: (...args: any) => any): void { this._finishCallbacks.push(callback); } /** * Remove all onFinished callbacks * @returns {void} */ public clearFinished(): void { this._finishCallbacks = []; } /* eslint-disable @typescript-eslint/no-unused-vars */ public resize(size: { width: number; height: number }) { // DO NOTHING } public sync(): void { // Do nothing } /* eslint-enable @typescript-eslint/no-unused-vars */ } export default AnimationControl;