Saturday, 15 September 2018

Angular 2+ get reference of dynamically-generated HTML elements for canvas manipulation

I have drawing service in Angular with several methods that take various drawing-related parameters and a parameter that references the dynamically-generated Id of a canvas element like the drawLizard method herein:

drawing.service:

import { Injectable } from '@angular/core';
import { Genotype } from './genotype.model';

@Injectable({
  providedIn: 'root'
})
export class DrawingService {
  constructor() {
  }
...
drawLizard(canvasId: string, genotype: Genotype){
  //head
  this.drawTriangle(37.5,87.5,37.5,112.5,25,100, canvasId,"black", true);
  this.drawArc(37.5, 100, 12.5, 3*Math.PI/2, Math.PI/2, canvasId,"black", true);
  // console.log("mark got here, too"); //TODO fix

  //eyes
  this.drawArc(37.5, 106.25, 2, 0, 2*Math.PI, canvasId,"white", true);
  this.drawArc(37.5, 93.75, 2, 0, 2*Math.PI, canvasId,"white", true);
  this.drawArc(37.5, 106.25, 0.5, 0, 2*Math.PI, canvasId,"black", true);
  this.drawArc(37.5, 93.75, 0.5, 0, 2*Math.PI, canvasId,"black", true);

  //body
  this.drawEllipse(100, 100, 50, 10, 0, 0, 2 * Math.PI, canvasId, 'black', true);

  //legs
  this.drawEllipse(140, 110, 30, 3, 0.65, 0, 2 * Math.PI, canvasId, 'black', true);
  this.drawEllipse(140, 90, 30, 3, 0.9+Math.PI/2, 0, 2 * Math.PI, canvasId, 'black', true);
  this.drawEllipse(70, 110, 30, 3, -Math.PI/6, 0, 2 * Math.PI, canvasId, 'black', true);
  this.drawEllipse(70, 90, 30, 3, Math.PI/6, 0, 2 * Math.PI, canvasId, 'black', true);

  this.drawArc(60, 101, 3, 0, 2*Math.PI, canvasId, genotype.getAllele1(), true);
  this.drawArc(85, 102, 3, 0, 2*Math.PI, canvasId, genotype.getAllele2(), true);
  this.drawArc(109, 94, 3, 0, 2*Math.PI, canvasId, genotype.getAllele1(), true);
  this.drawArc(120, 102, 3, 0, 2*Math.PI, canvasId, genotype.getAllele2(), true);
}
...
}

I have several such canvas elements dynamically generated in my lizard-display.component.html:

...
<mat-card small class="example-card" *ngFor="let individual of individuals; let i=index">
...
<canvas id="lizard-canvas" width="200" height="200" style="border:1px solid #c3c3c3;">
    Your browser does not support the canvas element.
</canvas>
...
</mat-card>
...

In my lizard-display.component.ts file, I generate an example lizard and attempt to draw it:

import { OnInit, Component } from '@angular/core';
import { DrawingService } from '../drawing.service';
import { Genotype } from '../genotype.model';
import { Gene } from '../gene.model';
import { Organism } from '../organism.model';
import { ColorNameService } from '../color-name.service';
import { IndividualGenerationService } from '../individual-generation.service';

@Component({
  selector: 'app-lizard-display',
  templateUrl: './lizard-display.component.html',
  styleUrls: ['./lizard-display.component.css'],
  providers: [DrawingService]
})
export class LizardDisplayComponent implements OnInit {
  private individuals: Array<Organism> = new Array<Organism>();

  constructor(private ds: DrawingService, private cns: ColorNameService, private individualGenService: IndividualGenerationService) { }

  ngOnInit() {

      //TODO delete me after fleshed out more
      let testIndividual: Organism = this.individualGenService.makeIndividual("green", "blue");
      let genotype: Genotype = testIndividual.getGeneByName("spot color").getGenotype();
      this.individuals.push(testIndividual);

      this.ds.drawLizard('lizard-canvas0', genotype);
  } 
}

Lots of solutions out there (e.g.,here) seem to work for folks who don't have to then apply .getContext('2d') on their element.

As it is, I can confirm that canvasElement (at least in the drawTriangle method called by drawLizard in the drawing service) using these solutions on SO is null.

I'm hoping for Angular2+-like solutions to this issue.

A functional, reasonably minimal reproducible example can be found here:

git clone https://github.com/Atticus29/population-fragmentation.git
cd population-fragmentation
git checkout dynamicCanvasSO
npm install
ng serve

Navigate to http://localhost:4200/ in a browser



from Angular 2+ get reference of dynamically-generated HTML elements for canvas manipulation

No comments:

Post a Comment