Spaces:
Running
Running
File size: 3,677 Bytes
d5aa24d a659921 13bdc14 a659921 d5aa24d a659921 13bdc14 5f41035 13bdc14 a659921 d5aa24d 13bdc14 a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 5f41035 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 d5aa24d a659921 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | 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();
}
} |