Reputation: 43
I am working on a fun intro project to HTML Canvas. The basic concept is that some shapes in this case circles move around and bounce off the sides. The two problems I would like help with are:
After resizing the browser the circles may get stuck at the end of the screen on the open sides(bottom and right) where they are bounded by widthCanvas and heightCanvas. Ideally, I would the circles to behave the same way as they do on the sides(left and top) where they are bounded by 0. (See the if statements in the animate() function)
How to remove the white space around the canvas left due to the use of:
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html,
body {
overflow: hidden;
}
</style>
</head>
<body onresize="resizeCanvas()">
<div>
<canvas id="canvas"></canvas>
</div>
<script>
const canvas = document.getElementById('canvas');
/** @type {CanvasRenderingContext2D} */
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
widthCanvas = canvas.width;
heightCanvas = canvas.height;
draw(40);
function draw(num) {
//number of cycles
num_cycles = num;
// speed bounds
min_speed = 4;
// real max_speed is + min_speed
max_speed = 3;
// create arrays for changing values
const arr_x = new Array(num_cycles);
const arr_y = new Array(num_cycles);
const arr_dx = new Array(num_cycles);
const arr_dy = new Array(num_cycles);
const arr_r = new Array(num_cycles);
// populate arrays with random vaalues in range so circles
// have different velocities on y and x as well as vary in radii
for (let index = 0; index < num_cycles; index++) {
arr_x[index] = ((widthCanvas * 0.2) * Math.random()) + (widthCanvas * 0.4);
arr_y[index] = ((heightCanvas * 0.2) * Math.random()) + (heightCanvas * 0.4);
arr_dx[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? -1 : 1);
arr_dy[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? 1 : -1);
arr_r[index] = 50 + Math.random() * widthCanvas / 12;
}
let arr_color = ["rgba(47, 133, 209, 0.6)", "rgba(244, 67, 54, 0.6)", "rgba(71, 50, 123, 0.6)", "rgba(241, 194, 50, 0.6)", "rgba(56, 118, 29, 0.6)"];
function animate() {
//clear the canvas so that new drawings are on a blank canvas
ctx.clearRect(0, 0, widthCanvas, heightCanvas)
ctx.fillStyle = "rgba(224, 31, 92, 1)";
ctx.fillRect(0, 0, widthCanvas, heightCanvas)
// Draw shapes aand animations
for (var i = 0; i <= widthCanvas; i += widthCanvas / 120) {
addLinesPath(i, i, 0, heightCanvas, "rgba(31, 118, 224, 0.5)");
}
for (let index = 0; index < num_cycles; index++) {
draw_circle(arr_x[index], arr_y[index], arr_r[index], arr_color[index % arr_color.length])
if (arr_x[index] + arr_r[index] > widthCanvas || arr_x[index] - arr_r[index] < 0)
arr_dx[index] = -arr_dx[index];
if (arr_y[index] + arr_r[index] > heightCanvas || arr_y[index] - arr_r[index] < 0)
arr_dy[index] = -arr_dy[index];
arr_x[index] += arr_dx[index];
arr_y[index] += arr_dy[index];
}
requestAnimationFrame(animate);
}
animate()
}
// resize
function resizeCanvas() {
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
widthCanvas = canvas.width;
heightCanvas = canvas.height;
}
function get_width() {
return canvas.width;
}
function get_height() {
return canvas.height;
}
// draw line
function addLinesPath(y_start, y_end, x_start, x_end, color) {
ctx.strokeStyle = color;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(y_start, x_start);
ctx.lineTo(y_end, x_end);
ctx.stroke();
}
// draw circle
function draw_circle(x, y, r, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
}
</script>
</body>
</html>
Upvotes: 1
Views: 70
Reputation: 18428
After resizing the browser the circles may get stuck...
Consider following simplified code from your snippet:
if (arr_x[index] + arr_r[index] > widthCanvas)
arr_dx[index] = -arr_dx[index];
Here, when the circle goes out of right border due to resizing, the if
statement evaluates to true all the time. Because you are switching direction every frame! 😬
Make sure you switch the direction only once after the circle goes out of the canvas.
How to remove the white space around the canvas left...
By default <body>
has some margin. In Chrome 8px. Need to check other browser. Get rid of those margins and paddings if any on all the involved elements. Or adjust the canvas width in code accordingly.
Demo:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html,
body {
overflow: hidden;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
</head>
<body onresize="resizeCanvas()">
<div>
<canvas id="canvas"></canvas>
</div>
<script>
const canvas = document.getElementById('canvas');
/** @type {CanvasRenderingContext2D} */
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
widthCanvas = canvas.width;
heightCanvas = canvas.height;
draw(10);
function draw(num) {
//number of cycles
num_cycles = num;
// speed bounds
min_speed = 2;
// real max_speed is + min_speed
max_speed = 2;
// create arrays for changing values
const arr_x = new Array(num_cycles);
const arr_y = new Array(num_cycles);
const arr_dx = new Array(num_cycles);
const arr_dy = new Array(num_cycles);
const arr_r = new Array(num_cycles);
// populate arrays with random vaalues in range so circles
// have different velocities on y and x as well as vary in radii
for (let index = 0; index < num_cycles; index++) {
arr_x[index] = ((widthCanvas * 0.2) * Math.random()) + (widthCanvas * 0.4);
arr_y[index] = ((heightCanvas * 0.2) * Math.random()) + (heightCanvas * 0.4);
arr_dx[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? -1 : 1);
arr_dy[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? 1 : -1);
arr_r[index] = 50 + Math.random() * widthCanvas / 12;
}
let arr_color = ["rgba(47, 133, 209, 0.6)", "rgba(244, 67, 54, 0.6)", "rgba(71, 50, 123, 0.6)", "rgba(241, 194, 50, 0.6)", "rgba(56, 118, 29, 0.6)"];
function animate() {
//clear the canvas so that new drawings are on a blank canvas
ctx.clearRect(0, 0, widthCanvas, heightCanvas)
ctx.fillStyle = "rgba(224, 31, 92, 1)";
ctx.fillRect(0, 0, widthCanvas, heightCanvas)
// Draw shapes and animations
for (var i = 0; i <= widthCanvas; i += widthCanvas / 120) {
addLinesPath(i, i, 0, heightCanvas, "rgba(31, 118, 224, 0.5)");
}
for (let index = 0; index < num_cycles; index++) {
draw_circle(arr_x[index], arr_y[index], arr_r[index], arr_color[index % arr_color.length])
if (arr_x[index] + arr_r[index] > widthCanvas && arr_dx[index] > 0)
arr_dx[index] *= -1;
else if (arr_x[index] - arr_r[index] < 0 && arr_dx[index] < 0)
arr_dx[index] *= -1;
if (arr_y[index] + arr_r[index] > heightCanvas && arr_dy[index] > 0)
arr_dy[index] *= -1;
else if (arr_y[index] - arr_r[index] < 0 && arr_dy[index] < 0)
arr_dy[index] *= -1;
arr_x[index] += arr_dx[index];
arr_y[index] += arr_dy[index];
}
requestAnimationFrame(animate);
}
animate()
}
// resize
function resizeCanvas() {
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
widthCanvas = canvas.width;
heightCanvas = canvas.height;
console.log(widthCanvas, '=', heightCanvas);
}
function get_width() {
return canvas.width;
}
function get_height() {
return canvas.height;
}
// draw line
function addLinesPath(y_start, y_end, x_start, x_end, color) {
ctx.strokeStyle = color;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(y_start, x_start);
ctx.lineTo(y_end, x_end);
ctx.stroke();
}
// draw circle
function draw_circle(x, y, r, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
}
</script>
</body>
</html>
Here, to avoid complex code I've separated the if statements.
With simple debugging we can easily figure out such pesky bugs. This guide may help: https://developer.chrome.com/docs/devtools/javascript/
Upvotes: 1