How to arrange and style buttons in canvas? - javascript

let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
// for canvas size
var window_width = window.innerWidth;
var window_height = window.innerHeight;
canvas.style.background="yellow"
canvas.width = window_width;
canvas.height = window_height;
let hit_counter=0;
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
class Circle {
constructor(xpos, ypos, radius, color, text) {
this.position_x = xpos;
this.position_y = ypos;
this.radius = radius;
this.text = text;
this.color = color;
}
// creating circle
draw(context) {
context.beginPath();
context.strokeStyle = this.color;
context.fillText(this.text, this.position_x, this.position_y);
context.textAlign = "center";
context.textBaseline = "middle"
context.font = "20px Arial";
context.lineWidth = 5;
context.arc(this.position_x, this.position_y, this.radius, 0, Math.PI * 2);
context.stroke();
context.closePath();
}
update() {
this.text=hit_counter;
context.clearRect(0, 0, window_width, window_height)
this.draw(context);
if ((this.position_x + this.radius) > window_width) {
this.dx = -this.dx;
}
if ((this.position_x - this.radius) < 0) {
this.dx = -this.dx;
}
if ((this.position_y - this.radius) < 0) {
this.dy = -this.dy;
}
if ((this.position_y + this.radius) > window_height) {
this.dy = -this.dy;
}
this.position_x += this.dx;
this.position_y += this.dy;
}
}
let my_circle = new Circle(100, 100, 50, 'Black', hit_counter);
my_circle.update();
<button>ex1</button>
<button>ex2</button>
<button>ex3</button>
<button>ex4</button>
<button>ex5</button>
<button>ex6</button>
<button>ex7</button>
<button>ex8</button>
<canvas id="canvas"></canvas>
HTML
How to arrange and style buttons in canvas? I tried adding CSS to buttons but it didn't work for me.. How to do that? How to arrange the buttons in center of canvas?
<button>ex1</button>
<button>ex2</button>
<button>ex3</button>
<button>ex4</button>
<button>ex5</button>
<button>ex6</button>
<button>ex7</button>
<button>ex8</button>
<canvas id="canvas"></canvas>
JS
How to arrange and style buttons in canvas. I tried adding CSS to buttons but it didn't work for me.. How to do that? How to arrange the buttons in center of canvas?
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
// for canvas size
var window_width = window.innerWidth;
var window_height = window.innerHeight;
canvas.style.background="yellow"
canvas.width = window_width;
canvas.height = window_height;
let hit_counter=0;
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
class Circle {
constructor(xpos, ypos, radius, color, text) {
this.position_x = xpos;
this.position_y = ypos;
this.radius = radius;
this.text = text;
this.color = color;
}
// creating circle
draw(context) {
context.beginPath();
context.strokeStyle = this.color;
context.fillText(this.text, this.position_x, this.position_y);
context.textAlign = "center";
context.textBaseline = "middle"
context.font = "20px Arial";
context.lineWidth = 5;
context.arc(this.position_x, this.position_y, this.radius, 0, Math.PI * 2);
context.stroke();
context.closePath();
}
update() {
this.text=hit_counter;
context.clearRect(0, 0, window_width, window_height)
this.draw(context);
if ((this.position_x + this.radius) > window_width) {
this.dx = -this.dx;
}
if ((this.position_x - this.radius) < 0) {
this.dx = -this.dx;
}
if ((this.position_y - this.radius) < 0) {
this.dy = -this.dy;
}
if ((this.position_y + this.radius) > window_height) {
this.dy = -this.dy;
}
this.position_x += this.dx;
this.position_y += this.dy;
}
}
let my_circle = new Circle(100, 100, 50, 'Black', hit_counter);
my_circle.update();

