158 lines
No EOL
4.3 KiB
JavaScript
158 lines
No EOL
4.3 KiB
JavaScript
|
|
/*
|
|
The interface is like a flywheel.
|
|
*/
|
|
export class Flywheel {
|
|
constructor() {
|
|
this.value = 0.; // start at 0 - gradual meter
|
|
this.stage = 0.; // start at 0 - the various stages
|
|
|
|
this.f_falloff = (value) => value / 20; // value at which it reduces per second
|
|
this.f_stage = (value) => 5 * Math.log10(value); // value to stage calculation
|
|
|
|
this.value_min = 0;
|
|
this.value_max = 100; // gives stage 0-9
|
|
|
|
// this.interval = window.setInterval(this.step, 50)
|
|
this.time = null;
|
|
window.requestAnimationFrame(this.step.bind(this));
|
|
// TODO: once/twice per second should be enough! + on release (add())
|
|
|
|
this.effects = {
|
|
'shape': new ShapeEffect(),
|
|
'video': new VideoEffect(),
|
|
}
|
|
}
|
|
|
|
step(time) {
|
|
if (this.time === null) {
|
|
// first run
|
|
this.time = time;
|
|
window.requestAnimationFrame(this.step.bind(this));
|
|
return;
|
|
}
|
|
|
|
if (time - this.time < 500) {
|
|
window.requestAnimationFrame(this.step.bind(this));
|
|
return;
|
|
}
|
|
|
|
const dt = time - this.time;
|
|
this.time = time;
|
|
|
|
this.value -= this.f_falloff(this.value) * dt / 1000; // linear falloff
|
|
|
|
if (this.value < 0) {
|
|
this.value = 0;
|
|
}
|
|
// console.log(this.value,this.falloff, dt,this.time);
|
|
|
|
// TODO: check if this should be different
|
|
|
|
const stage = Math.max(0, Math.floor(this.f_stage(this.value)));
|
|
if (stage != this.stage) {
|
|
this.changeStage(stage);
|
|
}
|
|
|
|
window.requestAnimationFrame(this.step.bind(this));
|
|
}
|
|
|
|
add(increment) {
|
|
this.value += typeof increment == 'undefined' ? 1 : increment;
|
|
// cap:
|
|
if (this.value > this.value_max) this.value = this.value_max;
|
|
}
|
|
|
|
changeStage(stage) {
|
|
this.stage = stage;
|
|
console.log('stage now at', this.stage);
|
|
for (let fx of Object.values(this.effects)) {
|
|
fx.setStageHandler(this.stage);
|
|
}
|
|
}
|
|
}
|
|
|
|
function effect(start_stage, end_stage) {
|
|
return class Effect {
|
|
constructor() {
|
|
this.enabled = false;
|
|
this.start_stage = start_stage;
|
|
this.end_stage = end_stage;
|
|
this.intensity = 0;
|
|
this.intensity_easing = (t) => t; // 0 < t <= 1: use this to make effect eg. more eased
|
|
}
|
|
|
|
setStageHandler(stage) {
|
|
if (stage < this.start_stage || stage > this.end_stage) {
|
|
this.disable(stage);
|
|
} else {
|
|
this.enable(stage);
|
|
}
|
|
}
|
|
|
|
enable(stage) {
|
|
if (!this.enabled) {
|
|
this.enabled = true;
|
|
this.enableHandler();
|
|
}
|
|
|
|
const ds = this.end_stage - this.start_stage + 1;
|
|
if (ds === 1) {
|
|
this.setIntensity(1);
|
|
} else {
|
|
const s = stage - this.start_stage + 1;
|
|
const t = s / ds;
|
|
this.setIntensity(this.intensity_easing(t));
|
|
}
|
|
}
|
|
|
|
disable(stage) {
|
|
if (this.enabled) {
|
|
this.enabled = false;
|
|
this.disableHandler();
|
|
}
|
|
}
|
|
|
|
setIntensity(intensity) {
|
|
if (intensity !== this.intensity) {
|
|
this.intensity = intensity;
|
|
this.intensityHandler();
|
|
}
|
|
}
|
|
|
|
enableHandler() {/* to override */ }
|
|
disableHandler() {/* to override */ }
|
|
intensityHandler() {/* to override */ }
|
|
}
|
|
|
|
|
|
}
|
|
|
|
class ShapeEffect extends effect(3, 10) {
|
|
getAngles() {
|
|
if (!this.enabled) {
|
|
return 4;
|
|
}
|
|
if (this.intensity < .3) {
|
|
return 3;
|
|
} else if (this.intensity < .7) {
|
|
return 5;
|
|
} else {
|
|
// random pick
|
|
const corners = [3, 4, 5, 7]
|
|
return corners[Math.floor(Math.random() * corners.length)];
|
|
}
|
|
}
|
|
}
|
|
class VideoEffect extends effect(3, 10) {
|
|
// override enable instead of using handler to apply it gradually
|
|
disableHandler() {
|
|
document.getElementById('video_background').style.opacity = 0;
|
|
}
|
|
|
|
intensityHandler() {
|
|
document.getElementById('video_background').style.opacity = this.intensity;
|
|
}
|
|
|
|
|
|
} |