javascript Canvas Animation with setInterval - javascript

I have a problem in my code it dont work and i dont find the misstakes i think the misstakes is because the many nesting and i have set a bracket on the wrong place.
The Function from the code is a Animation in the Animation are some images at the top of the canvas and than should this images slowly came from the top to the bottom like a watterfall.i hope you can understand my explanation.
console.log("hey");
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'); //ctx = contex
var img = new Image();
img.src="../img/cookie.png";
canvas.width = canvas.scrollWidth;
canvas.height = canvas.scrollHeight;
img.onload = function() {
console.log("Loaded image")
var add = 10;
var id = setInterval(function () {
if (add == 500) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , 0, 100, 100);
ctx.drawImage(img,100,0, 100, 100);
ctx.drawImage(img,200,0, 100, 100);
ctx.drawImage(img,300,0, 100, 100);
ctx.drawImage(img,400,0, 100, 100);
ctx.drawImage(img,500,0, 100, 100);
ctx.drawImage(img,600,0, 100, 100);
ctx.drawImage(img,700,0, 100, 100);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , add, 100, 100);
ctx.drawImage(img,100,add, 100, 100);
ctx.drawImage(img,200,add, 100, 100);
ctx.drawImage(img,300,add, 100, 100);
ctx.drawImage(img,400,add, 100, 100);
ctx.drawImage(img,500,add, 100, 100);
ctx.drawImage(img,600,add, 100, 100);
ctx.drawImage(img,700,add, 100, 100);
add++;
}
}, 10)
}
PS:sorry if some misstakes in my text but i am still student. :D
PPS: thanks for the help.
EDIT: Now it works thanks for the help.
**EDit2:**now i have a nother problem the code will only exectude one time but it should excetuded the full time if anybody can help me i am very danbar.

I think all of your brackets are in the right place. The big error I see is that your if statement says if (add = 1000) using single = instead of double ==. This means that you're setting add to 1000 in your if statement instead of comparing it.
Edit: Another issue you had was that your image src was being defined in its onload, which doesn't really make sense, as the onload waits for src to be loaded.
I made a jsfiddle here where your code works, check it out: https://jsfiddle.net/pjkmwvp6/

