Meerdere afbeeldingen tekenen op één canvas

Ik heb een array die alle informatie bevat over hoe de afbeelding moet worden getekend. Ik wil 2 afbeeldingen tekenen en wanneer ik het doe, tekent het alleen de laatste afbeelding. Wat kan ik doen?

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];
}
6

6 antwoord

Ik kon geen specifiekere redenen uitleggen, maar hier is de oplossing die ik heb bedacht. Het werkt voor mij.

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

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; }
</div> </div>

7
toegevoegd

Ik ben niet positief, maar die imageObj is misschien niet de imageObj die je zou verwachten in de imageObj.onload-functie. In plaats van te doen

 context.drawImage(imageObj, sourceX, sourceY,

Kijk wat er gebeurt als je dat doet

 context.drawImage(this, sourceX, sourceY,
4
toegevoegd
dit is waarschijnlijk een goed deel van het antwoord en zal waarschijnlijk een oplossing zijn. declareren van lokale variabelen in een for-lus is het andere probleem dat ik hier zie ..
toegevoegd de auteur Brett Caswell, de bron
dat wil zeggen dat de waarden die worden gebruikt met de methode context.drawImage nog steeds buiten het bereik vallen .. dat wil zeggen dat sourceX sourceY ... waarschijnlijk is zijn tiles [tiles.length -1] equivalent op elke imageObj (of this ) instantie, toch?
toegevoegd de auteur Brett Caswell, de bron

ik had soortgelijke problemen, ik vind de oplossing leuk

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

bel window.requestAnimationFrame (draw); vanuit je draw-functie zal het een oneindige lus uitvoeren en je afbeeldingen tekenen zodra ze klaar zijn

1
toegevoegd

Als u meerdere afbeeldingen laadt, is het raadzaam alle afbeeldingen vooraf te laden. Kijk hier voor meer informatie:

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

1
toegevoegd

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

bind wraps the intended function, and performs a call on it using additional specified parameters (args). The first parameter of bind will be the this instance of the function. Setting it to undefined will pass the original this instance.

anonieme functie.

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

Ik geef de voorkeur aan niet te gebruiken anonieme functies voor algemene eventafhandeling; in plaats daarvan zou ik een object aangeven om handlers op te slaan.

Op die manier kunt u de handler tijdens runtime vervangen. Op een manier zoals het volgende.

declareren object om gebeurtenisafhandelingsfuncties op te slaan

  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

0
toegevoegd
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;
};

stuk van mijn js-spel, ik hoop dat het gejuich helpt!

0
toegevoegd