How to work with timer in canvas javascript? - javascript

I need to make a rectangle appear randomly somewhere in the canvas, and then it will need to appear randomly in a new place, but I have one problem, it appears a new one but the previous rectangle stay where it was at the beginning and then there are so many rectangles in the canvas, I need to be only one, this is what I've done:
function rectangle(x,y){
var ctx
ctx.beginPath();
ctx.rect(20, 20, 15, 10);
ctx.stroke();
}
function randomMove(){
var myVar;
var x;
var y;
x = Math.floor(Math.random() * 10) + 1;
y = Math.floor(Math.random() * 10) + 1;
myVar = setInterval( ()=> {rectangle(x,y)}, 5000); // pass the rectangle function
}

You need to clear the canvas.
The easiest way is to draw a rectangle over entire canvas (assuming it's a white background)
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
or if it is transparent...
ctx.clearRect(0, 0, width, height);
You will need to do this on every frame.
const ctx = window.canvas.getContext("2d");
function clearCanvas() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
function rectangle(x, y) {
ctx.beginPath();
ctx.fillStyle = "red";
ctx.rect(x, y, 15, 10);
ctx.stroke();
}
function randomMove() {
var myVar;
var x;
var y;
x = Math.floor(Math.random() * ctx.canvas.width) + 1;
y = Math.floor(Math.random() * ctx.canvas.height) + 1;
rectangle(x, y);
}
function draw() {
clearCanvas();
randomMove();
}
myVar = setInterval(draw, 200);
draw();
<canvas id="canvas"></canvas>

Related

Rectangle is not moving

I am trying to code a rectangle moving but it is not working and I do not understand why. I created a class for the rectangle and gave the parameters value. Then I drew the rectangle. I am trying to add the value of 5 to the rectangle's x but nothing is happening.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var width = 50;
class Rectangle{
constructor(x, y){
this.x = x;
this.y = y;
}
draw(){
ctx.beginPath();
ctx.rect(this.x, this.y, width, height);
ctx.fillStyle = "0095DD";
ctx.fill();
ctx.closePath();
}
}
function movingRectangle(){
var rect = new Rectangle(canvas.width/2 - width/2, 300);
rect.draw();
rect.x += 5;
}
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
movingRectangle();
}
var interval = setInterval(draw, 10);
You're recreating rect on each movingRectangle() call, effectively resetting its position to the initial value.
Move this:
var rect = new Rectangle(canvas.width/2 - width/2, 300);
Out of the movingRectangle() function - you only need to create the Rectangle instance once.
I managed to do a short example, based in your code, and leaving the Rectangle constructor outside:
function movingRectangle(){
let x = rect ? rect.x + 5 : canvas.width/2 - width/2;
if (!rect)
rect = new Rectangle(x, 300);
rect.x = x;
rect.draw();
}
https://jsfiddle.net/nicoavn/vc254q0a/4/

Animating circle in html canvas with javascript

