Angular 2+ получает ссылку на динамически сгенерированные элементы HTML для манипулирования холстом - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть служба рисования в Angular с несколькими методами, которые принимают различные параметры, связанные с рисованием, и параметр, который ссылается на динамически генерируемый Id элемента canvas, такой как метод drawLizard:

drawing.service:

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

@Injectable({
  providedIn: 'root'
})
export class DrawingService {
  constructor() {
  }

  drawArc(x: number, y: number, radius: number, startAngle:number, endAngle: number, elementId: string, color: string, fillStatus: boolean) {
    let canvas = <HTMLCanvasElement> document.getElementById(elementId);
    // console.log(canvas); //TODO fix
    if (canvas) {
      let ctx = canvas.getContext('2d');
      ctx.beginPath();
      ctx.arc(x, y, radius, startAngle, endAngle);
      if (fillStatus) {
        ctx.fillStyle = color;
        ctx.fill();
      } else {
        ctx.lineWidth = 1;
        ctx.strokeStyle = color;
        ctx.stroke();
      }
    } else {
      //TODO handle error here
    }
  }

  drawTriangle(x1: number, y1: number, x2: number, y2: number, x3: number, y3:number, elementId: string, color: string, fillStatus: boolean){

    // let canvasElementTest = <HTMLCanvasElement>document.getElementById("first");
    // console.log(canvasElementTest); //TODO fix
    let canvasElement = <HTMLCanvasElement>document.getElementById(elementId);
    // let canvasElement: Element = <HTMLCanvasElement>document.getElementsByClassName(elementId);
    console.log(canvasElement); //TODO fix
    if (canvasElement){
      let context = canvasElement.getContext("2d");
      context.beginPath();
      context.moveTo(x1, y1);
      context.lineTo(x2, y2);
      context.lineTo(x3, y3);
      context.closePath();
      context.lineWidth = 1;
      context.strokeStyle = color;
      context.stroke();
      if(fillStatus){
        context.fillStyle = color;
        context.fill();
    }
  } else{
    //TODO throw/handle error here
  }
}

drawEllipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle:number, endAngle:number, elementId: string, color: string, fillStatus: boolean){
  let canvas = <HTMLCanvasElement> document.getElementById(elementId);
  if(canvas){
    let ctx = canvas.getContext('2d');
    // ctx.setLineDash([])
    ctx.beginPath();
    ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, false); //x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise
    ctx.stroke();
    if(fillStatus){
      ctx.fillStyle = color;
      ctx.fill();
    }
    ctx.closePath();
  } else{
    //TODO handle error here
  }

}

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);

  //random polka dots
  // let colorArray = new Array<string>("blue", "pink", "orange", "#FF00FF", "red", "#00FFFF", "#800000", "#00FF00", "#008000", "#00FFFF", "#008080", "#BFBFFE", "#800080");
  // this.drawArc(77, 95, 3, 0, 2*Math.PI, canvasId, colorArray[Math.floor(Math.random()*colorArray.length)], 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);
}
}

У меня есть несколько таких элементов canvas, которые динамически генерируются в моем lizard-display.component.html:

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

В моем файле lizard-display.component.ts я создаю примерЯщерица и попытка нарисовать его:

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);
  } 
}

Множество решений (например, здесь ), кажется, работают для людей, которые не должны затем применять .getContext('2d') к своимelement.

Как таковой, я могу подтвердить, что canvasElement (по крайней мере, в методе drawTriangle, вызываемом drawLizard в сервисе рисования), использующем эти решения в SO, равен нулю.

Я надеюсь на Angular2 + -подобные решения этой проблемы.

Функциональный, разумно минимальный воспроизводимый пример можно найти здесь:

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

Перейдите к http://localhost:4200/ вбраузер

1 Ответ

0 голосов
/ 14 сентября 2018

угловой способ получить ссылки на элементы html с помощью ViewChildren, например, так:

export class LizardDisplayComponent implements OnInit, AfterViewInit {
  @ViewChildren('canvases') canvases: QueryList<ElementRef>;
  private individuals: Array<Organism> = new Array<Organism>();

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

  ngOnInit() { } 

  ngAfterViewInit() { // view children arent available till this hook
     this.canvases.forEach(canvas => console.log(canvas)); 
     //here you'll see each has a nativeElement property that is a reference to that element, you can theoretically pass that to your service to be drawn on, this is just looping over everything with the '#canvases' tag applied to it

     let testIndividual: Organism = this.individualGenService.makeIndividual("green", "blue");
     let genotype: Genotype = testIndividual.getGeneByName("spot color").getGenotype();
     this.individuals.push(testIndividual);

     //you can pass them to your service like this instead of the id
     this.ds.drawLizard(this.canvases.toArray()[0], genotype);
  }
}

декоратор viewchildren в основном запрашивает у компонента любые элементы, у которых есть тег, указанный вами в декораторе, который вы применяете.тег в HTML, например:

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

, тогда вы можете передать его на службу:

drawLizard(canvasRef: ElementRef, genotype: Genotype){
  this.drawTriangle(37.5,87.5,37.5,112.5,25,100, canvasRef,"black", true);
  ...
}

drawTriangle(x1: number, y1: number, x2: number, y2: number, x3: number, y3:number, elementRef: ElementRef, color: string, fillStatus: boolean){
  let canvasElement = <HTMLCanvasElement>elementRef.nativeElement;
  ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...