JQuery canvas drawImage() not working - javascript

I've tried everything I can think of and I'm reaching my wit's end.
"tilesheet.png" should be drawn onto the canvas but nothing I try seems to work.
Occasionally, when I try some new method I found online, it will appear to work fine once, but if I refresh the page it stops again.
Here is the code I'm using:
<head>
<title>Test Code</title>
<script src='scripts/jquery.js'></script>
</head>
<body>
<img id='img' src='images/tilesheet.png' style='position:absolute; visibility:hidden;'/>
<div id="port"></div>
<script>
viewHeight = 10;
viewWidth = 10;
$("#port").append("<canvas id='mapview' width='"+(viewWidth*32)+"' height='"+(viewHeight*32)+"' style='border:1px solid black;'>Your browser doesn't support the canvas element.</canvas>");
var worldMap = new gameMap(viewHeight,viewWidth);
worldMap.redraw();
// These functions define a gameMap "CLASS" //
function gameMap (height,width){
this.tileSheet = $("#img");
this.canvas = $("#mapview");
this.ctx = this.canvas.getContext("2d");//<-- Error is referring to this line
}
//Draw Function
gameMap.prototype.redraw = function(){
this.tileSheet.onload = function(){
this.ctx.drawImage(this.tileSheet,10,10);
}
this.tileSheet.src = "apps/gamejournal/images/tilesheet.png";
for(i = this.viewY; i < this.viewY+this.viewHeight; i++){
for(j = this.viewX; j < this.viewX+this.viewWidth; j++){
}
}
this.mapcss();
};
//CSS
gameMap.prototype.mapcss = function(){
var h = this.viewHeight*this.tileSize;
var w = this.viewHeight*this.tileSize;
$('#port').css({
"height":h,
"width":w,
"position":"relative",
"margin":"0 auto"
});
};
</script>
</body>
Update 10/30/15 - After using Google Chrome's "Inspect Element" feature, I've noticed that an error is being reported:
TypeError: this.canvas.getContext is not a function (test.php:26)
Does anyone know what might be causing this?
Update 11/4/15 - I've created a JSFiddle so you can see what my code is doing.
https://jsfiddle.net/6ss8ygLd/3/
Any help would be greatly appreciated. Thanks!

Okay, after a lot of extra research I seem to have found the solution to my own problem.
The problems proved to be a mix of using jquery in places where it wouldn't work, and putting my "onload" function in the wrong place.
Here is the final code I used:
<head>
<title>Test Code</title>
<script src='scripts/jquery.js'></script>
</head>
<body>
<img id="tiles" src="images/tilesheet.png" style="position:absolute; left:-9999px;"/>
<div id="port"></div>
<script>
viewHeight = 10;
viewWidth = 10;
var mapw = viewWidth*32;
var maph = viewHeight*32;
$("#port").append("<canvas id='mapview' width='"+mapw+"' height='"+maph+"' style='border:1px solid black;'>Your browser doesn't support the canvas element.</canvas>");
// These functions define a gameMap "CLASS" //
function gameMap (height,width){
this.canvas = document.getElementById("mapview");
this.ctx = this.canvas.getContext("2d");
this.tileSheet = document.getElementById("tiles");
}
//Draw Function
gameMap.prototype.redraw = function(){
this.ctx.drawImage(this.tileSheet,0,0);
};
//Call Functions
document.getElementById("tiles").onload = function(){
var worldMap = new gameMap(viewHeight,viewWidth);
worldMap.redraw();
}
</script>
</body>

Related

Issues with Prototype Interactive Space Map [duplicate]

