why is my clientwidth/100 different than my width by percent? - javascript

I have a small program that when you press down on ArrowDown, the circle should move downwards from its position on screen. The issue I have is that my initial positioning for my svg circle object set by cx: 5% and cy:5% are different than my 5 * xshift and 5 * yshift which are derived from document.getElementById("test").clientWidth/100 and document.getElementById("test").clientHeight/100 which I would believe to be a good conversion to percentage. However when the program is run, the initial ArrowDown corrects the initial placement and creates a noticable shifted difference.
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");
}
}, true);
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Snake Game</title>
<style>
html, body {
margin: 0;
padding: 0;
border: 0;
height: 100%
}
svg {
position: absolute;
margin: 0;
padding: 0;
border: 0;
background-color: blueviolet;
}
</style>
</head>
<body>
<!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
<svg id="test" width="100%" height="100%">
<circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
</svg>
<script src="test.js"></script>
</body>
</html>

You can check complete code from: this fiddle, I combined your pieces of code and added a single line.
`
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
doShift();
}
}, true);
function doShift(){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");
}
//document.addEventListener("onready", ()=> doShift());
//document.ondomcontentready=doShift;
doShift();
`;
Although it looks like a hack, the final doShift(); call creates the same effect as when you first press the down button - you specify what you want.

They are different because you are using a transform. The transform is being applied on top of (in addition to) the cx and cy coordinates.
In other words, the circle is being positioned at:
x = cx + translate.x = 5% + 5%
y = cy + (n * translate.y) = 5% + (n * 5%)
One way to fix this is to forget the transform attribute and just update the cx and cy attributes instead. Eg.
document.getElementById('circe').setAttribute("cy", player.y);
Demo
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("cy", player.y);
}
}, true);
html, body {
margin: 0;
padding: 0;
border: 0;
height: 100%;
}
svg {
position: absolute;
margin: 0;
padding: 0;
border: 0;
background-color: blueviolet;
}
<!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
<svg id="test" width="100%" height="100%">
<circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
</svg>

Related

Zoom Into the Area Cursor Points