you can put your buttons inside of a container and position it with absolute property in css
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
// for canvas size
var window_width = window.innerWidth;
var window_height = window.innerHeight;
canvas.style.background="yellow"
canvas.width = window_width;
canvas.height = window_height;
let hit_counter=0;
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
class Circle {
constructor(xpos, ypos, radius, color, text) {
this.position_x = xpos;
this.position_y = ypos;
this.radius = radius;
this.text = text;
this.color = color;
}
// creating circle
draw(context) {
context.beginPath();
context.strokeStyle = this.color;
context.fillText(this.text, this.position_x, this.position_y);
context.textAlign = "center";
context.textBaseline = "middle"
context.font = "20px Arial";
context.lineWidth = 5;
context.arc(this.position_x, this.position_y, this.radius, 0, Math.PI * 2);
context.stroke();
context.closePath();
}
update() {
this.text=hit_counter;
context.clearRect(0, 0, window_width, window_height)
this.draw(context);
if ((this.position_x + this.radius) > window_width) {
this.dx = -this.dx;
}
if ((this.position_x - this.radius) < 0) {
this.dx = -this.dx;
}
if ((this.position_y - this.radius) < 0) {
this.dy = -this.dy;
}
if ((this.position_y + this.radius) > window_height) {
this.dy = -this.dy;
}
this.position_x += this.dx;
this.position_y += this.dy;
}
}
let my_circle = new Circle(100, 100, 50, 'Black', hit_counter);
my_circle.update();
.container{
position:absolute;
}
.container .buttons{
position: absolute;
top:0px;
padding:0.5rem;
}
.container .buttons button{
background:transparent;
padding:0.5rem;
}
<div class="container">
<div class="buttons">
<button>ex1</button>
<button>ex2</button>
<button>ex3</button>
<button>ex4</button>
<button>ex5</button>
<button>ex6</button>
<button>ex7</button>
<button>ex8</button>
</div>
<canvas id="canvas"></canvas>
</div>

Related

How to add external javascript in react app

I made a JavaScript particle animation and it works fine on a normal html website.
I tried implementing it into my react app using react helmet/useEffect but both didn't work and I don't know what's going on.
Here is my script:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = 'absolute';
canvas.style.width = '100%';
canvas.style.height = '100%';
const container = document.querySelector('.particles');
container.appendChild(canvas);
let particleArray;
class Particle {
constructor(x, y, dirX, dirY, size, color) {
this.x = x;
this.y = y;
this.dirX = dirX;
this.dirY = dirY;
this.size = size;
this.color = color;
this.scale = .1;
this.counter = 0;
}
draw() {
var gradient = ctx.createRadialGradient(this.x, this.y, this.size / 8, this.x, this.y, this.size);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'white');
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
ctx.shadowColor = this.color;
ctx.shadowBlur = 10;
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
if (this.x + this.size > canvas.width || this.x - this.size < 0) {
this.dirX = -this.dirX;
}
if (this.y + this.size > canvas.height || this.y - this.size < 0) {
this.dirY = -this.dirY;
}
this.size += this.scale;
this.counter += .1;
if (this.counter > 3) {
this.scale = -this.scale;
this.counter = 0;
}
this.x += this.dirX;
this.y += this.dirY;
this.draw();
}
}
function init() {
particleArray = [];
for (let i = 0; i < 25; i++) {
let size = Math.random() * 3;
let x = Math.random() * (innerWidth - size * 2);
let y = Math.random() * (innerHeight - size * 2);
let dirX = (Math.random() * .4) - .2;
let dirY = (Math.random() * .4) - .2;
let colors = ['#721240']
let color = colors[Math.floor(Math.random() * colors.length)];
particleArray.push(new Particle(x, y, dirX, dirY, size, color));
}
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particleArray.length; i++) {
particleArray[i].update();
}
}
init();
animate();
window.addEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
And here is how I tried to add it to my react app in App.js:
<div className="particles">
{useScript("./assets/particles.js")}
</div>
useScript is a react function using useEffect:
import { useEffect } from "react";
function useScript(url) {
useEffect(() => {
const script = document.createElement("script");
script.src = url;
script.async = false;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, [url]);
}
export default useScript;
Please help I'm stuck...
Instead of injecting the script, why don't you directly inject the code itself in useEffect. That's worked for me on multiple occassions
This is my proposed code. console.log() things like canvas and particleArray at multiple places to get it right
import { useEffect } from "react";
function useScript(url) {
useEffect(() => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = 'absolute';
canvas.style.width = '100%';
canvas.style.height = '100%';
const container = document.querySelector('.particles');
container.appendChild(canvas);
let particleArray;
class Particle {
constructor(x, y, dirX, dirY, size, color) {
this.x = x;
this.y = y;
this.dirX = dirX;
this.dirY = dirY;
this.size = size;
this.color = color;
this.scale = .1;
this.counter = 0;
}
draw() {
var gradient = ctx.createRadialGradient(this.x, this.y, this.size / 8, this.x, this.y, this.size);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'white');
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
ctx.shadowColor = this.color;
ctx.shadowBlur = 10;
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
if (this.x + this.size > canvas.width || this.x - this.size < 0) {
this.dirX = -this.dirX;
}
if (this.y + this.size > canvas.height || this.y - this.size < 0) {
this.dirY = -this.dirY;
}
this.size += this.scale;
this.counter += .1;
if (this.counter > 3) {
this.scale = -this.scale;
this.counter = 0;
}
this.x += this.dirX;
this.y += this.dirY;
this.draw();
}
}
function init() {
particleArray = [];
for (let i = 0; i < 25; i++) {
let size = Math.random() * 3;
let x = Math.random() * (innerWidth - size * 2);
let y = Math.random() * (innerHeight - size * 2);
let dirX = (Math.random() * .4) - .2;
let dirY = (Math.random() * .4) - .2;
let colors = ['#721240']
let color = colors[Math.floor(Math.random() * colors.length)];
particleArray.push(new Particle(x, y, dirX, dirY, size, color));
}
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particleArray.length; i++) {
particleArray[i].update();
}
}
init();
animate();
window.addEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
return ()=>{
window.removeEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
}
}, [url]);
}
export default useScript;

