Simultaneous function call in javascript - javascript

here is the code:
var ctx = canvas.getContext('2d');
var chop1 = new Image();
chop1.src = "img/chopper.png";
var blt = new Image();
blt.src = "img/bullet.png"
var chopperX = 0;
var chopperY = 0;
var ascent = 2;
var limit = 500;
var start = null;
var bltX = 135;
function fire()
{
bltX +=ascent;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(blt,bltX,20 ,
chop1.width, chop1.height);
requestAnimationFrame(fire);
}
function up(){
chopperY-=ascent;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(chop1,0,chopperY ,
chop1.width, chop1.height);
requestAnimationFrame(up);
if(chopperY == 20){
setInterval(fire,1000)
}
if(chopperY == 0){
fly();
}
}
function fly() {
chopperY+=ascent;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(chop1,0,chopperY ,
chop1.width, chop1.height);
if (chopperY < limit) {
requestAnimationFrame(fly);
}
if(chopperY==limit){
up();
}
fly();
As per the condition(chopperY == 20),"fire" method is excute.But i want to call "fire" and "fly" function simultaneously at this particular condition. Is there any way to do this? In this code when "fire" method excute then "fly" method stop automatically.Is there any way to solve this issue?

It looks like you are making a game. You should use event listeners. See some examples here or keyboard examples. This would allow you to connect keyboard actions to code and they should run at the same time.

I'm not sure if I understand you correctly but if your goal is, to pass two functions to setInterval, than you can achieve this by wrapping them up in an anonymous function:
if(chopperY == 20){
setInterval(function () {
fire();
fly();
},1000)
}
This will call both functions every second. However, the fire function will get executed first.

Related

why does ctx.fillRect() executed only after the for loop is over?

I want to build a basic function where an Object (Rectangle) is painted, it's x coordinate is changed and than painted again. However, when I execute my code nothing happens until my for loop is over and than everything gets executed at the same time.
ctx = document.querySelector('canvas').getContext('2d');
class Car{
constructor(options){
this.pos = options.pos;
this.size = options.size;
this.color = options.color;
}
draw(){
ctx.fillStyle = this.color;
ctx.fillRect(this.pos[0], this.pos[1], this.size[0], this.size[1]);
}
move(){
this.pos[0] = this.pos[0] + 10;
}
}
const audi = new Car({pos: [10,10], size: [300,20], color: "red"});
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
function drawAndMove(){
audi.draw();
audi.move();
sleep(1000);
ctx.clearRect(0, 0, 300, 20);
}
for (let i = 0; i < 10; i++) {
drawAndMove();
}
<canvas></canvas>
When you use sleep(1000) all the script is paused.
Javascript is single threaded language that mean the code is executed synchronously line after line, if you want to make thing append later than they should be, use setTimeout than sleep()
like that :
function drawAndMove(){
audi.draw();
audi.move();
setTimeout(() => {
ctx.clearRect(0, 0, 300, 20);
}, 1000);
}
By this way the code will continue to run sidedly and the script wont be paused !

Paint a line step to step with time function

I wrote this code but it don't work. Javascript draws the line at once, instead of showing me how the line is drawn
What am I doing wrong? Thanks
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = 200;
while (i<220) {
ctx.beginPath();
ctx.lineWidth = 10;
ctx.lineCap = "butt";
ctx.moveTo(20, 20);
ctx.lineTo(i, 20);
ctx.stroke();
console.log("Hello");
sleep(200);
console.log("World!");
i++
}
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
<p>The three different line caps:</p>
<canvas id="myCanvas">Example</canvas>
Just use setInterval to see the animation like this :
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
let i = 0;
const startInterval = function(){
i += 5
ctx.beginPath();
ctx.lineWidth = 10;
ctx.lineCap = "butt";
ctx.moveTo(20, 20);
ctx.lineTo(i, 20);
ctx.stroke();
if(i === 220){
clearInterval(interval);
console.log("finished")
}
}
let interval = setInterval(startInterval, 200)
<p>The three different line caps:</p>
<canvas id="myCanvas">
Example</canvas>
I can't explain exactly why that behaviour is occurring, but I do have a solution. Typically if you want to perform the same task in repeated intervals, you use setInterval. There's also setTimeout which you could use, but the first is more appropriate.
var number = 0;
// you pass the function to call, and how often as arguments
let count = setInterval(countUpTo5, 500);
function countUpTo5() {
if (number > 5) {
// by passing the name of the interval, you can stop it
clearInterval(count);
} else {
console.log(number);
number++;
}
}
Good luck, and if you'd like more help just leave a comment.
That's because canvas does not update itself while code is running. You can easily see the effect by changing canvas border color for example. The only way to solve this is to imulate async operations with setTimeout or setInterval, as offered above. By this you make the stack empty for a while and canvas repaints as the result within each iteration.

My Game loop accelerates and character leaves a trail

The code:
// create stuff
var ghObj = {
x : 0,
y : 0
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var ghost = new Image();
ghost.src = "ghost.png"
//define variables
var ghostMove = function () {
ghObj.x+=(Math.floor(Math.random() * 9 - 4))
console.log(ghObj.x)
ghObj.y+=(Math.floor(Math.random() * 9 - 4))
}
var ghostCheck = function () {
if (ghObj.x<0) {
ghObj.x=0
}
if (ghObj.x>390) {
ghObj.x=390
}
if (ghObj.y<0) {
ghObj.y=0
}
if (ghObj.y>390) {
ghObj.y=390
}
}
var drawIm = function (sprite, position) {
ctx.save();
ctx.translate(position.x, position.y);
ctx.drawImage(sprite, 0, 0, sprite.width, sprite.height, 0, 0, sprite.width, sprite.height);
ctx.restore();
};
// begin "game" when ghost is loaded
ghost.onload = function() {
mainLoop()
}
// main loop
function() {
ghostMove()
ghostCheck()
drawIm(ghost, ghObj)
setInterval(mainLoop, 1000)
}
sorry if its a bit long.
what's supposed to happen is the ghost moves randomly round the screen at a steady rate.
instead, it moves randomly but increasingly quickly and leaves copies of itself everywhere.
Isn't the restore function supposed to clear the screen each time?
have i got the game loop wrong?
thanks in advance.
function mainLoop(){
setInterval(mainLoop,100);
}
I think the error is obvious. I recommend to use setTimeout or requestAnimationFrame instead... And this should remove the duplicates i think its an optical ilusion
...

HTML5 Canvas Drawing History

I'm curious to know how applications such as Adobe Photoshop implement their drawing history with the ability to go back or undo strokes on rasterized graphics without having to redraw each stroke from the beginning...
I'm wanting to implement a similar history function on an HTML5 drawing application I'm working on but duplicating the canvas after every stoke seems like it'd use too much memory to be a practical approach, especially on larger canvas'...
Any suggestions on how this might be implemented in a practical and efficient manner?
I may have a solution.....
var ctx = document.getElementById("canvasId").getContext("2d");
var DrawnSaves = new Array();
var Undo = new Array();
var FigureNumber = 0;
var deletingTimer;
function drawLine(startX, startY, destX, destY) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(destX, destY);
ctx.stroke();
var Para = new Array();
Para["type"] = "line";
Para["fromX"] = startX;
Para["fromY"] = startY;
Para["toX"] = destX;
Para["toY"] = destY;
DrawnSaves.push(Para);
FigureNumber++;
}
function undo() {
ctx.beginPath();
ctx.clearRect(0, 0, 500, 500);
Undo[FigureNumber] = DrawnSaves[FigureNumber];
DrawnSaves[FigureNumber] = "deleted";
FigureNumber--;
drawEverything();
startTimeoutOfDeleting();
}
function undoTheUndo() {
FigureNumber++;
DrawnSaves[FigureNumber] = Undo[FigureNumber];
drawEverything();
clearTimeout(deletingTimer);
}
function drawEverything() {
for (i = 0; i < DrawnSaves.length; i++) {
if (DrawnSaves[i].type == "line") {
ctx.beginPath();
ctx.moveTo(DrawnSaves[i].fromX, DrawnSaves[i].fromY);
ctx.lineTo(DrawnSaves[i].toX, DrawnSaves[i].toY);
ctx.stroke();
}
}
}
function startTimeoutOfDeleting() {
setTimeout(function() {Undo[FigureNumber] = "deleted";}, 5000);
}
This is really simple, first I draw a line when the function is called and save all his parameters in an array. Then , in the undo function I just start a timer do delete the figure drawn i 2000 miliseconds, clears the whole canvas and makes it can't be redrawn. in the undoTheUndo function, it stops the timer to delete the figure and makes that the figure can be redrawn. In the drawEverything function, it draws everything in the array based on it's type ("line here"). That's it... :-)
Here is an example working : This, after 2sec UNDOs then after 1sec UNDOTHEUNDO

How do I capture the onclick event called in HTML?

So, I have an <img> tag that has an onclick attribute. The onclick calls a function called analyze(this), with this being the image.
The analyze function does some things to the image that aren't entirely relevant, except for the fact that it draws it onto the <canvas> element (using the drawImage function).
But now, I want to also pick the color I just clicked on in the image. I am currently using the method answered here (the answer with 70+ votes, not the chosen one): How do I get the coordinates of a mouse click on a canvas element?
But, I think I might be doing this wrong. I have the image drawn and my functions called (and those all work), but the color picking part isn't being called. I think that this is because I didn't actually capture the event. This is generally how my code looks:
<img onclick="javascript:analyze(this);" />
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
img = new Image();
img.onload = function () {
canvaselement.drawImage(img, 0, 0, 250, 250);
...
canvaselement.onClick = function () {
var coords = canvaselement.relMouseCoords(event);
pick(img, canvaselement, coords); // pass in coordinates
}
}
img.src = img_elem.src;
}
function relMouseCoords(event) {
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return {
x: canvasX,
y: canvasY
}
}
function pick(img, canvaselement, coords) {
var pickedColor = "";
canvaselement.drawImage(img, 0, 0, 250, 250);
xx = coords.x;
yy = coords.y;
var imgData = canvas.getImageData(xx, yy, 1, 1).data;
pickedColor = rgbToHex(imgData);
//alert(pickedColor);
return pickedColor;
}
So, the code never gets to the pick function. I have a feeling that it's because I didn't actually capture the onclick event. I'm also not even sure if this is the right way to get the coordinates on the canvas, I'm just sort of hoping that I even get to that part of the debugging process at this point.
Thanks for your help!
The problem is probably that you're assigning canvaselement to the results of getContext('2d') and not to the element itself, which you will need for the click event binding. Create two variables, one for the DOM element itself and one for the context, something like:
var canvaselement = document.getElementById('canvas'),
canvaselementctx = canvaselement.getContext('2d');
...
canvaselement.onClick = function() {
var coords = canvaselementctx.relMouseCoords(event);
...
}
You have a couple of errors in the code but the reason the code you got from the linked post is that you forgot to include the prototype definition it uses:
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
Now you can call relMouseCoords on the canvas element:
/// event name in lower case
canvaselement.onclick = function () {
var coords = canvaselement.relMouseCoords(event);
//...
However, you will still get problems as you don't use a canvas context for the drawing calls.
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
/// get context like this
ctx = canvaselement.getContext('2d'),
img = new Image();
img.onload = function () {
/// use context to draw
ctx.drawImage(img, 0, 0, 250, 250);
//...

Categories