Refering to codepen demo here, I created this zoom in and zoom out function which works fine.
May I ask the code to zoom in and out of the area which my cursor points using the mouse scroll?
For example, if my cursor is moved to the green area in my picture and when I scoll the mouse, it will zoom into and out of the specific area? Any help will be very much appreicated :)
<div onclick="zoomin()" style="display: block;float: left;border: 1px solid;cursor: pointer">
ZoomIn
</div>
<div onclick="zoomout()" style="display: block;float: left;border: 1px solid;cursor: pointer;margin-left: 10px">
ZoomOut
</div>
var svg=document.getElementById('mainsvg');
var gnode=document.getElementById('gnode');
var zoomPercentage=0.25;
var MAXIMUM_ZOOM_HEIGHT = 1400;
var baseBox={};
var level=0;
var widthRatio,heightRatio;
var clientheight = document.documentElement.clientHeight;
var clientwidth = document.documentElement.clientWidth;
function setup(){
var
baseX,
baseY,
baseWidth,
baseHeight,
percentageDifference,
heightDifference;
svg.setAttribute('height', clientheight);
svg.setAttribute('width', clientwidth);
var boundry=document.getElementById('boundry');
boundry.setAttribute('height', clientheight-1);
boundry.setAttribute('width', clientwidth-1);
var centernode=document.getElementById('centernode');
centernode.setAttribute('cy', clientheight/2);
centernode.setAttribute('cx', clientwidth/2);
if (svg.height.baseVal.value >= MAXIMUM_ZOOM_HEIGHT)
baseHeight = MAXIMUM_ZOOM_HEIGHT;
else
baseHeight = Math.round(gnode.getBBox().height) + 60;
baseY = (svg.height.baseVal.value - baseHeight) / 2;
percentageDifference = baseHeight / svg.height.baseVal.value;
baseWidth = percentageDifference * svg.width.baseVal.value;
baseX = (svg.width.baseVal.value - baseWidth) / 2;
baseBox.x = baseX;
baseBox.y = baseY;
baseBox.width = baseWidth;
baseBox.height = baseHeight;
level = 0;
heightDifference = MAXIMUM_ZOOM_HEIGHT - baseHeight;
zoomPercentage = (heightDifference / 10) / heightDifference;
setViewBox(baseBox);
}
function setViewBox(viewBox) {
svg.viewBox.baseVal.x = Math.round(viewBox.x);
svg.viewBox.baseVal.y = Math.round(viewBox.y);
svg.viewBox.baseVal.width = Math.round(viewBox.width);
svg.viewBox.baseVal.height = Math.round(viewBox.height);
setRatios();
}
function setRatios () {
widthRatio = svg.viewBox.baseVal.width / svg.width.baseVal.value;
heightRatio = svg.viewBox.baseVal.height / svg.height.baseVal.value;
}
function calculateViewBox(level) {
var
height = baseBox.height - (zoomPercentage * level * baseBox.height),
y = baseBox.y + (baseBox.height - height) / 2,
width = baseBox.width - (zoomPercentage * level * baseBox.width),
x = baseBox.x + (baseBox.width - width) / 2,
viewBox = {
x: x,
y: y,
width: width,
height: height
}
return viewBox;
}
function zoomin(){
level++;
if(level>5)
level=5;
var
x,
y,
paperViewBox = svg.viewBox.baseVal,
previousViewBox = calculateViewBox(level - 1),
newViewBox = calculateViewBox(level);
//callback = this.afterZoom;
if (Math.round(paperViewBox.x) > Math.round(newViewBox.x))
/**
* is panned left
*/
x = paperViewBox.x - (previousViewBox.width - newViewBox.width) / 2;
else if (Math.round(paperViewBox.x) < Math.round(previousViewBox.x) - (Math.round(newViewBox.x) - Math.round(previousViewBox.x)))
/**
* is panned right
*/
x = paperViewBox.x + (previousViewBox.width - newViewBox.width) + (previousViewBox.width - newViewBox.width) / 2;
else
x = newViewBox.x;
if (Math.round(paperViewBox.y) > Math.round(newViewBox.y))
/**
* is panned up
*/
y = paperViewBox.y - (previousViewBox.height - newViewBox.height) / 2;
else if (Math.round(paperViewBox.y) < Math.round(previousViewBox.y) - (Math.round(newViewBox.y) - Math.round(previousViewBox.y)))
/**
* is panned down
*/
y = paperViewBox.y + (previousViewBox.height - newViewBox.height) + (previousViewBox.height - newViewBox.height) / 2;
else
y = newViewBox.y;
var data = {
viewBox: {
x: x,
y: y,
width: newViewBox.width,
height: newViewBox.height
}
}
SetZoomViewBox(data);
}
function SetZoomViewBox(data){
var viewBox = data.viewBox;
svg.viewBox.baseVal.x = Math.round(viewBox.x);
svg.viewBox.baseVal.y = Math.round(viewBox.y);
svg.viewBox.baseVal.width = Math.round(viewBox.width);
svg.viewBox.baseVal.height = Math.round(viewBox.height);
setRatios();
}
function zoomout(){
level--;
if(level<0)
level=0;
var
x,
y,
paperViewBox = svg.viewBox.baseVal,
previousViewBox = calculateViewBox(level + 1),
newViewBox = calculateViewBox(level);
if (Math.round(paperViewBox.x) > Math.round(previousViewBox.x) + (Math.round(previousViewBox.x) - Math.round(newViewBox.x)))
/**
* is panned left
*/
x = paperViewBox.x - (newViewBox.width - previousViewBox.width);
else if (Math.round(paperViewBox.x) < Math.round(previousViewBox.x))
/**
* is panned right
*/
x = paperViewBox.x;
else
x = newViewBox.x;
if (Math.round(paperViewBox.y) > Math.round(previousViewBox.y) + (Math.round(previousViewBox.y) - Math.round(newViewBox.y)))
/**
* is panned up
*/
y = paperViewBox.y - (newViewBox.height - previousViewBox.height);
else if (Math.round(paperViewBox.y) < Math.round(previousViewBox.y))
/**
* is panned down
*/
y = paperViewBox.y;
else
y = newViewBox.y;
var data = {
viewBox: {
x: x,
y: y,
width: newViewBox.width,
height: newViewBox.height
}
}
SetZoomViewBox(data);
}
setup();
<div onclick="zoomin()" style="display: block;float: left;border: 1px solid;cursor: pointer">
ZoomIn
</div>
<div onclick="zoomout()" style="display: block;float: left;border: 1px solid;cursor: pointer;margin-left: 10px">
ZoomOut
</div>
<svg id="mainsvg" width="600px" height="500px" viewBox="0 0 600 500">
<g id="gnode">
<rect id="boundry" x="0" y="0" width="599" height="499" fill="none" stroke='black'/>
<circle id="centernode" cx="300" cy="250" r="5" fill="red" stroke="none" />
<rect id="selected" x="450" y="100" width="50" height="50" fill="blue" stroke='none'/>
</g>
</svg>
You can add the following code to handle zoom in and zoom out based on mouse wheel event:
svg.addEventListener("wheel", function(event) {
if (event.deltaY < 0) {
zoomin();
} else if (event.deltaY > 0) {
zoomout();
}
});
Place this code after the setup function. It will handle the zoom in and zoom out events when the mouse wheel is scrolled over the svg element.