How can I perform a reset on the loop I have when pressing a button?

I'm creating a code where 3 balls will bounce when a button is clicked. I have a code I found in the internet and added the start button but clicking it multiple times speed up the balls. Also, I tried adding a reset button that will clear out the canvas but can't make it work. Sharing both the HTML and JS code.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1000;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
Ball.prototype.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
Ball.prototype.update = function() {
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
let balls = [];
function loop() {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size, width - size), random(0 + size, height - size), 5, 5, 'yellow', size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
}
requestAnimationFrame(loop);
}
document.getElementById('Begin').addEventListener('click',loop);
<input type='button' id='Begin' value='start'>
<canvas id='myCanvas'></canvas>
You need to store the requestAnimationFrame in a var and use cancelAnimationFrame to stop
I added a div to hold the buttons and now delegate from that div so only one event handler is needed.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1000;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
let rq; // this we can use to request and cancel
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
Ball.prototype.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
Ball.prototype.update = function() {
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
let balls = [];
function loop() {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size, width - size), random(0 + size, height - size), 5, 5, 'yellow', size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
}
rq = requestAnimationFrame(loop);
}
document.getElementById('butDiv').addEventListener('click', function(e) {
const tgt = e.target;
if (tgt.id === "Begin") {
if (tgt.value === "start") {
loop()
tgt.value = "stop";
document.getElementById("resetCanvas").classList.add("hide");
} else {
cancelAnimationFrame(rq)
this.value = "start";
document.getElementById("resetCanvas").classList.remove("hide");
}
} else if (tgt.id === "resetCanvas") {
cancelAnimationFrame(rq)
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
document.getElementById("Begin").value="start";
tgt.classList.add("hide");
}
})
.hide {
display: none;
}
<div id="butDiv">
<input type='button' id='Begin' value='start'> <input type='button' class="hide" id='resetCanvas' value='reset'>
</div>
<canvas id='myCanvas'></canvas>

