Why is my js to create raining bowties not working? - javascript

I am making a project where I need to make an html canvas with raining bowtie images. Here is my js:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
let img = new Image("images.png")
var ok2animate = true;
img.onload = function(){
function Drop() {
this.x = Math.random() * (canvas.width - 20);
this.y = -Math.random() * 20;
this.fallRate = Math.random()*.5+.5;
}
//
Drop.prototype.draw = function () {
// this.x;
// this.y;
ctx.drawImage(img, this.x, this.y)
return (this);
}
//
Drop.prototype.fall = function () {
this.y += this.fallRate;
return (this);
}
function animate() {
// request another animation frame
if (ok2animate) {
requestAnimationFrame(animate);
}
ctx.fillRect(0,0,canvas.width,canvas.height)
//ctx.clearRect(0, 0, canvas.width, canvas.height);
// make all drops fall and then redraw them
for (var i = 0; i < drops.length; i++) {
drops[i].fall().draw();
}
}
// an array of objects each representing 1 drop
var drops = [];
// add some test drops
for (var i = 0; i < 10; i++) {
drops.push(new Drop());
}
setInterval(function(){requestAnimationFrame(animate)}, 1000)
requestAnimationFrame(animate)
}
<canvas id="canvas" width=300 height=300></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
How do I make it so the images rain down at 1 second intervals?
(I have included the image file in the same folder)
I have tried using an image file from the web, using a bigger canvas, uwing other versions of jquery, but none of those worked.

Image creation
You can create a new image with the Image constructor. You already did that, however, the arguments that the constructor accepts are the width and the height of the image, not the url. You need the src property of the image to reference the image file.
And since you only use 1 single image, that isn't changing, you only have to create and load it once. You can reuse the same image for as many times as you want.
Starting the loop
Now, you need to start the loop after all the images (which in this case is one) has been loaded. Listen for the onload event on the image and call the setInterval function whenever the image is loaded.
setInterval will start of the rendering here, so there is no need to call requestAnimationFrame(animate) anywhere else.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// Create the image like this.
const image = new Image(100, 100);
image.src = "https://www.fillmurray.com/100/100";
function Drop() {
this.x = Math.random() * (canvas.width - 20);
this.y = -Math.random() * 20;
this.fallRate = Math.random() * 10 + 0.5;
}
Drop.prototype.draw = function() {
ctx.drawImage(image, this.x, this.y)
return this;
}
Drop.prototype.fall = function() {
this.y += this.fallRate;
return this;
}
const drops = [];
for (let i = 0; i < 10; i++) {
drops.push(new Drop());
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height)
for (const drop of drops) {
drop.fall().draw();
}
}
image.onload = () => {
setInterval(function() {
requestAnimationFrame(animate)
}, 1000)
};
<canvas id="canvas" width=300 height=300></canvas>

Related

How to fill html5 canvas grid squares with image?