Can you try changing this???
// Change this
if(add = 1000){
// To this
if(add === 1000){

To address any doubts you may have with brackets, many editors and web services can perform code beautifying (aka pretty printing) for you. Give it a Google. Also, there’s one such tool build into Firefox with the Shift+F4 “slate”, just paste your code in it and hit Ctrl+P.
I think you’re not loading your image the right way. Be aware that setting an image’s src attribute is what actually triggers its loading. As is, your code can’t load the image since the instruction that sets src is inside the onload handler. Put it after.
When dealing with animations, setInterval is not the best suited function. Prefer requestAnimationFrame. Its syntax is very close and it has CPU-saving capabilities.

Related

How to move ellipse filled with an image to mask similar background?

I am a super early user of coding from Italy.
I came up with an idea to promote a company logo on their website and I almost reached the goal so I am sharing this problem.
The idea is to obtain a sort of clipping mask effect when the mouse/cursor move on the image
I've made so far a code that does the work with a still ellipse.
When I set the position parameters of the ellipse as mouseX and mouseY the effect does not work if not just a bit of a glitch at the start.
How can I make it work as intended?
Here you can find the link of what I have now:
https://editor.p5js.org/francesco.ficini.designer/full/FLBuhggW-
Here the code:
let img;
let imgbg2;
let maskImage;
function preload() {
img = loadImage("NeroP.jpg");
imgbg2 = loadImage("RossoP.jpg");
}
function setup() {
createCanvas(400, 225);
img.mask(img);
}
function draw() {
background(imgbg2, 0, 0);
//Immages
image(imgbg2, 0, 0);
image(img,0,0);
// Ellipse Mask
maskImage = createGraphics(400, 225);
maskImage.ellipse(200, 100, 50, 50);
imgbg2.mask(maskImage);
image(imgbg2, 0, 0);
}
The thing about the p5.Image.mask function is that it modifies the image that is being masked. Which means that any pixels that are cleared by the mask are gone for good. So if you want to dynamically change the mask you will need to make a copy of the original and re-apply the modified mask any time it changes.
Additionally you will want to avoid creating images and graphics objects in your draw() function because this can result in excessive memory allocation. Instead create a single set of graphics/images and re-use them.
let img;
let imgbg2;
let maskImage;
let maskResult;
function preload() {
img = loadImage("https://www.paulwheeler.us/files/NeroP.jpeg");
imgbg2 = loadImage("https://www.paulwheeler.us/files/RossoP.jpeg");
}
function setup() {
createCanvas(400, 225);
// Create graphics and image buffers in setup
maskImage = createGraphics(imgbg2.width, imgbg2.height);
maskResult = createImage(imgbg2.width, imgbg2.height);
}
function mouseMoved() {
if (maskResult) {
maskImage.clear();
// Ellipse
maskImage.ellipse(mouseX, mouseY, 50, 50);
// Copy the original imgbg2 to the maskResult image
maskResult.copy(
imgbg2,
0, 0, imgbg2.width, imgbg2.height,
0, 0, imgbg2.width, imgbg2.height
);
// apply the mask to maskResult
maskResult.mask(maskImage);
}
}
function draw() {
//Immagini
image(img, 0, 0);
// draw the masked version of the image
image(maskResult, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Extreme Novice needing assistance with mousePressed() event

I am VERY new to P5.js/processing (taking programming for artists). I am trying to make a crude game where an image (Jar Jar) bounces across the screen and another image (lightsaber) that moves with the mouse and when the mouse attached image goes over the bouncing image then the lightsaber will be mirrored and activate a sound. If this at all makes sense...
I have the bouncing image part down so far, but I am unable to make the mousePressed() function work. like I mentioned, I need the "lightsaber.png" to flip when the mouse is pressed. Also, when the mouse is pressed and is directly over the JarJar image, how would I add a score count and sound event?
Thank you!
here is my code so far:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700,700);
xspeed=random (15,22);
yspeed=random (15,22);
}
function draw() {
background(0);
image (lightSaber,mouseX,mouseY,100,100);
image(jarJar,jarJarX,jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200){
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ){
yspeed=yspeed*-1;
}
//picture mirrors when mouse pressed
if mouseClicked(){
scale(-1,1);
image(lightSaber);
}
//score counter coordinate with lightsaber hitting image
//
}
Let it be known that I'm not proficient at javaScript. This said, your question is quite simple so I can help anyway.
Some framework will have simple ways to mirror images. Processing likes to scale with a negative number. I re-coded some of your stuff to accommodate my changes. The main changes goes as follows:
I added a method to draw the lightsaber so we can "animate" it (read: flip it for a couple frames when the user clicks around).
I added a 'score' global variable to track the score, and a way for the user to see that score with the text method.
I added a method called "intersect" which isn't very well coded as it's something I did back when I was a student (please don't hurt me, it works just right so I still use it from time to time). For more details on how simple collisions works, take some time to read this answer I wrote some time ago, there are nice pictures too!
I added a mouseClicked method. This method will act like an event, which means that it will be triggered by a specific call (a left mouse button click in this case). This method contains the code to check for a collision between the squares which are the images. If there's an overlap, the score will increase and jarjar will run in another direction (this part is a bonus to demonstrate that this is the place where you can get creative about the collision).
I commented the code so you can get what I'm doing more easily:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
let flipLength;
let score = 0;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700, 700);
runJarJarRun();
}
function draw() {
background(0);
drawLightSaber(); // this way I can deal with the lightsaber's appearance in a dedicated method
image(jarJar, jarJarX, jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200) {
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ) {
yspeed=yspeed*-1;
}
//score counter coordinate with lightsaber hitting image
textSize(30);
fill(200, 200, 0);
text('Score: ' + score, 10, 40);
}
function drawLightSaber() {
if (flipLength) { // if the number is > 0 this will be true
flipLength--; // measure how ling the saber is flipped in frames # ~60 frames per second
push(); // isolating the translate ans scale manpulations to avoid ruining the rest of the sketch
translate(mouseX + 100, 0); // makes the coordinates so once flipped the lightsaber will still appear at the same location
scale(-1.0, 1.0); // flip x-axis backwards
image (lightSaber, 0, mouseY, 100, 100);
pop(); // ends the sequence started with 'push();'
} else {
image (lightSaber, mouseX, mouseY, 100, 100);
}
}
function runJarJarRun() {
xspeed=random (5, 10);
yspeed=random (5, 10);
}
function mouseClicked() { // this method will trigger once when the left mouse button is clicked
flipLength = 10;
if (intersect(jarJarX, jarJarY, 140, 200, mouseX, mouseY, 100, 100)) {
score++;
runJarJarRun(); // as a bonus, jarjar will run in another direction on hit
// you could totally put some more special effects, like a flash, a sound, some 'mesa ouchie bad!' text, whatever speaks to you
}
}
function intersect(x1, y1, w1, h1, x2, y2, w2, h2) {
let checkX = false;
let checkY = false;
if ( (x1<x2 && (x1+w1)>x2) || (x1<(x2+w2) && (x1+w1)>x2+w2) || (x1>x2 && (x1+w1)<(x2+w2)) ) {
checkX = true;
}
if ( (y1<y2 && (y1+h1)>y2) || (y1<(y2+h2) && (y1+h1)>y2+h2) || (y1>y2 && (y1+h1)<(y2+h2)) ) {
checkY = true;
}
return (checkX && checkY);
}
If there's something you don't understand, let me know in a comment and I'll be happy to elaborate. Good luck and have fun!
Hi and welcome to stack overflow. One thing to keep in mind when submitting here (or any forum where you're looking for help with code) is to post a minimal reproducible example. You'll be much more likely to get useful responses.
You'll also want to separate out your questions, as they each have multi-step responses.
Your first question is about how to get your sketch to display something when you press the mouse down. Your syntax isn't quite correct there. Here's a minimal example of how to check for a mouse held down.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if (mouseIsPressed == true) {
ellipse(100, 100, 100, 100);
}
}
Just a quick note that I tried to make this as 'novice-friendly' as possible. The == true is optional and not usually included.

How to fix clearRect?

Just as an introduction, I'm a beginner with JS so maybe the answer to the following problem is simple but I'm just not seeing it.
I have the following code:
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth
canvas.height = window.innerHeight
let img = new Image();
img.onload = function() { ctx.drawImage(img, 0, 0); };
img.src = './tree.jpg';
Which works, so no problem here.
Then I have:
ctx.clearRect(0, 0, 300, 300);
img.src = './tree.jpg';
ctx.drawImage(img, 730, 720);
And for some reason that eludes me, the clearRect doesn't want to work in that sequence.
Any suggestions are kindly appreciated.
Thanks
clearRect() does not work as intended here since the image hasn't been drawn on the canvas yet. What has happened here is the canvas gets cleared and then the image loads.
As Mozilla says here,
If you try to call drawImage() before the image has finished loading, it won't do anything (or, in older browsers, may even throw an exception). So you need to be sure to use the load event so you don't try this before the image has loaded:
Similiar to how you're using drawImage() in the onload(), clear your Rectangle after your image has loaded and been drawn.
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.clearRect(0, 0, 300, 300);
};

