Ball is bouncing from the centre not the edge - javascript

I have coded a ball to bounce around on a canvas, however, the ball only bounces from the centre, not the edge.
I have already tried putting the radius instead of the x and y but that didn't help at all, as of right now I am out of ideas.
I expect the ball to bounce of the edges of itself rather than the centre of it
<!DOCTYPE>
<html>
<head>
<title>Ball Bounce</title>
<style>
canvas {
border-width: 5px;
border-style: ridge;
border-color: #FF0000;
}
</style>
</head>
<body>
<canvas id="testCanvas" width="700" height="400"></canvas>
<script>
var canvas = document.getElementById("testCanvas");
var ctx = canvas.getContext("2d");
var x = 300;
var y = 300;
var radius = 50;
var circleColour = "green";
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var dx = 2;
var dy = -2;
function circle(x, y, r, c) {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI, false);
ctx.fillStyle = c;
ctx.fill()
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
circle(x, y, radius, circleColour)
if (y<0 || y > canvasHeight){
dy = -dy;
}
if (x>canvasWidth || x<0){
dx = -dx;
}
x = x + dx;
y = y + dy;
}
setInterval(draw, 5.5);
</script>
</body>
</html>

I have already tried putting the radius instead of the x and y but that didn't help at all...
You need to combine the radius with x and y (or the canvas edges) to make sure the ball changes direction at all four borders.
if (y - radius < 0 || y + radius > canvasHeight) {
dy = -dy;
}
if (x + radius > canvasWidth || x - radius < 0) {
dx = -dx;
}

Related

check if circle is hovered HTML5 Canvas [duplicate]

I'm new to canvas and I'm trying to listen to mouse clicks on the circles that I previously drew on canvas. I'm trying to change the colour of the circles (maybe to green) when I click on them.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var radius = 15;
for (var i = 0; i < 600; i += 100) {
var x = 100 + i;
var y = 100;
draw_circle(i, x, y, radius);
}
function draw_circle(ID, x, y, radius) {
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 3;
context.strokeStyle = 'black';
context.stroke();
context.closePath();
}
<!DOCTYPE HTML>
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="700" height="700"></canvas>
</body>
</html>
Just add the arc path again and use isPointInPath() with the mouse position. Only one arc can be tested at once, but it's fast to clear and add new paths. Do this in a loop.
Example
var c = document.querySelector("canvas"), ctx = c.getContext("2d");
getArc(50, 50, 40);
ctx.fill();
c.onclick = function(e) {
var rect = this.getBoundingClientRect(), // get abs. position of canvas
x = e.clientX - rect.left, // adjust mouse-position
y = e.clientY - rect.top;
getArc(50, 50, 40); // get path wo/ filling/stroking it
if (ctx.isPointInPath(x, y)) alert("Clicked");
};
function getArc(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2);
ctx.closePath();
}
<canvas></canvas>
The other approach is to use math and trigonometry:
// at this point we have the mouse position, so:
var dx = x - arcX,
dy = y - arcY,
dist = Math.abs(Math.sqrt(dx*dx + dy*dy));
if (dist <= radius) { ...clicked... };
Tip: you can skip squaring the dist by using r2 instead.
With SVG, it would be easy - a circle is an element, and can have a click handler, and has fill that you can manipulate to change colour.
With Canvas, you need to:
save the data for each circle you draw (center and radius)
capture click on canvas as cx, cy
check every circle data x, y, r you have, see whether dx * dx + dy * dy < r * r, where dx = cx - x, dy = cy - y. Circles that satisfy this equation were clicked
repaint the circle
With Canvas, you can use function addEventListener. There are quite a few mouse events you can detect: mousedown, mouseup, mousemove, mouseout and mouseover.
Here is a example:
<!DOCTYPE HTML>
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
<script>
function initialize() {
var canvas = document.getElementById("myCanvas");
canvas.addEventListener("mousedown", doMouseDown, false);
}
function doMouseDown() {
canvas_X = event.pageX;
canvas_Y = event.pageY;
alert("X = " + canvas_X + "Y = " + canvas_Y);
}
</script>
</head>
<body>
<canvas id="myCanvas" width="700" height="700"></canvas>
</body>
</html>

