为什么我的图像不会出现在 canvas 上?

Why won't my images appear on the canvas?

我想使用原型绘制许多不同大小的圆圈,上面有相同的图像。问题是,圆圈上没有绘制图像。

圆圈仍然存在,因为在使用描边时它们是可见的,但没有绘制图像。我可以在没有原型的情况下绘制一个带有图像的圆弧,但是一旦我使用它,它就不起作用了。

控制台中没有出现错误,所以我不清楚我遗漏了什么。 我试过将事件侦听器移到原型之外,但圆圈图像仍然没有出现。

如果有人对为什么这不起作用有任何见解或者解决方案可以分享,我们将不胜感激。

代码如下:

const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
  constructor(xPos, yPos, radius){
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
  }
}
Balls.prototype.render  = function(){
  const img = document.createElement('img');
  img.src = 'crystal.jpg';
  ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI*2)
  ctx.stroke(); 
  ctx.clip();
  img.addEventListener('onload', function(e){
    ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius, 
    this.radius*2, this.radius*2);
  });
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>

您的代码中有两个问题。首先,onload 事件应该是 load。其次,this在事件监听函数内部是未知的,所以this.radius等都是未定义的,ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius, this.radius*2, this.radius*2)不起作用。

我为 this.xPosthis.yPosthis.radius 使用了一些可以在事件侦听器回调函数中使用的变量。 希望这对您有所帮助!

const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
  constructor(xPos, yPos, radius) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
  }
}
Balls.prototype.render = function() {
  const img = new Image();
  img.src = 'https://source.unsplash.com/random';
  var xPos = this.xPos, yPos = this.yPos, radius = this.radius
  ctx.arc(xPos, yPos, radius, 0, Math.PI * 2)
  ctx.stroke();
  ctx.clip();
  img.addEventListener('load', function(e) {
    console.log("load")
    ctx.drawImage(img, xPos - radius, yPos - radius, 
    radius*2, radius*2);
  });
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>

给你,我只是在这里更改了 2 处以使你的代码工作。

  1. load 用于事件侦听器而不是 onload
  2. 使用箭头函数以依赖父上下文而不是动态上下文(this)。

const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
  constructor(xPos, yPos, radius) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
  }
}
Balls.prototype.render = function() {
  const img = document.createElement('img');
  img.src = 'https://via.placeholder.com/150.png?text=vijay'
  ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2)
  ctx.stroke();
  ctx.clip();
  img.addEventListener('load', (e) => {
    ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius,
      this.radius * 2, this.radius * 2);
  });
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>

这是加载图像的另一种方式,它更加模块化,如果您正在制作游戏,Img class 会派上用场。

Off-topic - if you want to load multiple images then you can add a总加载counter to keep track of how many images has been loaded and if the总加载count is equal to总图像count then you can call a callback which will fire the animationLoop and preloads all the images.

const ctx = document.getElementById('canvas').getContext('2d');

// Img class to provide modular code
class Img {
  constructor(src, x, y, size) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.src = src;
    this.img = new Image();
    this.img.src = this.src;
    this.isLoaded = false;
    this.img.addEventListener('load', (e) => {
      this.isLoaded = true;
      this.draw();
    });
  }

  draw() {
    if (this.isLoaded) {
      ctx.drawImage(this.img, this.x, this.y, this.size, this.size);
    }
  }
}

class Balls {
  constructor(xPos, yPos, radius) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
  }
}
Balls.prototype.render = function() {
  let imgx = this.xPos - this.radius;
  let imgy = this.yPos - this.radius;
  let imgr = this.radius * 2;
  let url = 'https://via.placeholder.com/150.png?text=Better';
  const img = new Img(url, imgx, imgy, imgr);
  ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2)
  ctx.stroke();
  ctx.clip();
  img.draw();
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>