Colliding two circles without using canvas

I have created three circles and made it bounce off the wall without using HTML canvas. Now I want two circles to collide with each other and move those circles in the opposite direction. I tried to detect the collision by checking it's position but it doesn't work. I don't know where I went wrong.
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Bounce Ball</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.circle{
height: 50px;
width: 50px;
position: absolute;
border-radius: 50%;
}
.container {
height: 300px;
width: 300px;
background-color: skyblue;
position: relative;
}
</style>
</head>
<body>
<div class ="container" id ="container">
<div class="circle" id = "circle1" style="background-color:black;
height: 50px; width: 50px;top:0; left:0"></div>
<div class="circle" id ="circle2" style="background-color:rgb(197, 100,
100);height: 50px; width: 50px;top:200px;left: 150px"></div>
<div class="circle" id ="circle3" style="background-color:brown;height:
50px;width: 50px;top:50px;left: 640px"></div>
</div>
<script>
var container = document.getElementById("container");
container.style.width="700px";
container.style.height = "300px";
var balls = document.getElementsByClassName("circle");
for(var i=0; i <balls.length; i++){
var speed={x:3,y:-3}
setInterval(draw, 50 , balls[i], speed);
}
function draw(ball, speed) {
if(parseInt(ball.style.left) > (parseInt(container.style.width)-
parseInt(ball.style.width)) || (parseInt(ball.style.left) <0) ){
speed.x = -speed.x;
}
ball.style.left = parseInt(ball.style.left) + speed.x + 'px';
if(parseInt(ball.style.top) > (parseInt(container.style.height)-
parseInt(ball.style.height)) || (parseInt(ball.style.top) <0)){
speed.y = -speed.y;
}
ball.style.top = parseInt(ball.style.top) + speed.y + 'px';
//for colliding two circles
for(var i =0 ; i <= balls.length-1; i++){
for(var j = i + 1; j < balls.length; j++){
if(parseInt(balls[i].style.left) +
parseInt(balls[i].style.width) ==
parseInt(balls[j].style.left) ||
parseInt(balls[j].style.left) +
parseInt(balls[j].style.width) ==
parseInt(balls[i].style.left) &&
parseInt(balls[i].style.top) +
parseInt(balls[i].style.height) ==
parseInt(balls[j].style.top) || parseInt(balls[j].style.top)
+ parseInt(balls[j].style.height) ==
parseInt(balls[i].style.top)) {
speed.x = - speed.x;
speed.y = -speed.y;
}
ball[i].style.left = parseInt(ball[i].style.left) +
speed.x + 'px';
ball[j].style.left = parseInt(ball[j].style.left) +
speed.x + 'px';
ball[i].style.top = parseInt(ball[i].style.top) +
speed.y + 'px';
ball[j].style.top = parseInt(ball[j].style.top) +
speed.y + 'px';
}
}
}
</script>
</body>
</html>
I would recommend moving as much as possible into javascript variables so you don't need to consult the HTML for every parameter.
You had quite the number of typos, among them speed.x = - speed.x; where you meant speed.x = -speed.x; and your code was difficult to read without any comments or helper functions to explain what's going on.
I have fixed your typos and restructured your code in the snippet below. Try checking the developer console, typically by pressing F12, as this will show you code errors with line number and severity rating.
In my snippet below i have tried to move the parameters into JavaScript to show how that would work, while still leaving some on the HTML nodes:
//Basic properties
var width = 700;
var height = 300;
//Get container
var container = document.getElementById("container");
// Set dimensions
container.style.width = width + "px";
container.style.height = height + "px";
//Load balls
var balls = Array.prototype.slice.call(document.getElementsByClassName("circle"))
.map(function(ball) {
return {
HTMLNode: ball,
xPos: parseInt(ball.style.left),
yPos: parseInt(ball.style.top),
xAcc: 3,
yAcc: -3,
size: 50
};
});
//Utility functions
function angleBetween(x1, y1, x2, y2) {
return Math.atan2(y2 - y1, x2 - x1);
}
function distanceBetween(x1, y1, x2, y2) {
return Math.abs(y2 - y1) + Math.abs(x2 - x1);
}
//Draw function
function draw() {
//Loop through balls
for (var ballIndex1 = 0; ballIndex1 < balls.length; ballIndex1++) {
var ball1 = balls[ballIndex1];
//Collide with horisontal wall
if (ball1.xPos > width - ball1.size || ball1.xPos < 0) {
ball1.xAcc = -ball1.xAcc;
}
//Collide with vertical wall
if (ball1.yPos > height - ball1.size || ball1.yPos < 0) {
ball1.yAcc = -ball1.yAcc;
}
//Collide with other balls
for (var ballIndex2 = ballIndex1 + 1; ballIndex2 < balls.length; ballIndex2++) {
var ball2 = balls[ballIndex2];
//Test within collision distance
if (distanceBetween(ball1.xPos, ball1.yPos, ball2.xPos, ball2.yPos) > ball1.size) {
continue;
}
//Get angle of collision
var angle = angleBetween(ball1.xPos, ball1.yPos, ball2.xPos, ball2.yPos);
//Apply force to acceleration
ball1.xAcc = -Math.cos(angle) * 3;
ball2.xAcc = -ball1.xAcc;
ball1.yAcc = -Math.sin(angle) * 3;
ball2.yAcc = -ball1.yAcc;
}
//Apply acceleration to position
ball1.yPos += ball1.yAcc;
ball1.xPos += ball1.xAcc;
//Apply to node
ball1.HTMLNode.style.left = ball1.xPos + "px";
ball1.HTMLNode.style.top = ball1.yPos + "px";
}
}
//Start simulation
setInterval(draw, 1000 / 60);
.circle {
position: absolute;
border-radius: 50%;
height: 50px;
width: 50px;
}
.container {
height: 300px;
width: 300px;
background-color: skyblue;
position: relative;
}
<div class="container" id="container">
<div class="circle" id="circle1" style="background-color:black;
top:0; left:0"></div>
<div class="circle" id="circle2" style="background-color:rgb(197, 100,
100);top:200px;left: 150px"></div>
<div class="circle" id="circle3" style="background-color:brown;top:50px;left: 640px"></div>
</div>