This is my easel js function, it draws a red circle and an image, however the circle is showing but the image isn't.
function Start() {
var stage = new createjs.Stage("DogeCanvas");
var dog = new createjs.Bitmap("doge.jpg");
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100;
circle.y = 100;
dog.x=100;
dog.y=100;
stage.addChild(circle, dog);
stage.update();
}
And this is the html file
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="Doge.js"></script>
</head>
<body bgcolor="#C7C7C7" onload="Start();">
<canvas id="DogeCanvas" width="480" height="320"></canvas>
</body>
</html>
Why? help please, seems like in everyones else code this works but why this isn't working for me?
The image is likely not loaded yet.
You can add a Ticker to the stage to constantly update it (which most applications do, since there is other things changing over time)
Example:
createjs.Ticker.on("tick", stage);
// OR
createjs.Ticker.addEventListener("tick", stage);
// OR
createjs.Ticker.on("tick", tick);
function tick(event) {
// Other stuff
stage.update(event);
}
Listen for the onload of the image, and update the stage again
Example:
var bmp = new createjs.Bitmap("path/to/image.jpg");
bmp.image.onload = function() {
stage.update();
}
Preload the image with something like PreloadJS before you draw it to the stage. This is a better solution for a larger app with more assets.
Example:
var queue = new createjs.LoadQueue();
queue.on("complete", function(event) {
var image = queue.getResult("image");
var bmp = new createjs.Bitmap(image);
// Do stuff with bitmap
});
queue.loadFile({src:"path/to/img.jpg", id:"image"});

Javascript function from a JS file doesn't get called from the canvas

I'm trying to learn about JavaScript and the html5 canvas, however, it's proving a little confusing and I don't understand why it doesn't seem to work...
I am working on creating a simple map that has some of the capabilities of google maps(drag and drop/zoom in/out/etc). In order to do this, I chose html5 canvas and easeljs for the drag and drop functions.
I have a javascript file (path.js) which contains 2 functions:
pathConstructor() - example function from the easeljs tutorial
drawMap() - copy of the first function slightly modified (and probably wrong right now)
Everything worked fine when I called pathConstructor() from the canvas, however, after I replaced it with drawMap(), everything stopped working. It won't even work if I replace drawMap() with pathContrcutor() right now.
I put some alerts before and after calling the function from the canvas and inside pathConstructor(). The before alert goes off but the others don't so for some reason the function never gets called...
If I use the pathConstructor code as inline code in the canvas then it works just fine, however, I would like to avoid that since I believe it's bad programming. I want it to be neat and each script to have its own file.
Anyone know why this is happening?
HTML
<!Doctype html>
<html>
<head>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="path.js" type="text/javascript"></script>
</head>
<body>
<canvas id="canvas" width="1300px" height="800px"style="border:1px dotted black;">
<script>pathConstructor();</script>
</canvas>
</body>
</html>
Javascript
var stage;
function pathConstructor() {
alert('inside pathConstructor');
stage = new createjs.Stage('canvas');
// this lets our drag continue to track the mouse even when it leaves the canvas:
// play with commenting this out to see the difference.
stage.mouseMoveOutside = true;
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
var label = new createjs.Text("drag me", "bold 14px Arial", "#FFFFFF");
label.textAlign = "center";
label.y = -7;
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
stage.addChild(dragger);
dragger.on("pressmove", function(evt) {
// currentTarget will be the container that the event listener was added to:
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
// make sure to redraw the stage to show the change:
stage.update();
});
stage.update();
}
function drawMap() {
stage = new createjs.Stage('canvas');
var bitMap = new createjs.Bitmap('middle-earth-map.jpg');
stage.mouseMoveOutside = true;
var dragger = new createjs.Container();
dragger.x = dragger.y = 0;
dragger.addChild(bitMap);
stage.addChild(dragger);
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});
stage.update();
}
For me it's working fine, you just have to remove that extra ")" in dragger.on('pressmove', function(evt2)) {;
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});

How to wait until onload event completes its work in JavaScript?