Logo particle animation

Im new to this area and hope some off you can help me.
I am super inspired be this site and the particle animation / function they have http://www.giantstepsmedias.com/
I found this one that are close to the inspiration. But i can't figure out how to change it to an images instead of the value in the input field.
var canvas = document.querySelector("#scene"),
ctx = canvas.getContext("2d"),
particles = [],
amount = 0,
mouse = {x:0,y:0},
radius = 1;
var colors = ["rgba(255,255,255,1)","rgba(255,255,255,.5)", "rgba(255,255,255,.25)","rgba(255,255,255,.1)"];
var copy = document.querySelector("#copy");
var ww = canvas.width = window.innerWidth;
var wh = canvas.height = window.innerHeight;
function Particle(x,y){
this.x = Math.random()*ww;
this.y = Math.random()*wh;
this.dest = {
x : x,
y: y
};
this.r = Math.random()*5 + 2;
this.vx = (Math.random()-0.5)*20;
this.vy = (Math.random()-0.5)*20;
this.accX = 0;
this.accY = 0;
this.friction = Math.random()*0.05 + 0.94;
this.color = colors[Math.floor(Math.random()*6)];
}
Particle.prototype.render = function() {
this.accX = (this.dest.x - this.x)/1000;
this.accY = (this.dest.y - this.y)/1000;
this.vx += this.accX;
this.vy += this.accY;
this.vx *= this.friction;
this.vy *= this.friction;
this.x += this.vx;
this.y += this.vy;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
ctx.fill();
var a = this.x - mouse.x;
var b = this.y - mouse.y;
var distance = Math.sqrt( a*a + b*b );
if(distance<(radius*70)){
this.accX = (this.x - mouse.x)/100;
this.accY = (this.y - mouse.y)/100;
this.vx += this.accX;
this.vy += this.accY;
}
}
function onMouseMove(e){
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function onTouchMove(e){
if(e.touches.length > 0 ){
mouse.x = e.touches[0].clientX;
mouse.y = e.touches[0].clientY;
}
}
function onTouchEnd(e){
mouse.x = -9999;
mouse.y = -9999;
}
function initScene(){
ww = canvas.width = window.innerWidth;
wh = canvas.height = window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = "bold "+(ww/10)+"px sans-serif";
ctx.textAlign = "center";
ctx.fillText(copy.value, ww/2, wh/2);
var data = ctx.getImageData(0, 0, ww, wh).data;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "screen";
particles = [];
for(var i=0;i<ww;i+=Math.round(ww/150)){
for(var j=0;j<wh;j+=Math.round(ww/150)){
if(data[ ((i + j*ww)*4) + 3] > 150){
particles.push(new Particle(i,j));
}
}
}
amount = particles.length;
}
function onMouseClick(){
radius++;
if(radius ===5){
radius = 0;
}
}
function render(a) {
requestAnimationFrame(render);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < amount; i++) {
particles[i].render();
}
};
copy.addEventListener("keyup", initScene);
window.addEventListener("resize", initScene);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onTouchMove);
window.addEventListener("click", onMouseClick);
window.addEventListener("touchend", onTouchEnd);
initScene();
requestAnimationFrame(render);
canvas{
background: black;
width: 100vw;
height: 100vh;
}
<canvas id="scene"></canvas>
<input id="copy" type="text" value="Hello Codepen ♥" />
The animation is based on whatever has been rendered to the canvas.
In your code that is
ctx.font = "bold "+(ww/10)+"px sans-serif";
ctx.textAlign = "center";
ctx.fillText(copy.value, ww/2, wh/2);
instead, change this to render an image:
const img = document.getElementById('img');
ctx.drawImage(img, ww/2, wh/2);
you might like to adjust the positions for .drawImage: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
Using HTML:
<canvas id="scene"></canvas>
<div style="display:none;">
<img id="img"
src="http://www.giantstepsmedias.com/img/logos/giant_steps_small.png">
</div>
However, rendering an image from a different server to your ctx gives The canvas has been tainted by cross-origin data so I can't give you a working snippet.
Use an image that is on the same server as the page or, as suggested, use a data: url:
var canvas = document.querySelector("#scene"),
ctx = canvas.getContext("2d"),
particles = [],
amount = 0,
mouse = {
x: 0,
y: 0
},
radius = 1;
var colors = ["rgba(255,255,255,1)", "rgba(255,255,255,.5)", "rgba(255,255,255,.25)", "rgba(255,255,255,.1)"];
var ww = canvas.width = window.innerWidth;
var wh = canvas.height = window.innerHeight;
function Particle(x, y) {
this.x = Math.random() * ww;
this.y = Math.random() * wh;
this.dest = {
x: x,
y: y
};
this.r = Math.random() * 5 + 2;
this.vx = (Math.random() - 0.5) * 20;
this.vy = (Math.random() - 0.5) * 20;
this.accX = 0;
this.accY = 0;
this.friction = Math.random() * 0.05 + 0.94;
this.color = colors[Math.floor(Math.random() * 6)];
}
Particle.prototype.render = function() {
this.accX = (this.dest.x - this.x) / 1000;
this.accY = (this.dest.y - this.y) / 1000;
this.vx += this.accX;
this.vy += this.accY;
this.vx *= this.friction;
this.vy *= this.friction;
this.x += this.vx;
this.y += this.vy;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
ctx.fill();
var a = this.x - mouse.x;
var b = this.y - mouse.y;
var distance = Math.sqrt(a * a + b * b);
if (distance < (radius * 70)) {
this.accX = (this.x - mouse.x) / 100;
this.accY = (this.y - mouse.y) / 100;
this.vx += this.accX;
this.vy += this.accY;
}
}
function onMouseMove(e) {
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function onTouchMove(e) {
if (e.touches.length > 0) {
mouse.x = e.touches[0].clientX;
mouse.y = e.touches[0].clientY;
}
}
function onTouchEnd(e) {
mouse.x = -9999;
mouse.y = -9999;
}
function initScene() {
ww = canvas.width = window.innerWidth;
wh = canvas.height = window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
//ctx.font = "bold "+(ww/10)+"px sans-serif";
//ctx.textAlign = "center";
//ctx.fillText(copy.value, ww/2, wh/2);
const img = document.getElementById('img');
ctx.drawImage(img, ww / 2 - 75, (wh / 2) - 75, 150, 150);
var data = ctx.getImageData(0, 0, ww, wh).data;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "screen";
particles = [];
for (var i = 0; i < ww; i += Math.round(ww / 150)) {
for (var j = 0; j < wh; j += Math.round(ww / 150)) {
if (data[((i + j * ww) * 4) + 3] > 150) {
particles.push(new Particle(i, j));
}
}
}
amount = particles.length;
}
function onMouseClick() {
radius++;
if (radius === 5) {
radius = 0;
}
}
function render(a) {
requestAnimationFrame(render);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < amount; i++) {
particles[i].render();
}
};
window.addEventListener("resize", initScene);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onTouchMove);
window.addEventListener("click", onMouseClick);
window.addEventListener("touchend", onTouchEnd);
initScene();
requestAnimationFrame(render);
canvas {
background: black;
width: 100vw;
height: 100vh;
}
<canvas id="scene"></canvas>
<div style="display:none;">
<img id="img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAsCAYAAAAJpsrIAAAC9UlEQVR42syZSWgUQRSGezJJ0IhLwIDLRQkumEMOihdFPOghcd9QEEREiIokHkQRISAKRsUdEUxAL2pGxV08iQt40QgexAUNiBgFSQY0EjEzk/J/8kqHobvrRat76sE3E7prar55vdTrl4RS6oXneaNBzvsbSdAPjoATYMCzFw3gAMj6zEvf2w2mlOJlPBgVMAmJTQY7Qa8lsQowMmR/iX7JhAxKgM0gBSZaEjNlP/PHThB14BaY48UUJYMYW8NyG1wToxgB2sA+MNQlMX3e7QZnwTiXxHSsBjfBTNfEKKaDa2BF3GIK/DSMocN5ke91ZXGKHQPthnEk1ALO8CoSuRjtfwvWg1bBfDTuMpgaxzk2nA8nrXHbQZ9h/FxwG8yPWkzlvR/mrHwyfKaaM7clzquSvnAZeG4YRwv1KXAcDItCrN9n2xOwiA+ZKRr5qtVFQLktsTVgks/2j7zvqKBioB9xndfbPlHKUCh+UeZ4DWYDL4BG0CuYpxPcAwMhY8hHLEbRAzaGyNWBD+r/Y9Biin/pQVARIFcLOoohpuMSGBsgNwakiiWmODMzAuTKwH6QKYYYRRdYFXLeNYCvxRCjyIJmzpKf3Dy+Gq2K0cmeFk7YBqoC5GrAA9sZo2zsEU76kCX85CrBOc6wFbFtPHET+C6QewfqA+SSoFUiJlmS9NMQLcZrhZVFe0BlQW2IDltrZTbv7xtgMXgqqOGosjjp0w4YYkussOZ/BpaAq4LPbgXnwYQoyp6Ez7bPXFkcKsioXywAd/LaCyrqxzdqfuzgeuubYew0cAXUgx+SyUstPNCcBu/5fKoOGVcFLvDYHPfCInvg1XGXL4rHgnK71iRlU4ziJculXGgRFEYarAN7DQ3B2MX0w0sz32DTLonpoD7aSvDGNTGK+3wfe+SaGEUnWM4ZdEqMogdsArsEba1YxXRl0cK9j26JmKnZlrQsSCXRUvAqpNf2e0nq4vTmfBbvcsE6+C9BK8RCbi/Myju8+l823i8BBgAb0AQfHTBwWAAAAABJRU5ErkJggg=="
alt="" />
</div>

