Using the BrowserAnimationModule with the HTMLCanvasElement

I am facing an issue while integrating Angular Material Dialog with my component that includes an HTMLCanvas element for drawing. It seems like the BrowserAnimationModule, which is imported in app.module.ts and used by Material Dialog, is causing a delay in displaying the drawing on the canvas. Strangely, nothing gets logged in the console.

whiteboard.component.ts

    export class WhiteboardComponent implements OnInit, OnDestroy {
  

  @ViewChild('whiteboard', {static: true})
  board: ElementRef<HTMLCanvasElement>;
  ctx: CanvasRenderingContext2D;
  active = false;
  htmlCanvas: HTMLElement;
  rectCanvas: ClientRect;
  penSize: number;
  penColor: string;
  subscriptions: Subscription[] = [];

  constructor(private canvasService: CanvasService) {
    this.subscriptions.push(this.canvasService
      .getCanvasEvent()
      .subscribe((data: string) => {
        const img = new Image();
        img.src = data;
        this.ctx.drawImage(img, 0, 0);
      }));
  }
  ngOnDestroy(): void {
    this.subscriptions.forEach(sub => sub.unsubscribe());
  }
  

  sendCanvasData() {
    this.canvasService.sendCanvasData(this.board.nativeElement.toDataURL());
  }

  ngOnInit(): void {
    this.penColor = 'black';
    this.penSize = 5;
    this.rectCanvas = this.htmlCanvas.getBoundingClientRect();
    this.ctx = this.board.nativeElement.getContext('2d');
    // This part is for resizing
    this.board.nativeElement.height = this.board.nativeElement.offsetHeight;
    this.board.nativeElement.width = this.board.nativeElement.offsetWidth;
    // ***********************


    this.board.nativeElement.addEventListener('mousedown', (evt) => {
      this.sendCanvasData();
      this.startDrawing(evt);
    });
    this.board.nativeElement.addEventListener('mouseup', (evt) => {
      this.sendCanvasData();
      this.endDrawing();
    });
    this.board.nativeElement.addEventListener('mousemove', (evt) => {
      this.sendCanvasData();
      this.draw(evt);
    });

  }



  startDrawing(e: MouseEvent): void {

    this.active = true;
    this.draw(e);


  }

  endDrawing(): void {

    this.active = false;
    this.ctx.beginPath();
  }

  draw(e: MouseEvent): void {

    if (!this.active) { return; }

    this.ctx.lineWidth = this.penSize;
    this.ctx.strokeStyle = this.penColor;
    this.ctx.lineCap = 'round';
    this.ctx.lineTo(e.clientX - this.rectCanvas.left, e.clientY - this.rectCanvas.top);
    this.ctx.stroke();
    this.ctx.beginPath();
    this.ctx.moveTo(e.clientX - this.rectCanvas.left, e.clientY - this.rectCanvas.top);

  }


  onClearCanvas(): void {
    this.ctx.clearRect(0, 0, this.board.nativeElement.width, this.board.nativeElement.height);
    this.sendCanvasData();
  }

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule} from '@angular/forms';
import { MaterialModule} from './material/material.module';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormComponent } from './form/form.component';
import { WhiteboardComponent } from './whiteboard/whiteboard.component';
import { ChatComponent } from './chat/chat.component';
import { PlaygroundComponent } from './playground/playground.component';
import { GameInfoFormComponent } from './game-info-form/game-info-form.component';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';