Working with .clientX example in JS any idea why you can not check a given argument?

<!DOCTYPE html>
<html>
<head>
<style>
div {
width: 100vw;
height: 100vh;
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<p>Click in the div element below to get the x (horizontal) and y (vertical) coordinates of the mouse pointer, when it is clicked.</p>
<div onmousemove="showCoords(event)"><p id="demo"></p></div>
<p><strong>Tip:</strong> Try to click different places in the div.</p>
<script>
function showCoords(event) {
var cX = event.clientX;
var sX = event.screenX;
var cY = event.clientY;
var sY = event.screenY;
var coords1 = "client - X: " + cX + ", Y coords: " + cY;
var coords2 = "screen - X: " + sX + ", Y coords: " + sY;
document.getElementById("demo").innerHTML = coords1 + "<br>" + coords2;
console.log(cX * 0.5);
if(cX < 0.5 * cX){
document.getElementById("demo").style.color = "red";
}
/*else if(cX > cX * 0.5 ){
document.getElementById("demo").style.color = "yellow";
}*/
else{
document.getElementById("demo").style.color = "black";
}
}
</script>
</body>
</html>
Hello, I have attached the given example I have been working on via W3schools. I can log cX to the screen dividing it by two. However when I then try to use it in an argument it will not work. Has anyone else came across a similar issue or have I made a fatal error in markup? Please let me know. If I find solution will be sure to post here. Thank you.
if(cX < 0.5 * cX){
This is always false, you probably meant cX < 0.5 * document.body.clientWidth.

overlapping absolutely positioned divs

I'm working on a little html5 game where the user has to click on a specified circle. I want the circles to change position every second randomly. I was able to make this. My only problem with it is that the circles often overlap one another. Is there any way I can prevent this? I've tried using margins, but that won't work because the circles have a position of absolute.
Here's the code for it:
//circles for game
var circle1 = document.getElementById('circle1');
var circle2 = document.getElementById('circle2');
var circle3 = document.getElementById('circle3');
//viewport height and width
var vh = 100;
var vw = 100;
//when the document loads, the circles change their position on screen
function changePosition() {
//Intercval that runs every second
setInterval ( function() {
//generates random numbers and assings them to the top and
//left properties of the circles
var circle1Top = Math.floor(Math.random() * vh ) + 1;
var circle2Top = Math.floor(Math.random() * vh ) + 1;
var circle3Top = Math.floor(Math.random() * vh ) + 1;
var circle1Left = Math.floor(Math.random() * vw) + 1;
var circle2Left = Math.floor(Math.random() * vw) + 1;
var circle3Left = Math.floor(Math.random() * vw) + 1;
//if the random number is greater than or equal to the device size, another number is generated
//this prevents the circles from appearing off screen
//circle1
while (circle1Top >= vh - 16 || circle1Top > vh) {
circle1Top = Math.floor(Math.random() * vh ) + 1;
};
while (circle1Left >= vw - 15 || circle1Top > vw) {
circle1Left = Math.floor(Math.random() * vw ) + 1;
};
//circle2
while (circle2Top >= vh - 16 || circle2Top > vh) {
circle2Top = Math.floor(Math.random() * vh ) + 1;
};
while (circle2Left >= vw - 15 || circle2Top > vw) {
circle2Left = Math.floor(Math.random() * vw ) + 1;
};
//circle3
while (circle3Top >= vh - 16 || circle3Top > vh) {
circle3Top = Math.floor(Math.random() * vh ) + 1;
};
while (circle3Left >= vw - 15 || circle3Top > vw) {
circle3Left = Math.floor(Math.random() * vw ) + 1;
};
//once the numbers are generated, they are assigned to the circles accordingly
circle1.style.top = circle1Top + 'vh';
circle1.style.left = circle1Left + 'vw';
circle2.style.top = circle2Top + 'vh';
circle2.style.left = circle2Left + 'vw';
circle3.style.top = circle3Top + 'vh';
circle3.style.left = circle3Left + 'vw';
}, 1000);
};
body {
background-color: aliceblue;
height: 100vh;
width: 100vw;
margin: 0;
overflow: hidden;
}
main {
width: 100%;
height: 100%;
margin: 0;
}
.circle {
width: 110px;
height: 110px;
background-color: blue;
border-radius: 50%;
position: absolute;
}
#circle1 {
background-color: red;
}
#circle2 {
background-color: blue;
}
#circle3 {
background-color: yellow;
}
/*media queries*/
#media only screen and (max-width: 435px) {
.circle {
width: 70px;
height:70px;
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link type="text/css" rel="stylesheet" href="test.css">
</head>
<body onload="changePosition()">
<main>
<div class="circle" id="circle1"></div>
<div class="circle" id="circle2"></div>
<div class="circle" id="circle3"></div>
</main>
<!-- Scripts -->
<script type="text/javascript" src="test.js"></script>
</body>
</html>
Any responses are greatly appreciated.
You have to check if the circles overlap and if they do, reload the script. To check if they overlap you have to do some math:
1) Find out what the center of the circle is:
var circle1centerX = circle1Left * document.documentElement.clientHeight * 0.65 + 55;
var circle1centerY = circle1Top * document.documentElement.clientHeight * 0.65 + 55;
document.documentElement.clientHeight * 0.65 is the factor you need to multiply with to convert vh or vw to px. 55 is half the radius of the circles.
2) Check if circles overlap:
If the circles overlap, then the distance between their centers must be lower than two times the radius. If the distance between the centers is equal to or larger than two times the radius, they don't overlap. (In your case 2 times the radius is 110px)
var distanceBetween1and2 = Math.sqrt(Math.pow(circle2centerX - circle1centerX, 2) + Math.pow(circle2centerY - circle1centerY));
var distanceBetween1and3 = Math.sqrt(Math.pow(circle3centerX - circle1centerX, 2) + Math.pow(circle3centerY - circle1centerY));
var distanceBetween2and3 = Math.sqrt(Math.pow(circle3centerX - circle2centerX, 2) + Math.pow(circle3centerY - circle2centerY));
(Pythagorean theorem)
if(distanceBetween1and2 < 2*radius || distanceBetween2and3 < 2*radius || distanceBetween1and3 < 2*radius) {
changePosition();
} else {
//place the circles
}
But there is one disadvantage of this method, when the area in which the circles are, is small enough, so there must be circles overlapping, there will be an infinite loop. You can prevent this by setting a minimum size on the screen in which the circles are placed.