How do you update HTML5 canvas from angular?

I have a little canvas that draws a cross and an input box to control the angle of rotation.
<input type='text' ng-model='angle'>
<canvas id="myLitleCanvas" width="200" height="200"></canvas>
<script>
var canvas = document.getElementById('myLitleCanvas');
var context = canvas.getContext('2d');
context.save();
context.translate(100, 100);
context.rotate({{angle}} * Math.PI / 180.0); // <---- problem
context.translate(-100, -100);
context.beginPath();
context.moveTo(100, 0);
context.lineTo(100, 200);
context.moveTo(0, 100);
context.lineTo(200, 100);
context.stroke();
</script>
Then I have a very simple controller bound to angle
function MapCtrl($scope) {
$scope.angle = 45;
}
ButI can't seem to access angle or redraw the canvas when the value in the text box changes. Is this even possible?
There is no token replacement in javascript blocks. The recommended way of doing DOM manipulation is to put your javascript code into a directive. You would then have an attribute that references your 'angle' parameter. You might want to look at angular-ui for ideas on doing custom UI directives. Hope this helps.
As previously mentioned, there is no token replacement in javascript blocks.
To get this working...move the code from the script block with the controller. And just simply access the angle as $scope.angle. You could also write a rotateAndRedraw function and bind to ng-click or whatever:
$scope.rotateAndRedraw = function (angle) {
context.clearRect(x,y,width,height);
context.translate(100, 100);
context.rotate(angle * Math.PI / 180.0);
context.translate(-100, -100);
context.beginPath();
context.moveTo(100, 0);
context.lineTo(100, 200);
context.moveTo(0, 100);
context.lineTo(200, 100);
context.stroke();
};
You could also wrap all this canvas code within a directive and easily replicate the canvas multiple times on a page.