I am new to html5 canvas. I want to draw one canvas grid and fill each grid square with an image from an API response. I have following code to draw the grid but I am struggling to fill each square with image.
This is js code:
window.onload = function(){
var c= document.getElementById('canvas');
var ctx=c.getContext('2d');
ctx.strokeStyle='white';
ctx.linWidth=4;
for(i=0;i<=600;i=i+60)
{
ctx.moveTo(i,0);
ctx.lineTo(i,600);
ctx.stroke();
}
for(j=0; j<=600; j=j+60)
{
ctx.moveTo(0,j);
ctx.lineTo(600,j);
ctx.stroke();
}
}
This code helps me drawing canvas grid but how to access each square and fill it with the image. I referred links related to this but seems difficult to understand. Can somebody please help me with this?
It's hard to answer your question without knowing exactly how the image is being returned by the api response. Assuming the api response is returning the image itself (not the image data in JSON or something like that) here is a solution:
html:
<canvas id="canvas" width="600" height="600"></canvas>
javascript:
window.onload = function() {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "green";
ctx.lineWidth = 4;
//draw grid
for (let i = 0; i <= 10; i++) {
const x = i*60;
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
const y = i*60;
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
//draw images
const p = ctx.lineWidth / 2; //padding
for (let xCell = 0; xCell < 10; xCell++) {
for (let yCell = 0; yCell < 10; yCell++) {
const x = xCell * 60;
const y = yCell * 60;
const img = new Image();
img.onload = function() {
ctx.drawImage(img, x+p, y+p, 60-p*2, 60-p*2);
};
//TODO: set img.src to your api url instead of the dummyimage url.
img.src = `https://dummyimage.com/60x60/000/fff&text=${xCell},${yCell}`;
}
}
};
Working example:
https://codepen.io/rockysims/pen/dLZgBm

Creating animations with HMTL5 canvas - Can't seem to add any objects

For a project, I need to take these two blocks of code and modify them to create a little animation. The Javascript document creates a background color and creates like white rectangles fall down, like snow. The HTML document creates the canvas.
I have worked with the HTML canvas and done some super basic animations, but I'm hitting a roadblock here. When I try to add stuff to this, it does not show up. All I want to do is add some text and then animate it going across the canvas and some other very basic stuff.
I tried adding the text to the script portion of the html document like I have done several times before, but it just didn't seem to do anything.
Any idea what I'm doing wrong?
(I'm an animation major, so I apologize in advance for my ignorance; scripting is not my forte)
html document:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>A Basic Animation</title>
<script type="text/javascript" src="buffer-script2.js"></script>
<style type="text/css">
body,td,th {
font-family: Arial, "Franklin Gothic Book", sans-serif;
}
</style>
</head>
<body>
<h2>An Animation with Double Buffer</h2>
<canvas id="Sky" width="600" height="300">
Canvas not supported
</canvas>
<script>
var canvas = document.getElementById("Sky");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.strokeText("Hello World",10,50);
</script>
</body>
</html>
Javascript file:
window.onload = init;
var canvas = null;
var context = null;
var bufferCanvas = null;
var bufferCanvasCtx = null;
var flakeArray = [];
var flakeTimer = null;
var maxFlakes = 200;
function Flake() {
this.x = Math.round(Math.random() * context.canvas.width);
this.y = -10;
this.drift = Math.random();
this.speed = Math.round(Math.random() * 5) + 1;
this.width = (Math.random() * 5) + 2;
this.height = this.width;
}
function init() {
canvas = document.getElementById('Sky');
context = canvas.getContext("2d");
bufferCanvas = document.createElement("canvas");
bufferCanvasCtx = bufferCanvas.getContext("2d");
bufferCanvasCtx.canvas.width = context.canvas.width;
bufferCanvasCtx.canvas.height = context.canvas.height;
// initialize the rects
flakeTimer = setInterval(addFlake, 200);
Draw();
setInterval(animate, 30);
}
function addFlake() {
flakeArray[flakeArray.length] = new Flake();
if (flakeArray.length == maxFlakes)
clearInterval(flakeTimer);
}
function blank() {
bufferCanvasCtx.fillStyle = "#330033";
bufferCanvasCtx.fillRect(0,0,bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);
}
function animate() {
Update();
Draw();
}
function Update() {
for (var i = 0; i < flakeArray.length; i++) {
if (flakeArray[i].y < context.canvas.height) {
flakeArray[i].y += flakeArray[i].speed;
if (flakeArray[i].y > context.canvas.height)
flakeArray[i].y = -5;
flakeArray[i].x += flakeArray[i].drift;
if (flakeArray[i].x > context.canvas.width)
flakeArray[i].x = 0;
}
}
}
function Draw(){
context.save();
/*
// create a clipping region
bufferCanvasCtx.beginPath();
bufferCanvasCtx.fillStyle="black";
bufferCanvasCtx.fillRect(0,0,bufferCanvas.width,bufferCanvas.height);
bufferCanvasCtx.arc(bufferCanvas.width/2,bufferCanvas.height/2,bufferCanvas.height/3,0,2*Math.PI);
bufferCanvasCtx.clip();
*/
blank();
for (var i = 0; i < flakeArray.length; i++) {
bufferCanvasCtx.fillStyle = "white";
bufferCanvasCtx.fillRect(flakeArray[i].x,flakeArray[i].y,flakeArray[i].width,flakeArray[i].height);
}
// copy the entire rendered image from the buffer canvas to the visible one
context.drawImage(bufferCanvas, 0,0,bufferCanvas.width, bufferCanvas.height);
context.restore();
}
I suggest...
Use requestAnimationFrame instead of an interval.
Get rid of the flakeTimer by initializing flakes at negative heights.
Get rid of the double buffer and render everything on one canvas.
Update flake positions relative to the time passed between updates.
Encapsulate updating and drawing of flakes, e.g. by introducing a Snow class.
Simplify iterations such as for (var i = 0; i < flakeArray.length; i++) by using e.g. for (let flake of flakes).
Less reliance on globals, pass canvas context and dimensions as parameters.
function Flake(x, y, drift, speed, size) {
this.x = x;
this.y = y;
this.drift = drift;
this.speed = speed;
this.size = size;
}
class Snow {
constructor() {
this.flakes = [];
}
update(dt, width, height) {
for (let flake of this.flakes) {
flake.y += flake.speed * dt;
if (flake.y > height) {
flake.y = -flake.size;
}
flake.x += flake.drift * dt;
if (flake.x > width) {
flake.x = -flake.size;
}
}
}
draw(ctx) {
ctx.fillStyle = "white";
for (let flake of this.flakes) {
ctx.fillRect(flake.x, flake.y, flake.size, flake.size);
}
}
}
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let snow = new Snow();
// Add flakes:
for (let i = 0; i < 200; ++i) {
snow.flakes.push(new Flake(
Math.round(Math.random() * canvas.width),
-i * 200,
Math.random() * 0.05,
Math.random() * 0.25 + 0.05,
Math.random() * 5 + 2)
);
}
// Animate:
let last = performance.now();
function frame(time) {
// Clear background:
ctx.fillStyle = "#330033";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Update & render snow:
snow.update(time - last, canvas.width, canvas.height);
snow.draw(ctx);
// Render text:
ctx.strokeStyle = "white";
ctx.font = "30px Arial";
ctx.strokeText("Hello World", 10, 50);
requestAnimationFrame(frame);
last = time;
}
requestAnimationFrame(frame);
<canvas id="canvas" width="600" height="300"></canvas>

How do I add four rotating images to an animated background?

I am trying to add four rotating images to an animated background.
I can only get one image working correctly with my code below.
How can I add in the other three images?
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('img');
img.onload = function(){
render();
}
img.src = 'nano3.png';
function drawImage(img,x,y,r,sx,sy){
sx=sx||0;
sy=sy||0;
r=(r*Math.PI/180)||0;
var cr = Math.cos(r);
var sr = Math.sin(r);
ctx.setTransform(cr,sr,-sr,cr,x-(cr*sx-sr*sy),y-(sr*sx+cr*sy));
ctx.drawImage(img,1,2);
}
var r = 1;
function render(){
requestAnimationFrame(render);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,800,800);
drawImage(img,50,50,r++,img.width/2,img.height/2);
}
This should help you out, I just created an object known as rotatingimage which stores a location, an image and its current rotation. We call the 'draw' method in a 'setInterval' function call which deals with rotating the canvas and then drawing the sprite correctly.
Just a note rotating many images can cause the canvas to lag also the CurrentRotation variable never gets reset to 0 when it reaches >359 so the CurrentRotation variable will keep going higher and higher, you may want to fix that in the RotatingImage.prototype.Draw function
jsFiddle:https://jsfiddle.net/xd8brfrk/
Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function RotatingImage(x, y, spriteUrl, rotationSpeed) {
this.XPos = x;
this.YPos = y;
this.Sprite = new Image();
this.Sprite.src = spriteUrl;
this.RotationSpeed = rotationSpeed;
this.CurrentRotation = 0;
}
RotatingImage.prototype.Draw = function(ctx) {
ctx.save();
this.CurrentRotation += 0.1;
ctx.translate(this.XPos + this.Sprite.width/2, this.YPos + this.Sprite.height/2);
ctx.rotate(this.CurrentRotation);
ctx.translate(-this.XPos - this.Sprite.width/2, -this.YPos - this.Sprite.height/2);
ctx.drawImage(this.Sprite, this.XPos, this.YPos);
ctx.restore();
}
var RotatingImages = [];
RotatingImages.push(new RotatingImage(50, 75, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(270, 25, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(190, 180, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(100, 270, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
setInterval(function() {
ctx.fillStyle = "#000"
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < RotatingImage.length; i++) {
var rotatingImage = RotatingImages[i];
rotatingImage.Draw(ctx);
}
}, (1000 / 60));
you can use save and restore to apply different transform to your drawing
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore

Picture background for canvas particle

I'm trying to create background for every created particle.
Canvas pattern is not working properly. I'm getting this error >> "SyntaxError: An invalid or illegal string was specified"
HTML
<canvas id="canvas"></canvas>
JS
(function(){
window.onload = function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'),
particles = {},
particleIndex = 0,
particleNum = 1;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.width);
function Particle(){
this.x = canvas.width / 2;
this.y = 0;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.2;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.test = 0;
this.maxLife = 100;
}
Particle.prototype.draw = function(){
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.test++;
if ( this.test >= this.maxLife ) {
delete particles[this.id];
};
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(this.x, this.y, 20, 20);
};
setInterval(function(){
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
};
for(var i in particles) {
particles[i].draw();
}
},30)
}})();
I was trying to do this also with ctx.drawImage(), but picture was displayed one time only.
Any tips?:)
Fiddle
I think the issue is the image being loaded later than its used.
Inside your draw() you have:
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,20,20);
It is a bad idea to create new images everytime you want to draw. I strongly suggest you create the img variable outside of the draw loop. Once you set the .src of an image, you have to wait until it is loaded to use it. There is an onload event you can use to let you know when its ready.
Here is an example:
var imgLoaded = false;
var img = new Image();
img.src = 'img/aaa.png';
img.onload = function() { imgLoaded = true; };
function draw() {
...
if (imgLoaded) {
var pattern = ctx.createPattern(img, 'repeat');
...
}
...
}

