I am trying to code an animated progress wheel in Angular 20. My animation works in a vanilla javascript environment, but when ported to Angular, nothing draws on the canvas and I'm not sure why. I've searched online and the only examples I can find of trying to do this don't work (issues with `this`, which is why I had to bind the values I need to the animation method). I've read about `this`, and have tried what I can, but have reached a point where I'm not sure what is going wrong. Here is my component. There's a Stackblitz link at the bottom reproducing the issue. Component: import { Component, computed, input, signal, OnInit, Signal, ViewChild, ElementRef, } from '@angular/core'; @Component({ selector: 'app-progress-wheel', template: `<canvas #myCanvas id="canvas" width="150" height="150" style="border:1px solid #000000;"> Unsupported </canvas>`, }) export class ProgressWheelComponent implements OnInit { public maxProgress = input<number>(1); public minProgress = input<number>(1); public completed = input<number>(0); @ViewChild('myCanvas') private canvas: ElementRef<HTMLCanvasElement>; private context: CanvasRenderingContext2D; private progressAngle: Signal<number>; private extraAngle: Signal<number>; private twoPi = 2 * Math.PI; private maxIterations = 100; private animationId: number = 0; constructor() {} ngOnInit() { this.initializeAngles(); } ngAfterViewInit(): void { this.context = this.canvas.nativeElement.getContext('2d'); this.animationId = requestAnimationFrame( this.animate.bind( this, this.maxIterations, this.progressAngle(), this.extraAngle(), this.context ) ); } ngOnDestroy(): void { if (this.animationId) { cancelAnimationFrame(this.animationId); } } private initializeAngles(): void { const extraCompleted = computed(() => Math.max(this.completed() - this.minProgress(), 0) ); const amountCompletedFraction = computed( () => (this.completed() - extraCompleted()) / this.minProgress() ); this.progressAngle = computed(() => amountCompletedFraction() * this.twoPi); this.extraAngle = computed(() => extraCompleted() * this.twoPi); } private animate(maxIterations, progressAngle, extraAngle, context): void { let i = 0; let j = 0; const ctx = context; if (i <= maxIterations || j <= maxIterations) { ctx.save(); ctx.clearRect(0, 0, 150, 150); ctx.translate(75, 75); ctx.scale(0.5, 0.5); ctx.rotate(-Math.PI / 2); if (i <= maxIterations) { ctx.beginPath(); ctx.lineWidth = 8; ctx.strokeStyle = '#325FA2'; ctx.arc(0, 0, 70, 0, progressAngle * (i / maxIterations), false); ctx.stroke(); i++; } else { ctx.beginPath(); ctx.lineWidth = 8; ctx.strokeStyle = '#325FA2'; ctx.arc(0, 0, 70, 0, progressAngle * (i / maxIterations), false); ctx.stroke(); ctx.beginPath(); ctx.strokeStyle = '#FF0000'; ctx.arc( 0, 0, 70, progressAngle, progressAngle + extraAngle * (j / maxIterations), false ); ctx.stroke(); j++; } ctx.restore(); this.animationId = requestAnimationFrame( this.animate.bind( this, maxIterations, progressAngle, extraAngle, context ) ); } } } StackBlitz: https://stackblitz.com/edit/stackblitz-starters-2bzndbtw?file=src/progress-wheel.component.ts Continue reading...