DJEveridge
DJEveridge

Reputation: 35

Moving circles with pure javascript and html canvas

I am new to programming and am playing around with HTML canvas and JavaScript. I am only using vanilla JavaScript right now, and I am trying to get a circle to move and get bigger or smaller when I click some buttons.

Everything that I've tried to do has resulted in, for example, the more I press the move left button, the faster it goes left, and if I press the move right button while it is moving left, it just slows down until it stops. Then it goes right.

This happens with every direction and size. All of the attempts I've made are basically this same code in a different order, so if anyone knows how to do this, I'd appreciate it. Thx.

Ignore the file names... they are from an old project. The styling looks weird in here because I made it on a much larger screen. I'm not that good with CSS yet.

const canvas = document.getElementById("canvas1");
const ctx = canvas.getContext('2d',);
const posUp = document.getElementById("posUp");
const posDown = document.getElementById("posDown");
const posRight = document.getElementById("posRight");
const posLeft = document.getElementById("posLeft");
const radUp = document.getElementById("radUp");
const radDown = document.getElementById("radDown");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let size = 0;
let PI = Math.PI;
let posX = window.innerWidth/2;
let posY = window.innerHeight/2;
let angle = 0;
let radius = 50;



const rrgb = `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`
const strokeRRGB = `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`


function posUpFunc() {    
    posY-= 2;
}
function posRightFunc() {
    posX+= 2;
}
function posDownFunc() {
    posY+= 2;
}
function posLeftFunc() {
    posX-= 2;
}
function radUpFunc() {
    radius++;
}
function radDownFunc() {
    radius--;
}

posUp.onclick = () => {
    console.log(posY)

    setInterval(posUpFunc, 10);
}

posRight.onclick = () => {
    console.log(posY)    
    setInterval(posRightFunc, 1);

}

posDown.onclick = () => {
    console.log(posY)
    setInterval(posDownFunc, 10);

}

posLeft.onclick = () => {
    console.log(posY)
    setInterval(posLeftFunc, 10);

}

radUp.onclick = () => {
    console.log(posY)
    setInterval(radUpFunc, 10);

}

radDown.onclick = () => {
    console.log(posY)
    setInterval(radDownFunc, 10);

}


function draw() {
    ctx.fillStyle = rrgb;
    ctx.strokeStyle = strokeRRGB;
    ctx.lineWidth = 3;
    ctx.clearRect(0,0,window.innerWidth,window.innerHeight)
    ctx.beginPath();
    ctx.arc(posX, posY, radius, 0, PI * 2);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
}    



setInterval(draw, 10)
body {
    overflow: hidden;
}


#canvas1 {
    position: absolute;
    border: 2px solid black;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;

}

button {
    height: 2.5%;
    width: 5%;
    position: absolute;
    cursor: pointer;
    z-index: 100;
}

button:hover {
    border: 1px solid black;
}

#posUp {
    left: 5%;
}

#posRight {
left: 10%;
top: 6.5%;
}

#posDown {
left: 5%;
top: 10%;
}

#posLeft {
left: 0%;
top: 6.5%;

}

#radUp {
left: 50.5%;
}

#radDown {
left: 50.5%;
top: 10%;
}

#circle-direction {
position: relative;
top: 5%;
left: 3%;
width: fit-content;
height: fit-content;
z-index: 100;

}

#circle-size {
    position: absolute;
    top: 0.9%;
    left: 50%;
    width: fit-content;
    height: fit-content;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="aestheticPasswordStrengthMeter.js" defer></script>
<link rel="stylesheet" href="aestheticPasswordStrengthMeter.css">  
  <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="circle-direction">Change circle direction.</div>
    <div id="circle-size"> Change circle size.</div>
    <button id="posUp">⇑</button>
    <button id="posRight">⇒</button>
    <button id="posDown">⇓</button>
    <button id="posLeft">⇐</button>
    <button id="radUp">⇑</button>
    <button id="radDown">⇓</button>
    <canvas id="canvas1"></canvas>
</body>
</html>

Upvotes: 0

Views: 477

Answers (2)

Ryan Walls
Ryan Walls

Reputation: 191

I have just gone through and simplified your code so it should work fine now. I have also made it so that the circle never leaves the viewport. If it reaches the edge of the screen it now bounces in the opposite direction.

I have updated it to use requestAnimationFrame as this is recommended over setInterval for things like this. You can read more about this here.

const canvas = document.getElementById("canvas1");
const ctx = canvas.getContext('2d');
const controlsDir = document.querySelector(".controls.direction");
const controlsSize = document.querySelector(".controls.size");

let size = 0;
let PI = Math.PI;
let posX = window.innerWidth / 2;
let posY = window.innerHeight / 2;
let moveX = 0;
let moveY = 0;
let angle = 0;
let radius = 30;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

controlsDir.addEventListener('click', function(event) {
  var dir = event.target.dataset.dir;
  
  if(dir == 'u') moveY = -2;
  if(dir == 'd') moveY = 2;
  if(dir == 'r') moveX = 2;
  if(dir == 'l') moveX = -2;
});

controlsSize.addEventListener('click', function(event) {
  var dir = event.target.dataset.dir;
  
  if(dir == 'u') radius++;
  if(dir == 'd') radius--;
});

function draw() {
    if(window.innerWidth < (posX + radius) || 0 > (posX - radius)) {
      moveX = -moveX;
    } else if(window.innerHeight < (posY + radius) || 0 > (posY - radius)) {
      moveY = -moveY;
    }
    posX = posX + moveX;
    posY = posY + moveY;
  ctx.clearRect(0,0,window.innerWidth,window.innerHeight);
  
    ctx.fillStyle = 'blue';
    ctx.beginPath();
    ctx.arc(posX, posY, radius, 0, PI * 2);
    ctx.closePath();
    ctx.fill();
    
    window.requestAnimationFrame(draw);
}    