adding mouse movement to a canvas animation

i have made a an animations in canvas html but now i want to make the origin from where the balls originate move around the canvas according to my mouse position. i want to add mouse event function but i can't seem to get the logic straightand add added to the code , any help would be appreciated !
function runParticles () {
var canvas = document.createElement("canvas");
c = canvas.getContext("2d");
var particles = {};
var particleIndex = 0;
var particleNum = 15;
// set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// add canvas to body
document.body.appendChild(canvas);
// style the canvas
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
function Particle() {
this.x = canvas.width / 2;
this.y = canvas.height / 2;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.3;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.life = 0;
this.maxLife = Math.random() * 30 + 60;
this.color = "hsla(" + parseInt(Math.random() * 360, 10) + ",90%,60%,0.5";
}
Particle.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
if (Math.random() < 0.1) {
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
}
this.life++;
if (this.life >= this.maxLife) {
delete particles[this.id];
}
c.fillStyle = this.color;
//c.fillRect(this.x, this.y, 5, 10);
c.beginPath();
c.arc(this.x, this.y, 2.5, degToRad(0), degToRad(360));
c.fill();
};
setInterval(function() {
//normal setting before drawing over canvas w/ black background
c.globalCompositeOperation = "source-over";
c.fillStyle = "rgba(0,0,0,0.5)";
c.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
}
// c.globalCompositeOperation = "darken";
for (var i in particles) {
particles[i].draw();
}
}, 30);
}
function degToRad(deg) {
var radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
<!DOCTYPE html5>
<html>
<head>
<title>disturbed</title>
<script src="toto.js" type="text/javascript"></script>
<script>
window.onload = () => runParticles();
</script>
</head>
<body>
</body>
</html>
I've added a function to detect the mouse position:
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
I've declared a variable m (the mouse).
var m = {x:canvas.width/2,y:canvas.height/2};
and I've changed the origin of the particles from this.x = canvas.width / 2;
this.y = canvas.height / 2;to this.x = m.x; this.y = m.y;
This is the position when the mouse do not move over the canvas
I've added an event "mousemove". When the mouse move over the canvas it's position change.
canvas.addEventListener("mousemove", (evt)=>{
m = oMousePos(canvas, evt);
})
I've also added an event "mouseleave". When the mouse leaves the canvas, the mouse goes back in the center.
canvas.addEventListener("mouseleave", (evt)=>{
m = {x:canvas.width/2,y:canvas.height/2};
})
Also I've changed the setInterval for requestAnimationFrame ( much more efficient ). The code inside is your code.
function runParticles () {
var canvas = document.createElement("canvas");
c = canvas.getContext("2d");
var particles = {};
var particleIndex = 0;
var particleNum = 8;
// set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var m = {x:canvas.width/2,y:canvas.height/2};///////
// add canvas to body
document.body.appendChild(canvas);
// style the canvas
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
function Particle() {
this.x = m.x;//////////
this.y = m.y;//////////
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.3;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.life = 0;
this.maxLife = Math.random() * 30 + 60;
this.color = "hsla(" + parseInt(Math.random() * 360, 10) + ",90%,60%,0.5";
}
Particle.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
if (Math.random() < 0.1) {
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
}
this.life++;
if (this.life >= this.maxLife) {
delete particles[this.id];
}
c.fillStyle = this.color;
//c.fillRect(this.x, this.y, 5, 10);
c.beginPath();
c.arc(this.x, this.y, 2.5, degToRad(0), degToRad(360));
c.fill();
};
function Draw() {
window.requestAnimationFrame(Draw);
c.globalCompositeOperation = "source-over";
c.fillStyle = "rgba(0,0,0,0.5)";
c.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
}
// c.globalCompositeOperation = "darken";
for (var i in particles) {
particles[i].draw();
}
}
Draw();
///////////////////
canvas.addEventListener("mousemove", (evt)=>{
m = oMousePos(canvas, evt);
})
canvas.addEventListener("mouseleave", (evt)=>{
m = {x:canvas.width/2,y:canvas.height/2};
})
///////////////////
}
function degToRad(deg) {
var radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
runParticles();
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
body,canvas{margin:0;padding:0;}
I hope this helps.

Shouldn't this "if statement" cause a bounce?

The if statement in question is:
if (
this.y + this.radius == lineInfo.loneSy &&
this.x + this.radius > lineInfo.loneSx &&
this.x + this.radius < lineInfo.loneEx
)
{
this.dy = -this.dy; //linebounce
}
I know for sure that the first two conditions work properly because if I omit the third conditional of: this.x + this.radius < lineInfo.loneEx, the ball bounces as expected, however when I add the third conditional in an attempt to constrict its bounce to only within the length of the line; the ball doesn't bounce at all - even though it should.
The entire code for reference is:
let canvas = document.getElementById('myCanvas');
let c = canvas.getContext('2d'); //c = super object (methods / functions) 2d
const sceneObjects = [];
let lineReact = {
jitter: false,
hitOne: false,
hitTwo: false,
hitThree: false,
hitFour: false
}
let lineInfo = {
loneSx: 0,
loneSy: 0,
loneEx: 0,
loneEy: 0
}
window.addEventListener('load',
function(e){
lineReact.jitter == true ? (lineReact.jitter = false) : (lineReact.jitter = true);
if (lineReact.jitter == true){
setTimeout(function(){
lineReact.jitter = false;
console.log("Time lapse " + lineReact.jitter);
}, 300);
}
console.log(lineReact.jitter);
}
)
function Square(x, y, width, height, color){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.draw = function(){
c.fillStyle = this.color;
c.fillRect(this.x, this.y, this.width, this.height);
}
this.update = function(){
this.draw();
}
}
function Line(startX, startY, endX, endY, color, lNumber){
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.color = color;
this.lockSx = this.startX;
this.lockSy = this.startY;
this.lockEx = this.endX;
this.lockEy = this.endY;
this.draw = function(){
c.beginPath();
c.strokeStyle = this.color;
c.moveTo(this.startX, this.startY);
c.lineTo(this.endX, this.endY);
c.stroke();
}
this.update = function(){
if (lineReact.jitter == false){
this.color = "white";
this.startX = this.lockSx;
this.startY = this.lockSy;
this.endX = this.lockEx;
this.endY = this.lockEy;
} else {
if(lNumber == 1){
lineInfo.loneSx = this.lockSx;
lineInfo.loneSy = this.lockSy;
lineInfo.loneEx = this.lockEx;
lineInfo.loneEy = this.lockEy;
this.startX -= Math.floor(Math.random() * 2);
this.startY += Math.floor(Math.random() * 2);
this.endX += Math.floor(Math.random() * 2);
this.endY += Math.floor(Math.random() * 2);
this.color = "red";
}
if(lNumber == 2){
this.startX -= Math.floor(Math.random() * 2);
this.startY -= Math.floor(Math.random() * 2);
this.endX -= Math.floor(Math.random() * 2);
this.endY += Math.floor(Math.random() * 2);
this.color = "red";
}
if(lNumber == 3){
this.startX -= Math.floor(Math.random() * 2);
this.startY -= Math.floor(Math.random() * 2);
this.endX += Math.floor(Math.random() * 2);
this.endY -= Math.floor(Math.random() * 2);
this.color = "red";
}
if(lNumber == 4){
this.startX += Math.floor(Math.random() * 2);
this.startY -= Math.floor(Math.random() * 2);
this.endX += Math.floor(Math.random() * 2);
this.endY += Math.floor(Math.random() * 2);
this.color = "red";
}
}
this.draw();
//console.log('test read ' + lineInfo.loneSx);
}
}
function Circle(x, y, dx, dy, radius){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.draw = function(){
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = 'black';
c.fillStyle = 'black';
c.fill();
c.stroke();
}
this.update = function(){
if (this.x + this.radius > canvas.width || this.x - this.radius < 0){
this.dx = -this.dx; // wallbounce
}
if (this.y + this.radius > canvas.height || this.y - this.radius < 0){
this.dy = -this.dy; // wallbounce
}
if (
this.y + this.radius == lineInfo.loneSy &&
this.x + this.radius > lineInfo.loneSx &&
this.x + this.radius < lineInfo.loneEx
)
{
this.dy = -this.dy; //linebounce
}
this.x += this.dx; //velocity
this.y += this.dy; //velocity
this.draw();
}
}
let square = new Square(280, 280, 40, 40, "pink");
let circle = new Circle(245, 195, 1, 1, 6);
let lineOne = new Line(280, 270, 320, 270, "white", 1);
let lineTwo = new Line(330, 280, 330, 320, "white", 2);
let lineThree = new Line(280, 330, 320, 330, "white", 3);
let lineFour = new Line(270, 280, 270, 320, "white", 4);
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height);
square.update();
lineOne.update();
lineTwo.update();
lineThree.update();
lineFour.update();
circle.update();
}
animate();
body {
background-color: black;
margin: 0;
}
#myCanvas {
position: absolute;
top: 50%;
left: 50%;
background-color: #385D72;
margin: -300px 0 0 -300px;
}
<canvas id="myCanvas" width="600" height="600">
You need to use || instead of &&:
if (
this.y + this.radius == lineInfo.loneSy &&
(this.x + this.radius < lineInfo.loneSx || this.x + this.radius > lineInfo.loneEx)
)
{
this.dy = -this.dy; //linebounce
}
With && you're testing if both conditions are true, but it's impossible for both to be true at the same time (the ball can't be both to the left of the line and to the right of the line).

Categories