Javascript 在一张画布上绘制多个图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8404937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:53:05  来源:igfitidea点击:

Drawing multiple images on one canvas

javascriptimagehtml

提问by user1068455

I have an array that contains all the information about how the imageshould be drawn. I want to draw 2 imagesand when I do it, it's only drawing the last image. What can I do?

我有一个数组,其中包含有关如何image绘制 的所有信息。我想绘制 2 images,当我这样做时,它只绘制最后一个图像。我能做什么?

for(i = 0; i < tiles.length; i++)
{
    var sourceX = tiles[i][5];
    var sourceY = tiles[i][6];
    var sourceWidth = tiles[i][9];
    var sourceHeight = tiles[i][10];
    var destWidth = sourceWidth;
    var destHeight = sourceHeight;
    var destX = tiles[i][7];
    var destY = tiles[i][8];

    var imageObj = new Image();
    imageObj.onload = function()
    {
        context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
    };
    imageObj.src = tiles[i][4];
}

回答by Ryan Huang

I couldn't explain more specific reasons, but here is the solution I figured out. It works for me.

我无法解释更具体的原因,但这是我想出的解决方案。这个对我有用。

const getContext = () => document.getElementById('my-canvas').getContext('2d');

// It's better to use async image loading.
const loadImage = url => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error(`load ${url} fail`));
    img.src = url;
  });
};

// Here, I created a function to draw image.
const depict = options => {
  const ctx = getContext();
  // And this is the key to this solution
  // Always remember to make a copy of original object, then it just works :)
  const myOptions = Object.assign({}, options);
  return loadImage(myOptions.uri).then(img => {
    ctx.drawImage(img, myOptions.x, myOptions.y, myOptions.sw, myOptions.sh);
  });
};

const imgs = [
  { uri: 'http://placehold.it/50x50/f00/000?text=R', x: 15, y:  15, sw: 50, sh: 50 },
  { uri: 'http://placehold.it/50x50/ff0/000?text=Y', x: 15, y:  80, sw: 50, sh: 50 },
  { uri: 'http://placehold.it/50x50/0f0/000?text=G', x: 15, y: 145, sw: 50, sh: 50 }
];

imgs.forEach(depict);
#my-canvas { background: #7F7F7F; }
<canvas id="my-canvas" width="80" height="210"></canvas>

回答by Jeffrey Sweeney

I'm not positive, but that imageObj may not be the imageObj you'd expect in the imageObj.onload function. Instead of doing

我并不肯定,但 imageObj 可能不是您在 imageObj.onload 函数中期望的 imageObj。而不是做

 context.drawImage(imageObj, sourceX, sourceY,

See what happens when you do

看看当你这样做时会发生什么

 context.drawImage(this, sourceX, sourceY,

回答by Garrett Vlieger

If you're loading multiple images, it's recommended that you pre-load all of the images first. See here for more information:

如果您要加载多个图像,建议您先预加载所有图像。浏览此处获取更多信息:

http://www.html5canvastutorials.com/tutorials/html5-canvas-image-loader/

http://www.html5canvastutorials.com/tutorials/html5-canvas-image-loader/

回答by wutzebaer

i had similar problems, i like the solution from

我有类似的问题,我喜欢的解决方案

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations

just call window.requestAnimationFrame(draw); from your draw function, it will run an infinit loop and draw your images as soon as they are ready

只需调用 window.requestAnimationFrame(draw); 从您的绘图功能中,它将运行一个无限循环并在您准备好后立即绘制您的图像

回答by Brett Caswell

here's a solution, and a recommended alternative; both use <function>.bind(<this>[,<arg1>][,<arg2>])

这是一个解决方案,以及一个推荐的替代方案;两者都使用<function>.bind(<this>[,<arg1>][,<arg2>])

bindwraps the intended function, and performs a call on it using additional specified parameters (args). The first parameter of bindwill be the thisinstance of the function. Setting it to undefinedwill pass the original thisinstance.

bind包装预期的函数,并使用附加的指定参数 (args) 对其执行调用。第一个参数bindwill 是this函数的实例。将其设置为undefined将传递原始this实例。

anonymous function.

匿名函数。

  var settings;

  for(i = 0; i < tiles.length; i++)
  {
      settings = {};
      settings.sourceX = tiles[i][5];
      settings.sourceY = tiles[i][6];
      settings.sourceWidth = tiles[i][9];
      settings.sourceHeight = tiles[i][10];
      settings.destWidth = sourceWidth;
      settings.destHeight = sourceHeight;
      settings.destX = tiles[i][7];
      settings.destY = tiles[i][8];

      settings.imageObj = new Image();
      settings.imageObj.onload = function(args)
      {
         context.drawImage(args.image, args.sourceX, args.sourceY, args.sourceWidth, args.sourceHeight, args.destX, args.destY, args.destWidth, args.destHeight);
      }.bind(undefined, settings);
      settings.imageObj.src = tiles[i][4];
  }


I prefer not to useanonymous functionsfor common event handling though; instead, I would declare an object to store handlers.

不过,我喜欢匿名函数用于常见的事件处理;相反,我会声明一个对象来存储处理程序。

That way you can replace the handler at runtime. In a manner like the following.

这样你就可以在运行时替换处理程序。以如下方式。

declare object to store event handling functions

声明对象来存储事件处理函数

  var Handlers = { 
      "drawImageHandler" : function drawImageHandler(args)
      {
          context.drawImage(args.image, args.sourceX, args.sourceY, args.sourceWidth, args.sourceHeight, args.destX, args.destY, args.destWidth, args.destHeight);
      }
  };

  function DebugInit() 
  {
      var func = Handlers.drawImageHandler;
      Handlers.drawImageHandler = function(func, args) {
         console.log("%o", args);
         func(args);
      }.bind(undefined, func);
  }


  var settings = {};
  DebugInit(); // when called, encapsulates Handlers.drawImageHandler;

  for(i = 0; i < tiles.length; i++)
  {
      settings = {};
      settings.sourceX = tiles[i][5];
      settings.sourceY = tiles[i][6];
      settings.sourceWidth = tiles[i][9];
      settings.sourceHeight = tiles[i][10];
      settings.destWidth = sourceWidth;
      settings.destHeight = sourceHeight;
      settings.destX = tiles[i][7];
      settings.destY = tiles[i][8];
      settings.imageObj = new Image();
      settings.imageObj.onload = Handlers.drawImageHandler.bind(undefined, settings);      
      settings.imageObj.src = tiles[i][4];
  }

jsFiddle: Example Fiddle

jsFiddle示例小提琴

回答by Rob

img[0]=new Image();
img[0].src="imgimg/img"+i+".png";
img[0].onload=function(){
  cntxt.drawImage(this,400,i*100,100,100);
  i++;
  img[i]=new Image(); 
  img[i].src="invimg/img"+i+".png";
  img[i].onload=this.onload;
};

piece of my js game, i hope it helps cheers!

我的js游戏的一部分,我希望它有助于欢呼!