@NgModule({
  declarations: [
    AppComponent,
    FormComponent,
    WhiteboardComponent,
    ChatComponent,
    PlaygroundComponent,
    GameInfoFormComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    // tslint:disable-next-line: deprecation
    HttpClientModule,
    ReactiveFormsModule,
    MaterialModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [GameInfoFormComponent]
})
export class AppModule { }

Answer №1

Consider transferring the majority of your initialization logic from the ngOnInit hook to the ngAfterViewInit hook. This is the ideal hook to use when you need assurance that the component view has been fully rendered.

ngOnInit(): void {
    this.penColor = 'blue';
    this.penSize = 7;
}
ngAfterViewInit(): void {
    this.canvasRect = this.htmlCanvas.getBoundingClientRect();
    this.context = this.board.nativeElement.getContext('2d');
    
    // Handle resizing
    this.board.nativeElement.height = this.board.nativeElement.offsetHeight;
    this.board.nativeElement.width = this.board.nativeElement.offsetWidth;
    // ***********************

    this.board.nativeElement.addEventListener('mousedown', (evt) => {
      this.sendCanvasData();
      this.startDrawing(evt);
    });
    this.board.nativeElement.addEventListener('mouseup', (evt) => {
      this.sendCanvasData();
      this.endDrawing();
    });
    this.board.nativeElement.addEventListener('mousemove', (evt) => {
      this.sendCanvasData();
      this.draw(evt);
    });

  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Storing multiple items in an array using LocalForage

I have a challenge where I need to add multiple items to an array without overriding them. My initial approach was like this: localForage.getItem("data", (err, results) => { console.log('results', results) // var dataArray ...

Guide: How to use multiple observables in resolver in Angular 4

I am looking for a way to retrieve multiple observables or results in my Angular application. Specifically, I want to first load a list of libraries and then load books based on the IDs of those libraries. I prefer not to call a service in the components, ...

What is the process for accessing and updating values within nested form fields in angular2?

I have been working on an Angular 2 application that utilizes Angular reactive forms. I need to retrieve the value of the innermost element and then update that value accordingly. form : FormGroup; constructor(private formBuilder: FormBuilder) { this. ...

When using a ngForm, submitting the form is triggered each time an action button is clicked

I have a form with multiple buttons in my ngForm. Each button has a different action, such as changing the status used for *ngIf condition check. However, every time I click the Create or Upload button, the form is submitted again and a new record is creat ...

Guide on merging non-modular JavaScript files into a single file with webpack

I am trying to bundle a non-modular JS file that uses jQuery and registers a method on $.fn. This JS must be placed behind jQuery after bundling. Here is an example of the structure of this JS file: (function($){ $.fn.splitPane = ... }(JQuery) If y ...

Obtain multiple class instances through HTTP-Get in Angular

Initially, explaining this with my actual code can be confusing, so I'll simplify the issue using a smaller example. Imagine my project retrieves data from 2 tables on the server, employeeDetails and employeeNames. employeeNames: This table consists ...

Adding an arrow to a Material UI popover similar to a Tooltip

Can an Arrow be added to the Popover similar to the one in the ToolTip? https://i.stack.imgur.com/syWfg.png https://i.stack.imgur.com/4vBpC.png Is it possible to include an Arrow in the design of the Popover? ...

When conducting a test, it was found that the JSX element labeled as 'AddIcon' does not possess any construct or call signatures

Here is a code snippet I'm currently working with: const tableIcons: Icons = { Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />), Check: forwardRef((props, ref) => <Check {...props} ref={ref} />) }; const AddIcon ...

Retrieve information for the designated page exclusively

When retrieving data from the backend using a service, I encounter an issue where the system may slow down if 2000 records are returned in one request. To address this, I would like to display only 10 records per page and fetch the next 10 records with eac ...

What steps should I take to troubleshoot an error with accessing 'request.body' within an async function that is returning a 'ReadableStream' object instead of the data I was expecting?

While developing my CRUD functionality in Next.js with TypeScript and Prisma, I encountered an issue with the PUT method. The GET method handler works fine, but for some reason, the PUT method is causing errors that I'm struggling to resolve. When in ...

What is the best way to compress a file for transfer to a server using gzip?

While attempting to upload a file and send it to the server via a REST API, I am looking for a reliable method to gzip the file. Unfortunately, there is limited documentation available on this topic. Can anyone suggest the most effective approach to achiev ...

Angular version 7.2.1 encounters an ES6 class ReferenceError when attempting to access 'X' before it has been initialized

I have encountered an issue with my TypeScript class: export class Vehicule extends TrackableEntity { vehiculeId: number; constructor() { super(); return super.proxify(this); } } The target for my TypeScript in tsconfig.json is set to es6: ...

What could be causing the Toast message to not show up in react-native-root-toast?

Incorporated react-native-root-toast into my expo project running on expo 51. Please see the code snippet below for reference: const toastColors = { 'error': { color: '#DA5C53', iconName: <WarningIcon size="5 ...

Building with Angular seems to be dragging on forever

Working with Angular 6.7 on a finance application that consists of over 80 modules. When I run the build using the command: node --max_old_space_size=16384 ./node_modules/@angular/cli/bin/ng build --prod The build process takes more than 90 minutes to com ...

Trouble configuring a React TypeScript router has arisen

Recently, I have successfully set up multiple routers in TypeScript. However, I am facing challenges in implementing the same in a new project for some unknown reason. import React from 'react'; import Container from './Components/Containers ...

Avoid the sudden change in page content when using Router.Navigate

When the link below is clicked, the current page jumps to the top before proceeding to the next page. <a href="javascript:void(0);" (click)="goToTicket(x.refNo, $event)">{{x.ticketTitle}}</a> component.ts goToTicket(refNo, e) { e.prev ...

Startup with a sleek fade-in animation

After multiple attempts following tutorials, I am still struggling to get a div in Angular to fade in when my page loads. Despite not receiving any errors, the implementation is not working as expected. Here's a glimpse of the current state of the ap ...

What steps can be taken to effectively build a test suite architecture using Jest?

After exploring all the available resources on the Jest documentation website, including various guides and examples, I have yet to find a solution to my specific question. I am in search of a methodology that would enable me to individually run test case ...

When utilizing React and Expressjs to upload a file through REST, the request seems to stall indefinitely

Seeking assistance with a simple React page containing a form for file selection and submission. The file is uploaded to the server via a POST request using axios. Here's the code snippet for the client-side: import React, { useState } from "reac ...

Eliminate information from Firestore with Angular

https://i.sstatic.net/MFKHB.png I encountered an issue while attempting to delete data from Firestore. Fetching and adding data is functioning correctly, but when attempting to delete data, it does not get removed and no error is displayed on the console. ...