I need to animate a circle moving in a html canvas. For this purpose, I decided to use a typical sprite animation technique which consist in the following general steps:
Initialize the background (in this case, just a gray rectangle)
Calculate new sprite's coordinates
Draw the sprite (the circle)
Reset the backgound
Goto 2
My problem is that the result looks like all the old circles seem to be redrawn each time I call ctx.fill() despite I am reseting the canvas.
What am I doing wrong? Any suggestion?
var canvas;
var ctx;
var canvasPos;
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
function init() {
canvas = document.getElementById("target_temp");
ctx = canvas.getContext("2d");
canvasPos = { x: canvas.offsetLeft, y: canvas.offsetTop };
drawSlider();
}
var y = 7;
function animate() {
y = y + 1;
knob.setPosition(8, y);
knob.clear();
knob.draw();
if (y < 93) {
setTimeout(animate, 10);
}
}
function drawSlider() {
ctx = canvas.getContext("2d");
ctx.fillStyle = "#d3d3d3";
ctx.fillRect(0, 0, 16, 100);
}
var knob = {
position: { x: 8, y: 7 },
oldPosition: { x: 8, y: 7 },
setPosition(_x, _y) {
this.oldPosition = this.position;
this.position.x = _x;
this.position.y = _y
},
clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawSlider();
},
draw() {
ctx.fillStyle = rgbToHex(0, 0, 112);
ctx.arc(8, this.position.y, 7, 0, 2 * Math.PI);
ctx.fill();
}
}
window.onload = function () { init(); animate(); };
<!DOCTYPE html>
<html>
<boyd>
<canvas id="target_temp" width="16px" height="100px"></canvas>
</boyd>
</html>
I see you already figured out to use the beginPath but I will disagree with the location I will put that at the very beginning of the function animate, take a look at the code below, I refactored your code, got rid of some unused variables, and made the slider an object just like you have for the knob
var canvas = document.getElementById("target_temp");
var ctx = canvas.getContext("2d");
var slider = {
width: 16,
height: 100,
draw() {
ctx.fillStyle = "#d3d3d3";
ctx.fillRect(0, 0, this.width, this.height);
}
}
var knob = {
position: {x: 8, y: 7},
radius: 8,
draw() {
ctx.fillStyle = "#00D";
ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
}
function animate() {
ctx.beginPath()
ctx.clearRect(0, 0, canvas.width, canvas.height);
slider.draw();
if (knob.position.y + knob.radius < slider.height)
knob.position.y++;
knob.draw();
setTimeout(animate, 10);
}
window.onload = function() {
animate()
};
<canvas id="target_temp"></canvas>
Ok, I found the cause: the arc() method stacks the circle as part of the path, so, for it to work, we need to reset the path like this:
draw() {
ctx.fillStyle = rgbToHex(0, 2*y, 107);
ctx.beginPath();
ctx.arc(8, this.position.y, 7, 0, 2 * Math.PI);
ctx.fill();
}

Use image to fill in arc in canvas using javascript

So I am totally new to canvas and trying a project in which I need to make small balls move around with their background as images. Following code is what I am trying right now.
ctx.beginPath();
ctx.arc(
this.pos[0], this.pos[1], this.radius, 0, 2 * Math.PI, true
);
let tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
let ballbackground = new Image();
if (this.color === "green") {
ballbackground.src = "https://s26.postimg.cc/fl2vwj1mh/greenball.png";
}
else if (this.color === "yellow") {
ballbackground.src = "https://s26.postimg.cc/if61a18yh/yellowball.png";
}
else if (this.color === "blue") {
ballbackground.src = "https://s26.postimg.cc/xb4khn7ih/blueball.jpg";
}
tempCanvas.width = 50;
tempCanvas.height = 50;
tCtx.drawImage(ballbackground,0,0,ballbackground.width, ballbackground.height,0,0,50,50);
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
And for moving those balls I do as follows:
const velocityScale = timeDelta / NORMAL_FRAME_TIME_DELTA,
offsetX = this.vel[0] * velocityScale * this.speed,
offsetY = this.vel[1] * velocityScale * this.speed;
this.pos = [this.pos[0] + offsetX, this.pos[1] + offsetY];
However, the problem is when objects move they seem like sliding over background image like so:
If I try "no-repeat" with createPattern, the balls won't display at all.
What I want is those balls with background images moving on the canvas?
move the balls by using the canvas transform?
const ctx = document.querySelector("canvas").getContext("2d");
const pattern = createPattern(ctx);
function drawCircleByPosition(ctx, x, y) {
ctx.beginPath();
ctx.arc(x, y, 50, 0, Math.PI * 2, true);
ctx.fill();
}
function drawCircleByTransform(ctx, x, y) {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(0, 0, 50, 0, Math.PI * 2, true);
ctx.fill();
ctx.restore();
}
function render(time) {
time *= 0.001;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = pattern;
drawCircleByPosition(ctx, 90, 75 + Math.sin(time) * 50);
drawCircleByTransform(ctx, 210, 75 + Math.sin(time) * 50);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function createPattern(ctx) {
const tCtx = document.createElement("canvas").getContext("2d");
tCtx.canvas.width = 50;
tCtx.canvas.height = 50;
tCtx.fillStyle = "yellow";
tCtx.fillRect(0, 0, 50, 50);
for (let x = 0; x < 50; x += 20) {
tCtx.fillStyle = "red";
tCtx.fillRect(x, 0, 10, 50);
tCtx.fillStyle = "blue";
tCtx.fillRect(0, x, 50, 10);
}
return ctx.createPattern(tCtx.canvas, "repeat");
}
canvas { border: 1px solid black; }
<canvas></canvas>
note that rather than call save and restore you can also just set the transform with setTransform which is probably faster since save and restore saves all state (fillStyle, strokeStyle, font, globalCompositeOperation, lineWidth, etc...).
You can either pass in your own matrix. Example
ctx.setTransform(1, 0, 0, 1, x, y); // for translation
and/or you can reset it to the default whenever and then use the standard transform manipulation functions
ctx.setTransform(1, 0, 0, 1, 0, 0); // the default
ctx.translate(x, y);
or whatever combination of things you want to do.

How does the background change every n seconds?

he requestAnimationFrame function, updates the canvas too fast, so, I can not do what I want. What do I want ? I want to change the background color of the canvas, every 2 seconds, but the problem is that I am cleaning the canvas in each frame. What I can do ?
(function(d, w) {
var canvas = d.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var x = 0,
y = 0,
speedX = .9;
update(x, y, speedX);
function update(x, y, speedX) {
var color = "";
setTimeout(function() { // Here i try set the color each 2s
color = randomColor(); // Need the color here
}, 2000);
ctx.fillStyle = color; // here paint the background
ctx.fillRect(0, 0, canvas.width, canvas.height); // paint
x += speedX;
box(x, y, speedX);
requestAnimationFrame(function() { // animation frame
update(x, y, speedX);
});
}
function box(x, y, speedX) {
ctx.fillStyle = "Black";
ctx.fillRect(+x, +y, 50, 50);
ctx.stroke();
}
function randomColor() {
for (var i = 0, str = "", hex = "0123456789ABCDEF",
random, max = hex.length; i < 6; i++, random =
Math.floor(Math.random() * max), str += hex[random]);
return "#" + str;
}
})(document, window);
<canvas></canvas>
The issue is, you are initializing color timeout inside update which is being fired every second. So essentially, you are creating a new timeout every millisecond but this value is never been accepted as the moment color is updated, you reset its value to "". Move the code to change background outside and use setInterval instead. So the process of creation of timers and updation of color is separate section and you will not override it in recursion.
Following is a sample
(function(d, w) {
var canvas = d.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var x = 0,
y = 0,
speedX = .9;
update(x, y, speedX);
var color = randomColor();
setInterval(function() { // Here i try set the color each 2s
color = randomColor(); // Need the color here
}, 2000);
function update(x, y, speedX) {
requestAnimationFrame(function() { // animation frame
ctx.fillStyle = color; // here paint the background
ctx.fillRect(0, 0, canvas.width, canvas.height); // paint
x += speedX;
box(x, y, speedX);
update(x, y, speedX);
});
}
function box(x, y, speedX) {
ctx.fillStyle = "Black";
ctx.fillRect(+x, +y, 50, 50);
ctx.stroke();
}
function randomColor() {
for (var i = 0, str = "", hex = "0123456789ABCDEF",
random, max = hex.length; i < 6; i++, random =
Math.floor(Math.random() * max), str += hex[random]);
return "#" + str;
}
})(document, window);
<canvas></canvas>

How to use RequestAnimationFrame correctly?

I made a diffuse animation and used RequestAnimationFrame to achieve it.I tried hundreds of times to improve my program.But it doesn't work!!!Where's my wrong?
function draw_point(x, y){
x += 10.5;
y += 10.5;
radius = 0;
var context = $("#canvas_graph")[0].getContext('2d');
window.webkitRequestAnimationFrame(render(x, y, radius, context));
};
function drawCircle(x, y, radius, context){
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2);
context.closePath();
context.lineWidth = 2;
context.strokeStyle = 'red';
context.stroke();
radius += 0.2;
if (radius > 10) {
radius = 0;
}
};
//The effect of diffusion is achieved by changing the attribute
function render(x ,y, radius, context){
return function step(){
var prev = context.globalCompositeOperation;
context.globalCompositeOperation = 'destination-in';
context.globalAlpha = 0.95;
context.fillRect(0, 0, 890, 890);
context.globalCompositeOperation = prev;
drawCircle(x, y, radius,context);
window.webkitRequestAnimationFrame(step);
};
};
draw_point(100, 100);
But this can be used normally.Function render through the globalAlpha attribute so that the circle is getting lighter.Newly drawn circles are getting bigger.Small rounds are becoming lighter and lighter by using the globalAlpha property again and again.
var context = $("#canvas_graph")[0].getContext('2d');
var radius = 0;
var x = 100;
var y = 100;
function drawCircle(){
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2);
context.closePath();
context.lineWidth = 2;
context.strokeStyle = 'red';
context.stroke();
radius += 0.2;
if (radius > 10) {
radius = 0;
}
};
function render(){
var prev = context.globalCompositeOperation;
context.globalCompositeOperation = 'destination-in';
context.globalAlpha = 0.95;
context.fillRect(0, 0, 890, 890);
context.globalCompositeOperation = prev;
drawCircle();
window.webkitRequestAnimationFrame(render);
};
window.webkitRequestAnimationFrame(render);
In addition,when canvas animation move up, how to restore the background?
Adjust your draw_point function like so. What you have currently is executing the render function right away, you want to pass a reference to requestAnimationFrame, not inserting a function call there
function draw_point(x, y){
x += 10.5;
y += 10.5;
radius = 0;
var context = $("#canvas_graph")[0].getContext('2d');
window.webkitRequestAnimationFrame(function() {
render(x, y, radius, context));
}
};

Categories

Resources