draw();
body {
    overflow: hidden;
}

canvas {
    position: absolute;
    border: 2px solid black;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

h4 {margin: 0; padding: 0.2em 0;}

.controls {
  position: absolute;
  padding: 4px 8px;
}

.buttons-container {
  display: flex;
}

.controls.direction {
  top: 0;
  left: 0;
}

.controls.size {
  top: 0;
  right: 0;
}

.button {
font-size: 14px;
  width: 25px;
  height: 25px;
  overflow: hidden;
  text-align: center;
  background-color: lightgrey;
  cursor: pointer;
}
<canvas id="canvas1"></canvas>

<div class="controls direction" >
  <h4>Change direction</h4>
    <div class="buttons-container">
    <div class="button" data-dir="u">⇑</div>
    <div class="button" data-dir="d">⇓</div>
    <div class="button" data-dir="r">⇒</div>
    <div class="button" data-dir="l">⇐</div>
  </div>
</div>

<div class="controls size">
  <h4>Change size</h4>
  <div class="buttons-container">
  <div class="button" data-dir="u">⇑</div>
  <div class="button" data-dir="d">⇓</div>
  </div>
</div>

Upvotes: 0

TechySharnav
TechySharnav

Reputation: 5084

The problem is, you are not clearing any intervals, that you are setting. You need to use clearInterval() method, to clear the set interval.

Also, the interval for posRightFunc was set to 1ms, which caused the program to lag.

const canvas = document.getElementById("canvas1");
const ctx = canvas.getContext('2d', );
const posUp = document.getElementById("posUp");
const posDown = document.getElementById("posDown");
const posRight = document.getElementById("posRight");
const posLeft = document.getElementById("posLeft");
const radUp = document.getElementById("radUp");
const radDown = document.getElementById("radDown");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let size = 0;
let PI = Math.PI;
let posX = window.innerWidth / 2;
let posY = window.innerHeight / 2;
let angle = 0;
let radius = 50;
let posXInt, posYInt;

const rrgb = `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`
const strokeRRGB = `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`


function posUpFunc() {
  posY -= 2;
}

function posRightFunc() {
  posX += 2;
}

function posDownFunc() {
  posY += 2;
}

function posLeftFunc() {
  posX -= 2 ;
}

function radUpFunc() {
  radius++;
}

function radDownFunc() {
  radius--;
  if (radius <= 0) radius = 0;  //cap the radius to 0, if it falls below 0
}

posUp.onclick = () => {
  console.log(posY)
  if(posYInt) clearInterval(posYInt);          //clear the interval, if it is set
  posYInt = setInterval(posUpFunc, 10);      
}

posRight.onclick = () => {
  console.log(posY)
  if(posXInt) clearInterval(posXInt);          //clear the interval, if it is set
  posXInt = setInterval(posRightFunc, 10);      
}

posDown.onclick = () => {
  console.log(posY)
  if(posYInt) clearInterval(posYInt);          //clear the interval, if it is set
  posYInt = setInterval(posDownFunc, 10);      

}

posLeft.onclick = () => {
  console.log(posY)
  if(posXInt) clearInterval(posXInt);          //clear the interval, if it is set
  posXInt = setInterval(posLeftFunc, 10);      
}

radUp.onclick = () => {
  console.log(posY)
  let count = 0;
  let interval = setInterval(() => {
    if (count > 20) clearInterval(interval);   //chnage 20 to amount of radius by which you want to increase it
    radUpFunc();
    count++;
  }, 10);
}

radDown.onclick = () => {
  console.log(posY)
  let count = 0;
  let interval = setInterval(() => {
    if (count > 20) clearInterval(interval);   //chnage 20 to amount of radius by which you want to decrease it
    radDownFunc();
    count++;
  }, 10);

}


function draw() {
  ctx.fillStyle = rrgb;
  ctx.strokeStyle = strokeRRGB;
  ctx.lineWidth = 3;
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
  ctx.beginPath();
  ctx.arc(posX, posY, radius, 0, PI * 2);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
}



setInterval(draw, 10)
body {
  overflow: hidden;
}

#canvas1 {
  position: absolute;
  border: 2px solid black;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

button {
  height: 2.5%;
  width: 5%;
  position: absolute;
  cursor: pointer;
  z-index: 100;
}

button:hover {
  border: 1px solid black;
}

#posUp {
  left: 5%;
}

#posRight {
  left: 10%;
  top: 6.5%;
}

#posDown {
  left: 5%;
  top: 10%;
}

#posLeft {
  left: 0%;
  top: 6.5%;
}

#radUp {
  left: 50.5%;
}

#radDown {
  left: 50.5%;
  top: 10%;
}

#circle-direction {
  position: relative;
  top: 5%;
  left: 3%;
  width: fit-content;
  height: fit-content;
  z-index: 100;
}

#circle-size {
  position: absolute;
  top: 0.9%;
  left: 50%;
  width: fit-content;
  height: fit-content;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <script src="aestheticPasswordStrengthMeter.js" defer></script>
  <link rel="stylesheet" href="aestheticPasswordStrengthMeter.css">
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="circle-direction">Change circle direction.</div>
  <div id="circle-size"> Change circle size.</div>
  <button id="posUp">⇑</button>
  <button id="posRight">⇒</button>
  <button id="posDown">⇓</button>
  <button id="posLeft">⇐</button>
  <button id="radUp">⇑</button>
  <button id="radDown">⇓</button>
  <canvas id="canvas1"></canvas>
</body>

</html>

Upvotes: 1

Related Questions