Why doesn't my canvas animation show?

I have been working on a canvas animation of a circle that moves in a random direction, and every second the direction changes. I do that by changing a velocity vector every second by repeatedly calling a function using setInterval, while changing the position of the circle's center and drawing it in another function using requestAnimationFrame. The result is an empty canvas, and I'm not sure why. The code is split into the following three files:
random_ball.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Random Ball</title>
<link rel="stylesheet" href="random_ball.css">
</head>
<body>
<canvas id="canvas"></canvas>
<script src="random_ball.js"></script>
</body>
</html>
random_ball.css
html, body{
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
margin: 0;
padding: 0;
}
canvas{
position: absolute;
width: 50vw;
height: 50vh;
top: 25vh;
left: 25vw;
border-style: solid;
margin: 0;
padding: 0;
}
random_ball.js
const canvas = document.getElementById('canvas')
const bounds = canvas.getBoundingClientRect()
const TWO_PI = 2*Math.Pi
const R = 25
const MAX_Y = bounds.height - R
const MAX_X = bounds.width - R
const ctx = canvas.getContext('2d')
function randomInterval(min, max){
return Math.random()*(max - min) + min
}
function randomVelocity(){ // velocity is pixels/sec
VEL.X = randomInterval(-POS.X + R, MAX_X - POS.X)
VEL.Y = randomInterval(-POS.Y + R, MAX_Y - POS.Y)
console.log('VEL: ' + JSON.stringify(VEL))
}
var POS = {X: bounds.height/2, Y: bounds.width/2}
var VEL = {X: 0, Y: 0}
var LAST_TIME = window.performance.now()
function drawCircle(color){
ctx.strokeStyle = color
ctx.beginPath()
ctx.moveTo(POS.X, POS.Y)
ctx.arc(POS.X, POS.Y, R, 0, TWO_PI, true)
ctx.stroke()
}
function draw(timestamp){
var dt = (timestamp - LAST_TIME)/1000
var dx = VEL.X*dt
var dy = VEL.Y*dt
drawCircle('#FFFFFF') // erase the old drawing by making it white
POS.X += dx
POS.Y += dy
//console.log('POS: ' + JSON.stringify(POS))
drawCircle('#000000')
LAST_TIME = timestamp
requestAnimationFrame(draw)
}
randomVelocity()
drawCircle('#000000')
setInterval(randomVelocity, 1000) //change velocity every second
requestAnimationFrame(draw)
I suspect that drawing white over the old circle means the picture is changing too fast for me to see it.
You might want to familiarize yourself with JavaScript syntax rules, and possibly a code checker like JSHint.
The main problem with your code is that you're referencing a nonexistent property of the Math object. Math has no Pi property. It's spelled PI (all caps). JavaScript is case sensitive about these things.
Next: a more common practice for clearing the canvas is to use ctx.clearRect(0, 0, width, height). Here's a JSFiddle to help you see the difference: https://jsfiddle.net/Hatchet/dy2dognp/

Categories

Resources