I'm developing a printing tool using HTML5 canvas. As a test, I've tried to draw an image and a rectangle on the canvas, and then copy it to a new window for printing, using the code below. But all I'm getting in the new window is a blank page.
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<canvas id="pageCanvas"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("pageCanvas");
canvas.height="700";
canvas.width="1000";
var ctx = canvas.getContext("2d");
var imageData="data:image/png;base64,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";
var imageObj = new Image();
imageObj.src = imageData;
imageObj.addEventListener("load", function() {
ctx.drawImage(imageObj, 50, 100,1000,600);
ctx.beginPath();
ctx.rect(100, 101, 200, 100);
ctx.lineWidth = 7;
ctx.strokeStyle = 'black';
ctx.stroke();
}, false);
var printWindow = window.open('');
printWindow.document.write('<html><BODY>');
printWindow.document.write('<center>');
printWindow.document.write('<img src="' + canvas.toDataURL()+'"/>');
printWindow.document.write('</center></body></html>');
printWindow.document.close();
printWindow.print();
</script>
</body>
</html>
Can you please guide me to overcome this issue?
You're opening the new window and trying to copy the content of the canvas onto it immediately after attaching the load event handler to the image, before the handler has actually had a chance to execute.
Just move all the JS code starting with the var printWindow = window.open(''); line inside the event handler, and it should work.
Oh, and please indent your code, especially if you expect anyone else to read it.
Addendum: If you want to wait until multiple images have loaded, the simplest way is to count the load events and call a function when all of them have fired, like this:
var imageURLs = [ ... image URLs here ... ];
var imageObjs = [];
var imagesLoaded = 0;
for (var i = 0; i < imageURLs.length; i++) {
var image = new Image();
image.addEventListener( "load", function() {
imagesLoaded++;
if (imagesLoaded == imageURLs.length) allImagesLoaded();
} );
image.src = imageURLs[i];
imageObjs.push(image);
}
function allImagesLoaded() {
// now do something with imageObjs
};
You could also get fancy and play with things like ES6 promises, but ultimately, the end result is the same.
See also:
Can I sync up multiple image onload calls?
Javascript - wait images to be loaded

Using the Canvas for web animation results in nothing happening?

I'm learning javascript, so a coworker is having me do basic animation in the browser. I just finished my code, using the canvas element to display images to the screen, but nothing happens when I run the code. My debug statements don't get printed to the console, nor do any errors. Can anyone see a problem with my code?
<html>
<body>
<canvas id="console" width="600" height="600"></canvas>
<script type="text/javascript">
(function() {
console.log("at top of script");
var ballImage = new Image();
ballImage.src = "http://upload.wikimedia.org/wikipedia/en/e/ec/Soccer_ball.svg";
var time_stamp;
var balls[];
var BALL_COUNT = 2;
function requestAnimFrame (cb) {
function fallback (cb){
window.setTimeout(cb, 10);
}
var func = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
fallback;
func (cb);
}
function update() {
var ts = Date.now();
var time_elapsed = ts - (time_stamp || ts);
time_stamp = ts;
canvas = document.getElementById("canvas");
// update ball positions and detect wall collisions
balls.forEach(function (ball){
canvas.clearRect( ball.xLocation, ball.yLocation, ball.scaleWidth, ball.scaleHeight );
ball.update(time_elapsed);
canvas.drawImage( ball.image, ball.xLocation, ball.yLocation, ball.scaleWidth, ball.scaleHeight );
});
}
function programRun() {
update();
requestAnimationFrame(programRun);
}
/*
CLASS: ball
*/
function Ball() {
// all the code and functions for the ball class....
}
ballImage.onload = function() {
// fill up the array containing the ball objects
for (var i = 0; i < BALL_COUNT; ++i){
balls.push (new Ball ("ball" + i));
}
// start running the program
programRun();
};
console.log("got to end of script");
}) ();
<script>
</body>
</html>
I'm almost certain it's some basic thing I messed up, because I didn't get any errors back from running the code. Any help is appreciated :)
This line caused it..
var balls[];
correct it by replacing it with:
var balls = [];
you should see the logs then.
Update:
I created a fiddle with the code above and revised some fragments of your code to conform to a version that may suit your needs in writing your own version of the ball animation.
The following are the problems that I saw in your code:
Of course the array declaration mentioned above var balls[]; to var balls = [];
Don't forget to declare variables with the var keyword. I changed
time_stamp = ts;
canvas = document.getElementById("canvas");
to
var time_stamp = ts;
var canvas = document.getElementById("canvas");
3. Your html code suggests that the ID of the canvas is id="console" but your javascript tries to get an element with id="canvas".
Changed
<canvas id="console" width="600" height="600"></canvas>
to
<canvas id="canvas" width="600" height="600"></canvas>
Inside your ball.each() iteration uses the canvas element to invoke methods that are supposed to be within the CanvasRenderingContext2D.
Add something after your var canvas declaration.
var ctx = canvas.getContext('2d');
use the ctx variable to manipulate the canvas itself. This should be your function update() definition.
function update() {
var ts = Date.now();
var time_elapsed = ts - (time_stamp || ts);
var time_stamp = ts;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
// update ball positions and detect wall collisions
balls.forEach(function (ball){
ctx.clearRect( ball.xLocation, ball.yLocation, ball.scaleWidth, ball.scaleHeight );
ball.update();
ctx.drawImage( ballImage, ball.xLocation, ball.yLocation, ball.scaleWidth, ball.scaleHeight );
});
}
UPDATE:
Always use var when declaring variables. If you want to use them as a variable that can be accessed from different scopes(inner scopes) then you can do it by declaring them a scope higher.
Something like this:
function BallAnimation() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function updateBall() {
ctx.fillRect(.....);
...
}
function Ball() {
this.canvas = canvas;
}
}
In such a manner you can still obtain the reference of the variables that you want to share from other scopes. Read this article to know more why vars are important.

