test
test

Reputation: 18198

JavaScript - Uncaught TypeError: Type error

I am trying to break a spritesheet and well, it's not putting it into a 2D array like it should. At the end of my code, near the console.log, it spits out ImageData...but when it tries to putImageData... I get Uncaught TypeError: Type error

Help?

and here's my code:

$(document).ready(function () {
    console.log("Client setup...");
    canvas = document.getElementById("canvas");
    context = canvas.getContext("2d");
    canvas.tabIndex = 0;
    canvas.focus();
    console.log("Client focused.");

    var imageObj = new Image();
    imageObj.src = "./images/all_tiles.png";
    imageObj.onload = function() {
    context.drawImage(imageObj, imageWidth, imageHeight);
    };

    var allLoaded = 0;
    var tilesX = ImageWidth / tileWidth;
    var tilesY = ImageHeight / tileHeight;
    var totalTiles = tilesX * tilesY;        
    var tileData = [totalTiles]; // Array with reserved size
    for(var i=0; i<tilesY; i++)
    {
      for(var j=0; j<tilesX; j++)
      {           
        // Store the image data of each tile in the array.
        tileData.push(context.getImageData(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
        allLoaded++;
      }
    }

    if (allLoaded == totalTiles) {
    console.log("All done: " + allLoaded);
    console.log(tileData[1]);
    context.putImageData(tileData[0], 0 ,0); // Sample paint
    }


});

error happens at context.putImageData(tileData[0], 0 ,0); // Sample paint

Here is example fiddle of code above http://jsfiddle.net/47XUA/

Upvotes: 2

Views: 12188

Answers (5)

Lorenzo De Tomasi
Lorenzo De Tomasi

Reputation: 89

I'm using Chrome.

context.drawImage(spritesheet.image, 0, 0, 4608, 768);// Works
context.drawImage(spritesheet.image, 768, 0, 768, 768, 4608, 768); // Doesn't work: Uncaught TypeError: Type error

Thank you!

Upvotes: 0

apsillers
apsillers

Reputation: 116030

Your problem is that the first element of tileData is not an ImageData object, it's a plain number! When you initialized your array you used:

var tileData = [totalTiles];

This means that tileData[0] is equal to the value of totalTiles, which is the number 483. You are providing a number instead of an ImageData object to putImageData, and the browser is throwing an error in confusion. If you look at any other element in the rest of your array, you'll see it is successfully being populated with ImageData objects as you expect; only the first element in the array is a number.

You probably meant to do:

var tileData = new Array(totalTiles);

which would create an array with the specified length property, instead of setting the first value in the array to a number. Personally, I would run some performance tests to see if that is even useful; you may be just as well using var tileData = [];

Upvotes: 4

Dave Tameside
Dave Tameside

Reputation: 31

A type error is caused when a variable or object passed into a statement is not of a type that is expected for that command and can’t be converted into something that is valid.

See here for a full definition of the error.

So most likely that context or tileData is in an incorrect format or is null or undefined

Upvotes: 3

Aesthete
Aesthete

Reputation: 18858

The problem here is that the imageObj.onload() function is being called AFTER the rest of the script is executed.

This means that queries to getImageData() are returning undefined, as there is no image data in the canvas when called.

A simple way to fix this is to encapuslate the remaining script in the imageObj.onload function, like so:

$(document).ready(function () {
console.log("Client setup...");
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.tabIndex = 0;
canvas.focus();
console.log("Client focused.");

var imageObj = new Image();
imageObj.src = "./images/all_tiles.png";

imageObj.onload = function() {

  context.drawImage(imageObj, 0, 0);

  var allLoaded = 0;
  var tilesX = imageWidth / tileWidth;
  var tilesY = imageHeight / tileHeight;
  var totalTiles = tilesX * tilesY;        
  var tileData = new Array(); // Array with NO reserved size
  for(var i=0; i<tilesY; i++)
  {
    for(var j=0; j<tilesX; j++)
    {           
      // Store the image data of each tile in the array.
      tileData.push(context.getImageData(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
      allLoaded++;
    }
  }

  context.putImageData(tileData[0], 0 ,0); // Sample paint
}; // End 'imageObj.onload()' scope.

}); // End document ready function scope.

This ensures that any calls to getImageData() are made after context.drawImage()

You may also have a problem here that you are not drawing the image to cover the canvas. Change the line:

context.drawImage(imageObj, imageWidth, imageHeight);

to

context.drawImage(imageObj, 0, 0);

EDIT: You also had ImageWidth and imageWidth (same for height). Rename these.

EDIT: Reserving the Array size here with new Array(totalTiles) was causing an issue. When we pushed new tile images to the array, it pushed to the end of the pre-allocated array (starting at tileData[totalTiles]). This is easily fixed by removing the size argument. Otherwise instead of using push() we could copy the image data into the array in a loop, eg: tileData[n] = getImageData(...), starting at tileData[0].

Upvotes: 0

devnull69
devnull69

Reputation: 16584

It might be a racing condition. You are using drawImage only when the image ./images/all_tiles.png has been loaded. But you are using the image data on the context before the onload fired. Try to move everything which is after the onload handler into the onload handler.

Upvotes: 0

Related Questions