How do I move an image in JavaScript?

I am trying to draw and move an image using JS.
This code works up until the moveImage function which simply does nothing. Can anyone help me figure this out?
I believe that I can get the image to move if I place it in the html, but I would prefer to have the script code place it instead if possible.
function init() {
var x = 1, y = 1;
var context = document.getElementById("Vehicle").getContext("2d");
var img = new Image();
img.onload = function () { context.drawImage(img, x, y, 24, 20); }
img.src = "images/Image.png";
//move
function moveImage(imgX, imgY) {
img.style.left = imgX + "px";
img.style.top = imgY + 'px';
}
setInterval(function () {
var FPS = 60;
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
moveImage(x, y);
}, 1000/FPS);
};
My guess is that img.style.left/right is either not correct or that I am not pointing to img properly.
If there is no way to do this, is there a way for me to remove (not just hide) the image so I can redraw it in the new location?
You have a scope issue. You are defining FPS inside the interval. This needs to be done before so that it can be used on the interval step parameter.
var FPS = 60;
var timer = (1000/FPS);
setInterval(function () {
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
moveImage(x, y);
}, timer);
Furthermore you cannot simply reposition an image on a canvas. It needs to be redrawn onto the canvas.
Once you call context.drawImage() the image can no longer be manipulated. You have, as it suggests, drew this onto the canvas. It's not the same as a HTML element within the DOM. It is now simply coloured pixels on a canvas.
See Demo: http://jsfiddle.net/8Ljvnt8j/1/
However you'll notice that the image is being repeated. This is because you are drawing on top of canvas. The canvas is 2d so you are simply painting on top of what is already there.
Therefore you need to clear down the canvas.
img.onload = function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, imgX, imgY, 24, 20);
}
See Demo: http://jsfiddle.net/8Ljvnt8j/2/
All in all:
function init() {
var x = 1;
var y = 1;
var canvas = document.getElementById("Vehicle");
drawImage();
//move
function drawImage() {
var context = document.getElementById("Vehicle").getContext("2d");
var img = new Image();
img.onload = function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, x, y, 24, 20);
}
img.src = "https://placeholdit.imgix.net/~text?txtsize=5&txt=20%C3%9720&w=20&h=20";
}
var FPS = 60;
var timer = (1000/FPS);
setInterval(function () {
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
drawImage();
}, timer);
};
init();

Categories

Resources