How to add SVG image to javascript html5 canvas animation?

I currently have a rotating bouncing ball within an html5 canvas and I am looking to insert an SVG image inside the ball that moves and rotates with it
I have this code from researching this but unsure if this is correct
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "";
Does anyone have any suggestion on how I might achieve this?
Here is my code
<canvas id="myCanvas"></canvas>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
// SPEED
var dx = 4;
var dy = -4;
var radius = 120;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = "#9370DB";
ctx.fill();
ctx.closePath();
if (x + dx > canvas.width - radius) {
dx = -dx;
}
if (x + dx < radius) {
dx = -dx;
}
if (y + dy > canvas.height - radius) {
dy = -dy;
}
if (y + dy < radius) {
dy = -dy;
}
x += dx;
y += dy;
}
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
x = canvas.width / 2;
y = canvas.height / 2;
setInterval(draw, 10);
var img = new Image();
img.src = ""; // Put the path to you SVG image here.
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
This should work
One way of doing it would be putting the image hidden in the HTML. In this case the image is an svg as data uri and has an id="apple" and you can say:
var img = apple;
To draw the image inside the ball you need to use the center of the ball, for example like this:
ctx.drawImage(img, x-img.width/2,y-img.height/2)
Also instead of using setInterval I'm using requestAnimationFrame and the image is not getting out of the screen on resize. I hope you will find my answer useful.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var rid = null;// request animation id
// SPEED
var dx = 4;
var dy = -4;
var radius = 120;
var img = apple;// the image is the one with the id="apple"
function draw() {
rid = window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = "#9370DB";
ctx.fill();
ctx.closePath();
//draw the image in the center of the ball
ctx.drawImage(img, x-img.width/2,y-img.height/2)
if (x + dx > canvas.width - radius) {
dx = -dx;
}
if (x + dx < radius) {
dx = -dx;
}
if (y + dy > canvas.height - radius) {
dy = -dy;
}
if (y + dy < radius) {
dy = -dy;
}
x += dx;
y += dy;
}
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
//stop the animation
if(rid){window.cancelAnimationFrame(rid); rid= null;}
//get the size of the canvas
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
x = canvas.width / 2;
y = canvas.height / 2;
//restart the animation
draw()
}
window.setTimeout(function() {
resizeCanvas();
window.addEventListener('resize', resizeCanvas, false);
}, 15);
<canvas id="myCanvas">
<img id="apple" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' id='Layer_1' x='0px' y='0px' width='106px' height='122px' viewBox='41 54 106 122'%3E%3Cg%3E%3Cpath fill='%23FFFFFF' stroke='%23ED1D24' stroke-width='2' stroke-miterlimit='10' d='M143.099,93.757c0,0-14.173,8.549-13.724,23.173 c0.449,14.624,11.954,23.413,15.974,24.073c1.569,0.258-9.245,22.049-15.984,27.448c-6.74,5.4-13.714,6.524-24.513,2.25c-10.8-4.275-18.449,0.275-24.749,2.612c-6.299,2.337-13.949-0.137-24.298-14.987c-10.349-14.849-21.823-49.271-6.074-66.146c15.749-16.874,33.298-10.124,38.022-7.875c4.725,2.25,13.05,2.025,22.499-2.25C119.7,77.782,138.374,86.782,143.099,93.757z'/%3E%3C/g%3E%3Cg%3E%3Cpath fill='%23FFFFFF' stroke='%23ED1D24' stroke-width='2' stroke-miterlimit='10' d='M118.575,54.609c0,0,0.9,5.625-1.35,10.349 s-10.718,20.936-22.994,17.999c-0.308-0.073-2.102-5.506,0.532-11.027C98.48,64.138,108.171,55.399,118.575,54.609z'/%3E%3C/g%3E%3C/svg%3E" />
</canvas>
Please run the code on full page.

how do i rotate a rectangle to point towards mouse