javascript canvas detect click on shape

I have a problem with the click function in javascript. This is my code:
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext('2d');
BigCircle = function(x, y, color, circleSize) {
ctx.shadowBlur = 10;
ctx.shadowColor = color;
ctx.beginPath();
ctx.arc(x, y, circleSize, 0, Math.PI * 2, true);
ctx.fill();
ctx.closePath();
};
var bigGreen = new BigCircle(1580, 800, '#5eb62b', 180);
function init() {
$("#bigGreen").click(function(e){
alert("test");
});
}
$(document).ready(function() {
init();
});
But the click event is not working! Does anybody know why? Thank you so much in advance!
You can now use hit regions in Chrome and Firefox:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility#Hit_regions
(Edit: Hit regions are now obsolete)
or just use one of the many canvas APIs:
http://www.fabricjs.com/
http://www.createjs.com/easeljs
http://www.paperjs.org
etc...
without seeing your html this question is a little bit unclear, it seems you would like to draw something on a canvas and use jquery to add click events for the circle, this isn't possible.
you can use jquery to get the click event ON the canvas and from the cursor position you can calculate if the user clicked the circle or not, but jquery won't help you here you have to do the math yourself.
jquery does only work for dom elements.
BigCircle = function(ctx,x, y, color, circleSize) {
ctx.beginPath();
ctx.arc(x, y, circleSize, 0, Math.PI * 2, true);
ctx.fillStyle=color
ctx.fill();
ctx.closePath();
this.clicked=function(){
ctx.fillStyle='#ff0000'
ctx.fill();
}
};
function init() {
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext('2d');
var bigGreen = new BigCircle(ctx,50, 50, '#5eb62b', 50);
$('#canvas').click(function(e){
var x = e.clientX
, y = e.clientY
if(Math.pow(x-50,2)+Math.pow(y-50,2) < Math.pow(50,2))
bigGreen.clicked()
})
}
$(document).ready(function() {
init();
});
​
jsfiddle is here
http://jsfiddle.net/yXVrk/1/
Canvas API function isPointInPath() can be used to assist with hit detection. This function can at least tell if mouse coordinates are within a complex shape without doing sophisticated math yourself. May work for simple shapes as well but my use case was for on a bezier curve path. However, you need to either incorporate this function in your drawing logic to test while paths are open or keep an array of Path2d objects to test against. I redraw on onClick handler and pass in mouse coords from event args, but I think I could have kept an array of Path2d objects instead.
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath
bigGreen is not in the HTML, so $("#bigGreen") selects nothing. You can't put a click function on things like JavaScript functions; since they don't exist in the DOM, how could you click one? You should replace #bigGreen with #canvas, since "canvas" is your HTML element.
I forked your fiddle to show this here.
Edit: If you want to see that the user clicked on a particular circle, you use the canvas click event, and then, you determine which circle was clicked by the coordinates passed into the click event.

Categories

Resources