Cannot read property 'getContext' of null, using canvas

I get the error Uncaught TypeError: Cannot read property 'getContext' of null and the important parts in files are... I am wondering since game.js is in a directory below, it cannot find canvas? What should I do?
./index.html:
<canvas id="canvas" width="640" height="480"></canvas>
./javascript/game.js:
var Grid = function(width, height) {
...
this.draw = function() {
var canvas = document.getElementById("canvas");
if(canvas.getContext) {
var context = canvas.getContext("2d");
for(var i = 0; i < width; i++) {
for(var j = 0; j < height; j++) {
if(isLive(i, j)) {
context.fillStyle = "lightblue";
}
else {
context.fillStyle = "yellowgreen";
}
context.fillRect(i*15, j*15, 14, 14);
}
}
}
}
}
I guess the problem is your js runs before the html is loaded.
If you are using jquery, you can use the document ready function to wrap your code:
$(function() {
var Grid = function(width, height) {
// codes...
}
});
Or simply put your js after the <canvas>.
Put your JavaScript code after your tag <canvas></canvas>
You don't have to include JQuery.
In the index.html:
<canvas id="canvas" width="640" height="480"></canvas><script src="javascript/game.js">
This should work without JQuery...
Edit: You should put the script tag IN the body tag...
You should put javascript tag in your html file.
because browser load your webpage according to html flow, you should put your javascript file<script src="javascript/game.js"> after the <canvas>element tag. otherwise,if you put your javascript in the header of html.Browser load script first but it doesn't find the canvas. So your canvas doesn't work.
Write code in this manner ...
<canvas id="canvas" width="640" height="480"></canvas>
<script>
var Grid = function(width, height) {
...
this.draw = function() {
var canvas = document.getElementById("canvas");
if(canvas.getContext) {
var context = canvas.getContext("2d");
for(var i = 0; i < width; i++) {
for(var j = 0; j < height; j++) {
if(isLive(i, j)) {
context.fillStyle = "lightblue";
}
else {
context.fillStyle = "yellowgreen";
}
context.fillRect(i*15, j*15, 14, 14);
}
}
}
}
}
First write canvas tag and then write script tag. And write script tag in body.
You just need to put<script src='./javascript/game.js'></script> after your <canvas>.
Because the browser don't find your javascript file before the canvas
I assume you have your JS file declared inside the <head> tag so it keeps it consistent, like standard, then in your JS make sure the canvas initialization is after the page is loaded:
window.onload = function () {
var myCanvas = document.getElementById('canvas');
var ctx = myCanvas.getContext('2d');
}
There is no need to use jQuery just to initialize a canvas, it's very evident most of the programmers all around the world use it unnecessarily and the accepted answer is a probe of that.
This might seem like overkill, but if in another case you were trying to load a canvas from js (like I am doing), you could use a setInterval function and an if statement to constantly check if the canvas has loaded.
//set up the interval
var thisInterval = setInterval(function{
//this if statment checks if the id "thisCanvas" is linked to something
if(document.getElementById("thisCanvas") != null){
//do what you want
//clearInterval() will remove the interval if you have given your interval a name.
clearInterval(thisInterval)
}
//the 500 means that you will loop through this every 500 milliseconds (1/2 a second)
},500)
(In this example the canvas I am trying to load has an id of "thisCanvas")

Categories