Fourier_face / src /frontend /js /animation_controller.js
Pastaaaaa2003's picture
yay app ready?
dc43ffb
Raw
History Blame Contribute Delete
3.68 kB
import EpicycleSystem from './epicycle_system.js';
export default class AnimationController {
constructor(canvasId, epicycleData) {
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.width = this.canvas.width;
this.height = this.canvas.height;
// Calculate total extent of all circles
let totalRadius = 0;
for (let [amplitude] of epicycleData) {
totalRadius += Math.abs(amplitude);
}
console.log('Total radius extent:', totalRadius);
// Scale to fit within 60% of canvas size
const targetSize = Math.min(this.width, this.height) * 1;
this.scale = totalRadius > 0 ? targetSize / totalRadius : 1;
console.log('Using scale:', this.scale);
this.epicycleSystem = new EpicycleSystem(epicycleData);
this.isRunning = true;
// NEW: Normalized time system
this.totalSteps = 500; // Total number of discrete steps in one period
this.currentStep = 0; // Current step [0, totalSteps)
this.stepsPerFrame = 1; // How many steps to advance per frame (speed control)
this.xOffset = this.width /2;
this.yOffset = this.height /2 ;
}
update() {
if (this.isRunning) {
// Discrete stepping approach (like the reference code)
this.currentStep += this.stepsPerFrame;
// Wrap around when we complete one period
if (this.currentStep >= this.totalSteps) {
this.currentStep = this.currentStep % this.totalSteps;
// Optionally clear path for clean restart
// this.epicycleSystem.clearPath();
}
// Calculate normalized time t ∈ [0, 1]
const t = this.currentStep / this.totalSteps;
// Update system with normalized time
this.epicycleSystem.updateWithNormalizedTime(t);
/* Alternative: Continuous time approach
this.time += this.speed;
if (this.time >= 1.0) {
this.time = this.time % 1.0;
}
this.epicycleSystem.updateWithNormalizedTime(this.time);
*/
}
}
render() {
this.context.fillStyle = '#000';
this.context.fillRect(0, 0, this.width, this.height);
this.epicycleSystem.render(this.context, this.xOffset, this.yOffset, this.scale);
// Optional: Display current time for debugging
this.context.fillStyle = '#fff';
this.context.font = '14px monospace';
const t = (this.currentStep / this.totalSteps).toFixed(3);
this.context.fillText(`t = ${t}`, 10, 20);
}
loop() {
this.update();
this.render();
requestAnimationFrame(() => this.loop());
}
pause() {
this.isRunning = !this.isRunning;
}
reset() {
this.epicycleSystem.reset();
this.currentStep = 0;
// this.time = 0; // If using continuous time
}
clearPath() {
this.epicycleSystem.clearPath();
}
// NEW: Jump to specific time
seekTo(t) {
// t should be in [0, 1]
this.currentStep = Math.floor(t * this.totalSteps);
this.epicycleSystem.clearPath();
this.epicycleSystem.updateWithNormalizedTime(t);
}
// NEW: Control speed
setSpeed(stepsPerFrame) {
this.stepsPerFrame = stepsPerFrame;
}
start() {
this.loop();
}
}