8

Trying to add a background image to canvas using drawImage and it's not showing up. I know the path to the image is correct because I can do <img src="{{ imageName }}" /> and that works. Everything else works fine in JavaScript but doesn't translate well to Angular.

HTML:

<canvas #canvas></canvas>

TypeScript:

import { Component, OnInit } from '@angular/core';
...

@Component({
  selector: 'app-box-picker',
  templateUrl: './box-picker.component.html',
  styleUrls: ['./box-picker.component.css']
})
export class BoxPickerComponent implements OnInit {
  @ViewChild('canvas') public canvas: ElementRef;

  canvasEl: any;
  ctx: CanvasRenderingContext2D;

  @Input() public width = 535.0;
  @Input() public height = 669.25;

  mousePosition: any;
  isMouseDown: boolean;
  dragoffx: number;
  dragoffy: number;

  circles: any;

  imageObj = new Image();
  imageName = "../../assets/pdf.png";

  constructor() {
  }

  ngOnInit() {

  }

  public ngAfterViewInit() {
    this.canvasEl = this.canvas.nativeElement;
    this.ctx = this.canvasEl.getContext('2d');

    this.canvasEl.width = this.width;
    this.canvasEl.height = this.height;

    this.imageObj.src = this.imageName;
    console.log(this.imageName);
    console.log(this.imageObj);
    // init circles
    var c1 = new Circle();
    c1.init(50, 50, 15, "rgba(217,83,79, .5)", "black", this.ctx);
    // console.log(c1);
    c1.out();

    this.circles = [c1];

    this.draw();

    this.captureDownEvents(this.canvasEl);
    this.captureMoveEvents(this.canvasEl);
    this.captureUpEvents(this.canvasEl);
  }

  draw() {
    //clear canvas
    this.ctx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);
    this.ctx.drawImage(this.imageObj, 0, 0, this.canvasEl.width, this.canvasEl.height);
    this.drawCircles();
  }

  drawCircles() {
    for (var i = this.circles.length - 1; i >= 0; i--) {
      this.circles[i].draw();
    }
  }
...
}

When I do a console.log(this.imageObj); sometimes I get <img src="../../assets/pdf.png"> and other times I get only <img>. Does that have anything to do with it?

Tommy J
  • 421
  • 2
  • 5
  • 18
  • 1
    You need to wait that your image has loaded before being able to do anything with it. Here you are calling draw in the same flow you did set your image's src, so when you draw it, it is a 0*0 image. – Kaiido Jul 07 '18 at 00:25
  • Possible duplicate of [CanvasContext2D drawImage() issue \[onload and CORS\]](https://stackoverflow.com/questions/32880641/canvascontext2d-drawimage-issue-onload-and-cors) – Kaiido Jul 07 '18 at 00:25

4 Answers4

7

@Kaiido is correct. I need to wait for the image to load. I'm using setTimeout(e => this.draw(), 500); until I figure out a better solution.

Tommy J
  • 421
  • 2
  • 5
  • 18
  • 1
    You could use do the draw in the `onload` of the image, i.e. `let image = new Image(); image.onload = function() { this.draw() }; image.src = '///';` – Kees de Kooter Jan 22 '19 at 10:07
3

in your javascript (or typescript code, you can someting like this to solve the timeout of the image:

var ctx = element.getContext("2d");
var img = new Image();
img.onload = function() {
    ctx.drawImage(img, 0, 0, img.width, img.height);
    // do other canvas handling here!
}
img.src = "assets/images/image.png";

This working 100% on HTML5, but have not tried to us it withing ts files. Hope this helps!

3

You can also wrap the onload in a Promise and use the async/await pattern for this:

export async function loadImage(src: string): Promise<HTMLImageElement> {
    const image = new Image();
    image.src = src;
    return new Promise(resolve => {
        image.onload = (ev) => {
            resolve(image);
        }
    });
}

Usage:

async drawImage() {
    const image: HTMLImageElement = await loadImage('assets/pdf.png');
    this.ctx = this.canvas.nativeElement.getContext('2d');
    this.ctx.drawImage(image, 0, 0, image.width, image.height);
}
George Chondrompilas
  • 3,167
  • 27
  • 35
2

try by using the following code:

Component HTML

<img #pdf style="display: none;" src="assets/pdf.png" />
<canvas #canvas></canvas>

Component.ts

 @ViewChild('canvas') public canvas: ElementRef;
 //Assets
 @ViewChild('pdf') imageObj: ElementRef;
 canvasEl: any;
 ctx: CanvasRenderingContext2D;
 ...
 draw() {
    ...
    this.ctx = this.canvas.nativeElement.getContext('2d');
    this.ctx.drawImage(imageObj.nativeElement, width, height);     
 }
 ...

Finaly all your code is ok. Just implement the loading image by using Element Ref.

George Chondrompilas
  • 3,167
  • 27
  • 35
Abel Valdez
  • 2,368
  • 1
  • 16
  • 33