I'm coding basic balloon game. Balloons are created dynamically into the canvas. Everything is ok but I could not add onclick event to hide the balloon. First function to start game is "Baslat()". Here is my codes
var canvas;
var sev = 1;
var zorluk = 3;
var ctx;
function Baslat() {
var x;
for (x = 1; x <= sev*zorluk; x++) {
BalonYap(x);
}
}
function seviye(a) {
sev = a.value;
}
function BalonYap(id) {
var img = new Image();
img.src = "balon.png";
img.id = "balon_"+id;
img.onload = BalonLoad(img); // works
img.onclick = Patlat(id); // doesn't work
}
function BalonLoad(img) {
var rnd1 = Math.floor(Math.random() * 750)+10;
var rnd2 = Math.floor(Math.random() *350)+10;
canvas = document.getElementById('myCanvas');
context = canvas.getContext("2d");
context.drawImage(img, rnd1, rnd2);
}
function Patlat(img) {
alert();
}
You need to assign function to event handlers. If you give arguments to a function it's called. You can try this factory method (you can give arbitrary parameters to the wrapping function and use them inside the returned function's closure):
function BalonLoad(img) {
return function() {
var rnd1 = Math.floor(Math.random() * 750)+10;
var rnd2 = Math.floor(Math.random() *350)+10;
canvas = document.getElementById('myCanvas');
context = canvas.getContext("2d");
context.drawImage(img, rnd1, rnd2);
}
}
Part of the issue here is that you are attempting to assign an event callback on an element that does not exist in the DOM. You are only drawing to the canvas. A click event will need to be applied to the canvas element. You will need to save the coordinates of each balloon, and use that to find the appropriate balloon when the canvas is clicked.
Related
I'm currently learning JavaScript at my university, so I apologize if my code is terrible. I'm new to it.
I'm having an issue only changing one image onclick using appendChild. What I want to happen is that if the person clicks on the image whose rng is <= 0.89, then only that image is changed to a different image. Every thing I've tried has changed all of the images whose rng was <=0.89.
Example: I click the first image (img1) which has rolled a number greater than 0.9. If (img2) has rolled the same (greater than 0.9), then it also changes. I'd only want img1 to change. Here is only some of my code as the whole thing is about 150 lines and I think this bit gets my point across somewhat well:
function myFunction() {
var rng=Math.random();
var rng2=Math.random();
if (rng <= 0.89){
var img1=document.createElement('img');
img1.src='card2.gif';
img1.id="bad1";
img1.onclick = goodbye;
document.getElementById('card').appendChild(img1);
}
if (rng2 <= 0.89){
var img2=document.createElement('img');
img2.src='card2.gif';
img2.onclick= goodbye;
img2.id="bad2";
document.getElementById('card2').appendChild(img2);
}
if (rng >= 0.9) {
var img1=document.createElement('img');
img1.src='card3.gif';
img1.id="good1";
img1.onclick = hello;
document.getElementById('card').appendChild(img1);
}
if (rng2 >= 0.9){
var img2=document.createElement('img');
img2.src='card3.gif';
img2.onclick= hello;
img2.id="good2";
document.getElementById('card2').appendChild(img2);
}
}
Like I said, every thing I've tried to only change the image that was clicked has changed all images whose rng is <=0.89. The answer's probably really obvious, but I'm new to this, like I said.
Based on the comments, the only change that your code needs is to make .onclick set to a function instead of a string. This way we also pass this the element reference to your functions goodbye and hello. You can also use this to read the element properties if you wanted to. If this is not what your looking for let us know.
img1.onclick = function(){goodbye(this)};
Script
function goodbye(e) {
e.src = 'https://www.youtube.com/yt/brand/media/image/YouTube-logo-full_color.png'
}
function hello(e) {
e.src = 'https://pbs.twimg.com/profile_images/767879603977191425/29zfZY6I.jpg'
}
function myFunction() {
var rng = Math.random();
var rng2 = Math.random();
if (rng <= 0.89) {
var img1 = document.createElement('img');
img1.src = 'card2.gif';
img1.id = "bad1";
img1.onclick = function () {
goodbye(this)
};
document.getElementById('card').appendChild(img1);
}
if (rng2 <= 0.89) {
var img2 = document.createElement('img');
img2.src = 'card2.gif';
img2.onclick = function () {
goodbye(this)
};
img2.id = "bad2";
document.getElementById('card2').appendChild(img2);
}
if (rng >= 0.9) {
var img1 = document.createElement('img');
img1.src = 'card3.gif';
img1.id = "good1";
img1.onclick = function () {
hello(this)
};
document.getElementById('card').appendChild(img1);
}
if (rng2 >= 0.9) {
var img2 = document.createElement('img');
img2.src = 'card3.gif';
img2.onclick = function () {
hello(this)
};
img2.id = "good2";
document.getElementById('card2').appendChild(img2);
}
}
jsfiddle if required
I have several canvases. I also have several picture URLs. I want to draw all pictures on the canvas. There is a problem in the drawing function. Drawing the image only works when the image loads completely, but I have to draw the image as it loads. I wrote following code:
for (var i = 2; i < length; i++) {
canvid[i] = "canv" + i;
img[i] = new Image();
img[i].src = "..\\images\\UploadImage\\"+ name + i + ".jpg";
img[i].onload = function () {
var c = document.getElementById(canvId[i]);
var cDraw = c.getContext("2d");
cDraw.drawImage(img[i], 0, 0);
};
I know this code has error, it's kind of pseudo code to show what I want.
Put your logic in
$(documet).ready(function(){
//logic
});
the answer is in following link
stack overflow link
when you want to call on click event on image variable you have to wait for it
so you couldn't use loop you have to put next call on previous image on load event .
var loadImages = function (imageURLarray) {
if (!(startPage < pages))
return;
canvid = "canv" + i;
img.src = imageURLarray[startPage];
// your top code
img.onload = function (e) {
// code, run after image load
var c = document.getElementById(canvid);
var cDraw = c.getContext("2d");
cDraw.drawImage(img, 0, 0);
startPage++;
loadImages(imageURLarray);
}
}
loadImages(imageURLarray);
Hello stackoverflow community!
First I must say that I dont have much experience with constructors.
So. What I am trying to do, is to animate a parachutist to fly from top to bottom of the screen.
I thought I could use a constructor to set up a parachutist:
var parachute = function() {
this.height = 35;
this.width = 30;
this.speed = 50;
this.xPos = Math.round(Math.random() * (window.width - this.width));
this.animate = function() {
this.img = new Image();
this.yPos = 0;
this.img.onload = function() {
ctxPara.globalCompositeOperation = 'copy';
ctxPara.translate(0, this.yPos);
ctxPara.drawImage(this.img, this.xPos, 0);
};
this.img.src = 'para.png';
this.yPos++;
};
};
This constructor is used in a function called 'fly':
var fly = function() {
var newParachute = new parachute();
setInterval(newParachute.animate, newParachute.speed);
};
And this 'fly' function is triggered when the window loads:
window.onload = function() {
var canvasBg = document.getElementById('canvasBg');
// I splitt the Background and the parachutists in two canvas elements
// handling the problem (to erase content and draw new content) with
// the canvas animation.
var canvasPara = document.getElementById('canvasPara');
ctxPara = canvasPara.getContext('2d');
canvasPara.width = window.width;
canvasPara.height = window.height;
canvasBg.width = window.width;
canvasBg.height = window.height;
fly();
clouds(); // background is loading here
};
What you should see, is a Parachutist flying down the screen. But unfortunately you don't...
Now, after that Long text. (Iam very sorry that it is so long :-( ) My question is: Do you know what I am doing wrong? Is my constuctor correct? Is, what i am trying to do, supposed to be written like this? Any advices or suggestions for a succesfull opportunity? (I hope my english isn't that terrible I think it is :-) )
Oh i forgot to mention the error. It's a TypeMissMatchError.
That means 'this.img' is not an img element at this line:
ctxPara.drawImage(this.img, this.xPos, 0);
Now, I followed the example of markE.
Instead of showing me a parachutist. It shows me an error in this line: ctxPara.drawImage(this.img, this.xPos, this.yPos);
var fly = function () {
var newParachute = new parachute();
newParachute.img.load.call(newParachute);
setInterval(newParachute.animate.call(newParachute), newParachute.speed);
};
var parachute = function () {
this.height = 35;
this.width = 30;
this.speed = 25;
this.xPos = Math.round(Math.random() * (window.innerWidth - this.width));
this.img = new Image();
this.yPos = 0;
this.img.isLoaded = false;
this.img.load = function () {
this.img.isLoaded = true;
};
this.img.src = 'parachute.png';
this.animate = function () {
if (this.img.isLoaded) {
ctxPara.clearRect(0, 0, canvasPara.width, canvasPara.height);
ctxPara.drawImage(this.img, this.xPos, this.yPos); // ERROR: 'Unknown Error'.
this.yPos++;
console.log('animating');
}
};
};
I am stuck again. But now i don't even know the reason... Please help!?
Demo: http://jsfiddle.net/m1erickson/ym55y/
A couple of issues:
(1) To get the window width you can use:
window.innerWidth
(2) setInterval calls newParachute.animate.
setInterval(newParachute.animate, newParachute.speed);
But this inside animate the window object--not the Parachute object.
To give the correct this to animate you can use the call method like this:
var newParachute = new parachute();
setInterval(function(){newParachute.animate.call(newParachute);}, newParachute.speed);
(3) You need to deal with clearing previously drawn images or they will still show on your canvas.
I ran through this: PUZZLE CREATING TUTORIAL and completed the puzzle. I'm trying to have the same script run on more than one img on a page. I tried running some of it through a loop:
var i;
for(i=1; i<3; i++){
function init(){
_img = new Image();
_img.addEventListener('load', onImage, false);
_img.src = "images/"+i+".png"
}
function onImage(e){
_pieceWidth = Math.floor(_img.width / PUZZLE_DIFFICULTY)
_pieceHeight = Math.floor(_img.height / PUZZLE_DIFFICULTY)
_puzzleWidth = _pieceWidth * PUZZLE_DIFFICULTY;
_puzzleHeight = _pieceHeight * PUZZLE_DIFFICULTY;
setCanvas();
initPuzzle();
}
function setCanvas(){
_canvas = document.getElementById(""+i+"");
_stage = _canvas.getContext('2d');
_canvas.width = _puzzleWidth;
_canvas.height = _puzzleHeight;
_canvas.style.border = "2px solid red";
}
console.log(i);
}
and I've gotten to a point where I can print the 'i'th picture in the 'i'th canvas id, but it will only print one puzzle at a time and not more.
Everything in the puzzle code is not set up to handle multiple puzzles. You'll actually need to make way more changes than that to have the puzzle get rendered correctly.
What you should probably do is make a new makePuzzle function, that sets up variables for the rest of the functions to use, and then have them accept arguments, instead of relying on the things that are in the global scope..
for an example (This won't work unchanged, but should illustrate my point):
function makePuzzle(puzzleId, difficulty) {
var image = new Image();
image.addEventListener('load', function() {
makePuzzleForImage(image);
}, false);
image.src = "images/"+puzzleId+".png"
}
makePuzzleForImage(image) {
var pieceWidth = Math.floor(image.width / difficulty)
var pieceHeight = Math.floor(image.height / difficulty)
var puzzleWidth = pieceWidth * difficulty;
var puzzleHeight = pieceHeight * difficulty;
var canvas = document.getElementById(""+puzzleId+"");
var stage = canvas.getContext('2d');
canvas.width = puzzleWidth;
canvas.height = puzzleHeight;
canvas.style.border = "2px solid red";
// this also needs to be made so it can accept arguments, but I didn't
// do that for you since it'll take more time:
// initPuzzle();
}
for (var i=1; i<3; i++) {
makePuzzle(i, PUZZLE_DIFFICULTY);
}
var canvas = null;
var context = null;
var img = null;
var frames = [];
var assets = [];
var imgLoadCount = 0;
setup = function (fileArray) {
assets = fileArray;
//Loading an image
for(var i = 0; i < assets.length; i++) {
console.log(i);
frames.push(new Image()); // declare image object
frames[i].onload = onImageLoad(assets.length); //declare onload method
frames[i].src = URL.createObjectURL(assets[i]); //set url
}
};
onImageLoad = function (len) {
console.log("IMAGE!!!");
canvas = document.getElementById("my_canvas"); //creates a canvas element
context = canvas.getContext('2d');
canvas.width = window.innerWidth; //for full screen
canvas.height = window.innerHeight;
var x, y, numTilesRow;
numTilesRow = 10;
imgLoadCount++;
console.log("imgLoadCount = " + frames.length + ", length = " + len);
if(imgLoadCount != len) {
return;
}
for(var index = 0; index < len; index++) {
x = Math.floor((index % numTilesRow));
y = Math.floor(index / numTilesRow);
worldX = x * numTilesRow;
worldY = y * numTilesRow;
context.drawImage(frames[index], worldX, worldY);
}
};
I cant tell why drawImage has suddenly stopped working after inserting the code
if(imgLoadCount != len) {return;} that makes sure that all images are properly loaded. Would some one please help me find a solution to this problem.
You'll have to understand the difference between a function reference and a function call. The .onload property expects to be assigned with a function reference, but you assign it with the return value of the immediate(!) call to the function .onImageLoad. The difference is the parentheses ().
If you want to call a function with parameters as a callback to .onload, then you'd have to include it into an anonymous function (which itself is a function reference)
frames[i].onload = function() {onImageLoad(assets.length);};
With this, of course, you create a closure. This means that at the point of execution the onImageLoad() method will have access to the current value of assets.length (and not to the value at the point of assignment!). But in your case this doesn't make any difference, because assets.length never changes.