I need help rotating a rectangle to point towards the mouse on the screen every time the mouse moves. ive been trying to do so using the onmousemove event and calculating degrees/angle, then converting to radians, but for some reason when i place the radians variable rad inside rotate();, the rectangle does not rotate at all.
<!DOCTYPE html>
<html>
<head>
<title>Rotate Rectangle Project</title>
<style>
canvas {
background:#f05424; display: block; margin: 0 auto;
}
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width=500 height=500 top=10px></canvas>
<p id='coord'>0</p>
<p id='degree'>0</p>
<p id='radian'>0</p>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var x = 100;
var y = 100;
var w = 100;
var h = 30;
var rX, rY, mX, mY, degrees, rad, coords;
document.onmousemove = function(e){
rX =533;
rY =100;
mX = e.clientX;
mY = e.clientY;
coords = mX + ',' + mY;
degrees = mY - rY + mX - rX;
rad = Math.atan2(mY - rY, mX - rX)* Math.PI/180;
draw();
document.getElementById('coord').innerHTML = coords;
document.getElementById('degree').innerHTML = degrees;
document.getElementById('radian').innerHTML = rad;
};
function rectangle(){
ctx.beginPath();
ctx.translate(x, y);
ctx.rotate(rad);
ctx.translate(-x, -y);
ctx.rect(x, y, w, h);
ctx.fillStyle = '#f8c778';
ctx.fill();
ctx.closePath();
}
function draw(){
ctx.clearRect(x,y,canvas.width,canvas.height);
rectangle();
}
</script>
</body>
</html>
I have edited your code, basically you need to call rectangle on onmousemove and clear the canvas.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var x = 100;
var y = 100;
var w = 100;
var h = 30;
var mouseX, mouseY, degrees, rad, coords;
document.onmousemove = function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
coords = mouseX + ',' + mouseY;
degrees = mouseY - y + mouseX - x;
rad = Math.atan2(mouseY - y, mouseX - x) * (180 / Math.PI);
rectangle();
};
function rectangle() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.translate(x, y);
ctx.rotate(rad);
ctx.translate(-x, -y);
ctx.rect(x, y, w, h);
ctx.fillStyle = '#f8c778';
ctx.fill();
ctx.closePath();
}
body {
margin: 0px;
padding: 0px;
}
canvas {
background: #f05424;
display: block;
margin: 0 auto;
}
<canvas id="myCanvas" width=500 height=500></canvas>

Animating shapes in javascript

So I'm trying to have shapes animate across the canvas and then bounce back after hitting the edge, and I'm unclear why my other two shapes do not have velocity like my ball does. I'll post the code below.
<html>
<body>
<section>
<div>
<canvas id="canvas" width="700" height="300"></canvas>
</div>
<script type="text/javascript">
var canvas,
context,
x = Math.floor((Math.random() * 400) + 1), //Ball x coordinate
y = Math.floor((Math.random() * 300) + 1), //Ball y coordinate
dx = Math.floor((Math.random() * 10) + 1), //X velocity
dy = Math.floor((Math.random() * 4) + 1), //Y velocity
width = 700, //Width of the background
height = 300; //Height of the background
function drawCircle(x,y,r) { //Draws the ball
context.beginPath();
context.arc(x, y, r, 0, Math.PI*2, true);
context.fill();
}
function drawRect(x,y,w,h) { //Draws the background
context.beginPath();
context.rect(x,y,w,h);
context.closePath();
context.fill();
}
function start() { //Runs when the window loads. Stores canvas and context in variables. Runs "draw" on an interval of 10ms
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
return setInterval(draw, 10);
}
function drawSquare(){
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.fillStyle = "white";
ctx.beginPath();
ctx.moveTo(200,50);
ctx.lineTo(250,50);
ctx.lineTo(300, 100);
ctx.lineTo(250,25);
ctx.fill();
}
}
function drawTri(){
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(75,25);
ctx.fill();
}
}
function draw() {
context.clearRect(0, 0, width, height); //Clears the drawing space
context.fillStyle = "black"; //Sets fillstyle to black (for the background)
drawRect(0,0, width, height); //Draws the background
context.fillStyle = "white"; //Sets fillstyle to white (for the ball)
drawCircle(x, y, 10);
drawTri();
drawSquare(); //Calls function to draw the ball
if (x + dx > width || x + dx < 0) //If the ball would leave the width (right or left) on the next redraw...
dx = -dx; //reverse the ball's velocity
if (y + dy > height || y + dy < 0) //If the ball would leave the height (top or bottom) on the next redraw...
dy = -dy; //reverse the ball's velocity
x += dx; //Increase ball x speed by velocity
y += dy; //Increase ball y speed by velocity
}
window.onload = start; //Run "start" function after the window loads
</script>
</section>
</body>
</html>
you forgot to do the drawing with the variables. And the variables are the same (as in the 2 shapes will always be together) because if x is 150 for the circle, the rect will be behind it. So, you need more variables to keep track of it like this: circ1x,circ1y,circ2x,circ2y,rect1x,rect1y,rect2x,rect2y
Your ball is being drawn using variable coordinates (x & y)
context.arc(x, y, r, 0, Math.PI*2, true);
Your shapes are being drawn using hardcoded, constant values:
ctx.moveTo(200,50);
ctx.lineTo(250,50);
ctx.lineTo(300, 100);
ctx.lineTo(250,25);
&
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(75,25);
To animate them, use variables to draw the other shapes, and update those variables. eg.
var x = 75,
y = 50;
ctx.moveTo(x,y);
ctx.lineTo(x + 25, y + 25);
ctx.lineTo(x, y - 25);

