threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
211 lines • 7.29 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Clock, EventDispatcher } from 'three';
import { uiButton, uiFolderContainer, uiInput, uiToggle } from 'uiconfig.js';
import { onChangeDispatchEvent, serializable, serialize } from 'ts-browser-helpers';
let ViewerTimeline = class ViewerTimeline extends EventDispatcher {
constructor() {
super(...arguments);
this._time = 0;
/**
* in secs
*/
this.delta = 0;
/**
* Maximum time in secs.
* This is used to limit the time in the timeline.
* Set to 0 to disable the limit.
*/
this.endTime = 2;
/**
* Reset the timeline time to 0 when the timeline ends.
* It is applicable only when the timeline is running and `endTime` is set to a value greater than 0.
* This can be used to loop the timeline.
* @default true
*/
this.resetOnEnd = true;
/**
* Stop the timeline when it reaches the end.
* This is applicable only when the timeline is running and `endTime` is set to a value greater than 0.
* This can be used to stop the timeline when it reaches the end.
* It is separate from `resetOnEnd`, the timeline is stopped and then reset when both are true.
* @default false
*/
this.stopOnEnd = false;
/**
* Running state.
*/
this.running = false;
this._clock = new Clock(false);
this._start = false;
this._stop = false;
this._reset = false;
// this is seek, not step actually
this._step = false;
}
/**
* Current time in secs
*/
get time() {
return this._time;
}
/**
* Set the current time and step a frame
* @param value
*/
set time(value) {
if (this._time === value)
return;
this.setTime(value, true);
}
/**
* Returns true if the timeline is running or if it is set to step this/next frame.
*/
shouldRun() {
return this.running || this._step;
}
start() {
this._start = true; // start next frame
if (this._stop)
this._stop = false;
if (this._step)
this._step = false;
}
stop() {
this._stop = true; // stop next frame
if (this._start)
this._start = false;
if (this._step)
this._step = false;
}
// @uiButton('Step')
// step() {
// if ((this.running || this._start) && !this._stop) return
// this._step = true // stop next frame
// }
reset() {
this._reset = true; // reset next frame
if (this._step)
this._step = false; // dont step if called before reset
// if (this._start) this._start = false
// if (this._stop) this._stop = false
}
update(viewer) {
this._refreshParams();
if (!this.running) {
this.delta = this._clock.getDelta(); // this will return 0 always
this.time = this._clock.elapsedTime;
return;
}
const d = viewer.getPlugin('ProgressivePlugin')?.postFrameConvergedRecordingDelta();
if (d && d > 0) {
// recorded frame
this.delta = d / 1000;
this._clock.oldTime += d;
this._clock.elapsedTime += this.delta;
this.time = this._clock.elapsedTime;
// viewer.setDirty(this) // for next frame
this.dispatchEvent({ type: 'update' });
}
else if (d !== undefined && d === 0) {
// recording, not converged yet.
this.delta = 0;
this.time = this._clock.elapsedTime;
}
else if (d === undefined || d < 0) {
// not recording
this.delta = this._clock.getDelta(); // this updates oldTime and elapsedTime
this.time = this._clock.elapsedTime;
// viewer.setDirty(this) // for next frame
this.dispatchEvent({ type: 'update' });
}
this._refreshParams();
}
_refreshParams() {
const isEnd = this.endTime > 0 && this.time >= this.endTime && this.running;
const isReset = this.resetOnEnd && isEnd;
const isStop = this.stopOnEnd && isEnd;
if (this._stop || isStop) {
this._clock.stop();
this._start = false;
this._stop = false;
this.running = this._clock.running;
this.dispatchEvent({ type: 'stop' });
}
if (this._start) {
this._clock.start();
this._clock.elapsedTime = this.time;
this._start = false;
this.running = this._clock.running;
this.dispatchEvent({ type: 'start' });
}
if (this._reset || isReset) {
this._clock.elapsedTime = 0;
this.time = 0;
this.delta = 0;
this._reset = false;
this.dispatchEvent({ type: 'reset' });
}
this.running = this._clock.running;
}
// todo better name
update2(_viewer) {
this._step = false;
}
setTime(t, stepFrame = true) {
if (t < 0)
t = 0;
this._clock.elapsedTime = t;
this._time = t;
this.delta = 0; // reset delta
// this._start = false
// this._stop = false
this._reset = false;
if (!this._start)
this._step = stepFrame;
this.dispatchEvent({ type: 'update' });
}
};
__decorate([
uiInput('Time', { readOnly: true })
], ViewerTimeline.prototype, "time", null);
__decorate([
uiInput('Delta', { readOnly: true })
], ViewerTimeline.prototype, "delta", void 0);
__decorate([
uiInput('Max Time'),
serialize(),
onChangeDispatchEvent('endTimeChanged')
], ViewerTimeline.prototype, "endTime", void 0);
__decorate([
uiToggle('Reset on End'),
serialize(),
onChangeDispatchEvent('resetOnEndChanged')
], ViewerTimeline.prototype, "resetOnEnd", void 0);
__decorate([
uiToggle('Stop on End'),
serialize(),
onChangeDispatchEvent('stopOnEndChanged')
], ViewerTimeline.prototype, "stopOnEnd", void 0);
__decorate([
uiInput('Running', { readOnly: true })
], ViewerTimeline.prototype, "running", void 0);
__decorate([
uiButton('Start')
], ViewerTimeline.prototype, "start", null);
__decorate([
uiButton('Stop')
], ViewerTimeline.prototype, "stop", null);
__decorate([
uiButton('Reset')
], ViewerTimeline.prototype, "reset", null);
ViewerTimeline = __decorate([
serializable('ViewerTimeline'),
uiFolderContainer('Timeline')
], ViewerTimeline);
export { ViewerTimeline };
//# sourceMappingURL=ViewerTimeline.js.map