Detect mouse clicks on circles on HTML5 canvas

I'm new to canvas and I'm trying to listen to mouse clicks on the circles that I previously drew on canvas. I'm trying to change the colour of the circles (maybe to green) when I click on them.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var radius = 15;
for (var i = 0; i < 600; i += 100) {
var x = 100 + i;
var y = 100;
draw_circle(i, x, y, radius);
}
function draw_circle(ID, x, y, radius) {
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 3;
context.strokeStyle = 'black';
context.stroke();
context.closePath();
}
<!DOCTYPE HTML>
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="700" height="700"></canvas>
</body>
</html>
Just add the arc path again and use isPointInPath() with the mouse position. Only one arc can be tested at once, but it's fast to clear and add new paths. Do this in a loop.
Example
var c = document.querySelector("canvas"), ctx = c.getContext("2d");
getArc(50, 50, 40);
ctx.fill();
c.onclick = function(e) {
var rect = this.getBoundingClientRect(), // get abs. position of canvas
x = e.clientX - rect.left, // adjust mouse-position
y = e.clientY - rect.top;
getArc(50, 50, 40); // get path wo/ filling/stroking it
if (ctx.isPointInPath(x, y)) alert("Clicked");
};
function getArc(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2);
ctx.closePath();
}
<canvas></canvas>
The other approach is to use math and trigonometry:
// at this point we have the mouse position, so:
var dx = x - arcX,
dy = y - arcY,
dist = Math.abs(Math.sqrt(dx*dx + dy*dy));
if (dist <= radius) { ...clicked... };
Tip: you can skip squaring the dist by using r2 instead.
With SVG, it would be easy - a circle is an element, and can have a click handler, and has fill that you can manipulate to change colour.
With Canvas, you need to:
save the data for each circle you draw (center and radius)
capture click on canvas as cx, cy
check every circle data x, y, r you have, see whether dx * dx + dy * dy < r * r, where dx = cx - x, dy = cy - y. Circles that satisfy this equation were clicked
repaint the circle
With Canvas, you can use function addEventListener. There are quite a few mouse events you can detect: mousedown, mouseup, mousemove, mouseout and mouseover.
Here is a example:
<!DOCTYPE HTML>
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
<script>
function initialize() {
var canvas = document.getElementById("myCanvas");
canvas.addEventListener("mousedown", doMouseDown, false);
}
function doMouseDown() {
canvas_X = event.pageX;
canvas_Y = event.pageY;
alert("X = " + canvas_X + "Y = " + canvas_Y);
}
</script>
</head>
<body>
<canvas id="myCanvas" width="700" height="700"></canvas>
</body>
</html>

Categories

Resources