What's wrong with my rewrite from jquery to react - javascript

I try to rewrite this liquid button https://codepen.io/waaark/pen/VbgwEM , it use jquery.
I want to rewrite it for my react component, but don't know what is wrong:
here is the component code:
import React from "react";
import Link from "next/link";
import { useRef } from 'react';
import { useEffect } from 'react';
import { useState } from 'react';
const getPixelRatio = context => {
var backingStore =
context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
return (window.devicePixelRatio || 1) / backingStore;
};
const useMove = () => {
let ref = useRef();
/* let msx = 0;
let msy = 0;
let mlx = 0;
let mly = 0; */
/* function mouseSpeed() {
msx = state.x - state.mouseLastXX;
msy = state.y - state.mouseLastYY;
mlx = state.x;
mly = state.y;
setTimeout(mouseSpeed, 50);
} */
const [state, setState] = useState({x: 0, y: 0, mouseDirectionXX:0, mouseDirectionYY:0, mouseSpeedXX:0, mouseSpeedYY:0, mouseLastXX:0, mouseLastYY:0})
const handleMouseMove = e => {
//e.persist()
let xx = state.mouseDirectionX;
let yy = state.mouseDirectionY;
//mouseSpeed();
if (state.x < e.clientX)
xx = 1;
else if (state.x > e.clientX)
xx = -1;
else
xx = 0;
if (state.y < e.clientY)
yy = 1;
else if (state.y > e.clientY)
yy = -1;
else
yy = 0;
//rx = (state.x - offset.left);
//ry = (state.y - offset.top);
setState(state => ({...state, x: e.clientX, y: e.clientY, mouseDirectionXX:xx, mouseDirectionYY:yy}))
//mouseX = e.clientX;
//mouseY = e.clientY;
//relMouseX = (mouseX - canvas.offsetLeft);
//relMouseY = (mouseY - canvas.offsetTop);
//console.log(xx + "///" + yy);
}
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, []);
return {
mouseX: state.x,
mouseY: state.y,
mouseDirectionX: state.mouseDirectionXX,
mouseDirectionY: state.mouseDirectionYY,
mouseLastX: state.mouseLastXX,
mouseLastY: state.mouseLastYY,
mouseSpeedX: state.mouseSpeedXX,
mouseSpeedY: state.mouseSpeedYY,
//relMouseX: state.relMouseXX,
//relMouseY: state.relMouseYY,
handleMouseMove,
}
}
const LiquidButton = () => {
const {mouseX, mouseY, mouseDirectionX, mouseDirectionY, handleMouseMove} = useMove();
let ref = useRef();
let buttonWidth = 240;
let buttonHeight = 60;
let points = 8;
let pointsA = [], pointsB = [];
let viscosity = 10, mouseDist = 70, damping = 0.05, showIndicators = false;
let relMouseX = 0;
let relMouseY = 0;
//let canvas = ref.current;
/* function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
//console.log("AYE");
}
mouseSpeed(); */
useEffect(() => {
let canvas = ref.current;
let context = canvas.getContext('2d');
let canvaspos = canvas.getBoundingClientRect();
let offset = {
top: canvaspos.top,
left: canvaspos.left,
};
let mouseLastX = 0;
let mouseLastY = 0;
//mouseDirectionX = 0,
//mouseDirectionY = 0,
let mouseSpeedX = 0;
let mouseSpeedY = 0;
relMouseX = (mouseX - offset.left);
relMouseY = (mouseY - offset.top);
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
//NEW
console.log("mouseX:" + mouseX)
console.log("mouseLastX: "+ mouseLastX);
console.log("mouseSpeedX: "+ mouseSpeedX);
console.log("relMouseX:" + relMouseX)
console.log("mouseDirectionX: "+ mouseDirectionX);
console.log("mouseY:" + mouseY)
console.log("mouseLastY: "+ mouseLastY);
console.log("mouseSpeedY: "+ mouseSpeedY);
console.log("relMouseY:" + relMouseY)
console.log("mouseDirectionY: "+ mouseDirectionY);
function Point(x, y, level) {
this.x = this.ix = 75+x;
this.y = this.iy = 75+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
//NEW-END
let ratio = getPixelRatio(context);
let width = getComputedStyle(canvas)
.getPropertyValue('width')
.slice(0, -2);
let height = getComputedStyle(canvas)
.getPropertyValue('height')
.slice(0, -2);
canvas.width = buttonWidth+150;
canvas.height = buttonHeight+150;
//canvas.width = width * ratio;
//canvas.height = height * ratio;
canvas.style.width = width+`px`;
canvas.style.height = height+`px`;
let x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
let requestId, i = 0;
const render = () => {
// Clear scene
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgba(0, 0, 200, 0.0)";
context.fillRect(0, 0, canvas.width, canvas.height);
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - offset.left, 0), canvas.width);
var gradientY = Math.min(Math.max(mouseY - offset.top, 0), canvas.height);
var distance = Math.sqrt(Math.pow(gradientX - canvas.width/2, 2) + Math.pow(gradientY - canvas.height/2, 2)) / Math.sqrt(Math.pow(canvas.width/2, 2) + Math.pow(canvas.height/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
requestId = requestAnimationFrame(render);
};
render();
return () => {
cancelAnimationFrame(requestId);
};
});
return (
<div>
<canvas ref={ref} style={{ width: '390px', height: '210px' }} >
<a href="#" className="btn-liquid">
<span className="inner">Press Button</span>
</a>
</canvas>
<div className="mouseArea">
Hook
<div className="mouseInfo">
The current mouse position is ({mouseX}, {mouseY}) <br />
Mouse Direction is ({mouseDirectionX}, {mouseDirectionY}) <br />
{/* Mouse Last ({mouseLastX}, {mouseLastY}) <br /> */}
{/* Mouse Speed ({mouseSpeedX}, {mouseSpeedY}) <br /> */}
</div>
</div>
</div>
);
};
export default LiquidButton;
i tried to calculate the mouse speed and mouse direction, but still confuse where to put the code.When I console log the value, the mouse position, mouse speed and mouse last position are the same value

How about this?
let pointsA = [];
let pointsB = [];
let $canvas = null;
let canvas = null;
let context = null;
// let vars = null;
let points = 8;
let viscosity = 20;
let mouseDist = 70;
let damping = 0.05;
let showIndicators = false;
let mouseX = 0;
let mouseY = 0;
let relMouseX = 0;
let relMouseY = 0;
let mouseLastX = 0;
let mouseLastY = 0;
let mouseDirectionX = 0;
let mouseDirectionY = 0;
let mouseSpeedX = 0;
let mouseSpeedY = 0;
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
function initButton(button) {
// Get button
// var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth + 100;
canvas.height = buttonHeight + 100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight / 2;
for (let j = 1; j < points; j++) {
addPoints((x + ((buttonWidth - buttonHeight) / points) * j), 0);
}
addPoints(buttonWidth - buttonHeight / 5, 0);
addPoints(buttonWidth + buttonHeight / 10, buttonHeight / 2);
addPoints(buttonWidth - buttonHeight / 5, buttonHeight);
for (let j = points - 1; j > 0; j--) {
addPoints((x + ((buttonWidth - buttonHeight) / points) * j), buttonHeight);
}
addPoints(buttonHeight / 5, buttonHeight);
addPoints(-buttonHeight / 10, buttonHeight / 2);
addPoints(buttonHeight / 5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
function Point(x, y, level) {
this.x = this.ix = 50 + x;
this.y = this.iy = 50 + y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity * this.level);
this.vy += (this.iy - this.y) / (viscosity * this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1 - Math.sqrt((dx * dx) + (dy * dy)) / mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
function renderCanvas() {
// rAF
// rafID =
requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width() / 2, 2) + Math.pow(gradientY - $canvas.height() / 2, 2)) / Math.sqrt(Math.pow($canvas.width() / 2, 2) + Math.pow($canvas.height() / 2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300 + (300 * distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j === 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (let i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
// var val = 30*0.552284749831;
if (nextP !== undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x + nextP.x) / 2;
p.cy1 = (p.y + nextP.y) / 2;
p.cx2 = (p.x + nextP.x) / 2;
p.cy2 = (p.y + nextP.y) / 2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x + nextP.x) / 2;
p.cy1 = (p.y + nextP.y) / 2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (let i = 0; i < pointsA.length; i++) {
// var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (let i = 0; i < pointsA.length; i++) {
// var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
const StaticLiquidButton = ({
className,
liquidBtnRef,
href
}) => ( <
a href = {
href
}
className = "btn-liquid"
ref = {
liquidBtnRef
} >
<
span class = "inner" >
Liquid button ?
<
/span> <
/a>
);
StaticLiquidButton.propTypes = {
className: PropTypes.string.isRequired
};
const LiquidButton = () => {
const liquidBtnRef = React.useRef()
React.useEffect(() => {
const button = liquidBtnRef.current;
initButton($(button));
$(document).on('mousemove', mouseDirection);
return () => {
$(document).off('mousemove', mouseDirection)
}
},[])
return (
<StaticLiquidButton
className="TeslaAppUI-LiquidButton"
href="http://waaark.com"
liquidBtnRef={liquidBtnRef}
/>
)
}
function App() {
return ( <
div >
<
LiquidButton / >
<
/div>
);
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
body {
margin: 0;
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js" integrity="sha512-ssNhh7jlzc+K93ckIlSXFHHz6fSFv0l619WOv8xbFNRbFOujbasb42LVMOggDrQR1ScJncoWb+KAJx1uF3ipjw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Good Luck...

Related

Problems with translating c++ to javascript

I was trying to replicate this c++ code in javascript.
https://github.com/OneLoneCoder/videos/blob/master/OneLoneCoder_PathFinding_AStar.cpp
The code should draw a yellow line from the red point to the green point.
I checked my implementation multiple times but I still can't figure out why it is not working.
For some reason it won't set the parent for my objects correctly.
Which results in the path not getting drawn.
Could really need some help here.
width = 11;
height = 9;
s = 50;
c = document.createElement("canvas");
document.body.appendChild(c);
ctx = c.getContext("2d");
c.width = width * s;
c.height = height * s;
nodes = [];
for (x = 0; x < width; x++) {
row = [];
nodes.push(row);
for (y = 0; y < height; y++) {
row.push(new Node(x, y));
}
}
SetNeighbours();
function SetNeighbours() {
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
if (x > 0) {
nodes[x][y].neighbours.push(nodes[x - 1][y])
}
if (x < width - 1) {
nodes[x][y].neighbours.push(nodes[x + 1][y])
}
if (y > 0) {
nodes[x][y].neighbours.push(nodes[x][y - 1])
}
if (y < height - 1) {
nodes[x][y].neighbours.push(nodes[x][y + 1])
}
}
}
}
nodes[3][0].obstacle = true;
nodes[3][1].obstacle = true;
nodes[3][2].obstacle = true;
nodes[3][3].obstacle = true;
nodes[3][4].obstacle = true;
nodes[3][5].obstacle = true;
nodes[7][3].obstacle = true;
nodes[7][4].obstacle = true;
nodes[7][5].obstacle = true;
nodes[7][6].obstacle = true;
nodes[7][7].obstacle = true;
nodes[7][8].obstacle = true;
start = nodes[1][1];
end = nodes[9][7];
//end.parent = nodes[9][6];
//nodes[9][6].parent = nodes[9][5]
current = start;
start.localGlobal = 0;
start.globalGoal = heuristic(start, end);
notTested = [];
notTested.push(start);
while (notTested.length > 0 && current != end) {
notTested.sort(function(a, b) {
return a.globalGoal < b.globalGoal
});
while (notTested.length > 0 && notTested[0].visited) {
notTested.shift();
}
if (notTested.length == 0) {
break;
}
current = notTested[0];
current.visited = true;
for (let n of current.neighbours) {
if (!n.visited && !n.obstacle) {
notTested.push(n);
}
newGoal = current.localGoal + distance(current, n);
if (newGoal < n.localGoal) {
n.parent = current;
n.localGoal = newGoal;
n.globalGoal = n.localGoal + heurisitc(n, end);
}
}
}
DrawCanvas();
function DrawCanvas() {
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
for (let node of nodes[x][y].neighbours) {
ctx.beginPath();
ctx.moveTo(x * s + (s / 2), y * s + (s / 2));
ctx.lineTo(node.x * s + (s / 2), node.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "navy";
ctx.stroke();
}
}
}
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
if (nodes[x][y] == start) {
ctx.fillStyle = "crimson";
} else if (nodes[x][y] == end) {
ctx.fillStyle = "green";
} else if (nodes[x][y].visited) {
ctx.fillStyle = "blue";
} else if (nodes[x][y].obstacle) {
ctx.fillStyle = "grey";
} else {
//ctx.fillStyle = x % 2 != y % 2 ? "lightgrey" : "darkgrey";
ctx.fillStyle = "navy";
}
ctx.fillRect(x * s + 5, y * s + 5, s - 10, s - 10);
}
}
}
if (end != null) {
p = end;
while (p.parent != null) {
ctx.beginPath();
ctx.moveTo(p.x * s + (s / 2), p.y * s + (s / 2));
ctx.lineTo(p.parent.x * s + (s / 2), p.parent.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
p = p.parent;
}
}
function Node(x, y) {
this.obstacle = false;
this.visited = false;
this.globalGoal = 1000000;
this.localGoal = 1000000;
this.x = x;
this.y = y;
this.neighbours = [];
this.parent = null;
}
function distance(a, b) {
return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2)
}
function heuristic(a, b) {
return distance(a, b);
}
body
{
background: black;
}
In line where you set current variable you have a typo
There should be start.localGoal = 0; and not start.localGlobal = 0;
width = 11;
height = 9;
s = 50;
c = document.createElement("canvas");
document.body.appendChild(c);
ctx = c.getContext("2d");
c.width = width * s;
c.height = height * s;
nodes = [];
for (let x = 0; x < width; x++) {
nodes[x] = [];
for (let y = 0; y < height; y++) {
nodes[x].push(new Node(x, y));
}
}
SetNeighbours();
function SetNeighbours() {
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
if (x > 0) {
nodes[x][y].neighbours.push(nodes[x - 1][y])
}
if (x < width - 1) {
nodes[x][y].neighbours.push(nodes[x + 1][y])
}
if (y > 0) {
nodes[x][y].neighbours.push(nodes[x][y - 1])
}
if (y < height - 1) {
nodes[x][y].neighbours.push(nodes[x][y + 1])
}
}
}
}
nodes[3][0].obstacle = true;
nodes[3][1].obstacle = true;
nodes[3][2].obstacle = true;
nodes[3][3].obstacle = true;
nodes[3][4].obstacle = true;
nodes[3][5].obstacle = true;
nodes[7][3].obstacle = true;
nodes[7][4].obstacle = true;
nodes[7][5].obstacle = true;
nodes[7][6].obstacle = true;
nodes[7][7].obstacle = true;
nodes[7][8].obstacle = true;
start = nodes[1][1];
end = nodes[9][7];
//end.parent = nodes[9][6];
//nodes[9][6].parent = nodes[9][5]
start.localGoal = 0;
start.globalGoal = heuristic(start, end);
current = start;
notTested = [];
notTested.push(start);
while (notTested.length > 0 && current !== end) {
notTested.sort(function (a, b) {
return a.globalGoal < b.globalGoal
});
while (notTested.length > 0 && notTested[0].visited) {
notTested.shift();
}
if (notTested.length === 0) {
break;
}
const current = notTested[0];
current.visited = true;
for (let n of current.neighbours) {
if (!n.visited && !n.obstacle) {
notTested.push(n);
}
const newGoal = current.localGoal + distance(current, n);
if (newGoal < n.localGoal) {
n.parent = current;
n.localGoal = newGoal;
n.globalGoal = n.localGoal + heuristic(n, end);
}
}
}
DrawCanvas();
function DrawCanvas() {
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
for (let node of nodes[x][y].neighbours) {
ctx.beginPath();
ctx.moveTo(x * s + (s / 2), y * s + (s / 2));
ctx.lineTo(node.x * s + (s / 2), node.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "navy";
ctx.stroke();
}
}
}
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
if (nodes[x][y] === start) {
ctx.fillStyle = "crimson";
} else if (nodes[x][y] === end) {
ctx.fillStyle = "green";
} else if (nodes[x][y].visited) {
ctx.fillStyle = "blue";
} else if (nodes[x][y].obstacle) {
ctx.fillStyle = "grey";
} else {
//ctx.fillStyle = x % 2 != y % 2 ? "lightgrey" : "darkgrey";
ctx.fillStyle = "navy";
}
ctx.fillRect(x * s + 5, y * s + 5, s - 10, s - 10);
}
}
}
if (end != null) {
p = end;
while (p.parent != null) {
ctx.beginPath();
ctx.moveTo(p.x * s + (s / 2), p.y * s + (s / 2));
ctx.lineTo(p.parent.x * s + (s / 2), p.parent.y * s + (s / 2));
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
p = p.parent;
}
}
function Node(x, y) {
this.obstacle = false;
this.visited = false;
this.globalGoal = 1000000;
this.localGoal = 1000000;
this.x = x;
this.y = y;
this.neighbours = [];
this.parent = null;
}
function distance(a, b) {
return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
}
function heuristic(a, b) {
return distance(a, b);
}
body
{
background: black;
}

Removing lag on rendering thousands of entities in JS canvas

I am a beginner in JS canvas. I wanna make a game but when rendering too many (Bricks) the game becomes unplayable. Most of the lag comes from draw function the part where bricks are drawn, From ctx.fill() and ctx.rect() function. I observed it with the chrome's performance devtool.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width / 2;
var y = canvas.height - ballRadius;
var bulletX = x;
var bulletY = y;
var bullet2X = x;
var bullet2Y = y;
var dx = 2;
var dy = -2;
var paddleHeight = 0;
var paddleWidth = canvas.width;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 50;
var brickColumnCount = 96;
var brickWidth = 5;
var brickHeight = 5;
var brickPadding = 0;
var brickOffsetTop = 0;
var brickOffsetLeft = 0;
var score = 0;
var damageDealth = 0;
var brickHealth = 1000;
var scoreEarned = 0;
window.bricks = [];
if (bricks.length == 0) {
bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: brickHealth
};
}
}
}
var resetLevel =
setInterval(() => {
var brickStatus = 0;
for (var row = 0; row < bricks.length; row++) {
bricks[row].forEach((status) => {
if (status.status > 1) {
brickStatus += 1;
}
})
}
if (brickStatus < 1) {
for (var row = 0; row < bricks.length; row++) {
for (var brick = 0; brick < bricks[row].length; brick++) {
if (bricks[row][brick].status < 1) {
brickHealth += 1;
bricks[row][brick].status = 1000
allBullets = [];
childBullets = [];
AOEBullets = [];
}
}
}
}
console.log(brickStatus);
console.log("BrickHealth: " + brickHealth)
}, 1000);
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = false;
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
class MakeBullet {
constructor(x, y, radius, color, speedX, speedY, pierce, lifespan, damage) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.color = color;
this.pierce = pierce;
this.lifespan = lifespan;
this.damage = damage;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.draw();
this.x = this.x + this.speedX;
this.y = this.y + this.speedY;
}
}
window.allBullets = [];
window.childBullets = [];
window.AOEBullets = [];
document.addEventListener("mousemove", (event) => {
const angle = Math.atan2(event.clientY - y, event.clientX - x);
window.shootAngle = {
x: Math.cos(angle),
y: Math.sin(angle)
}
})
setInterval(() => {
if (allBullets.length < 101) {
allBullets.push(new MakeBullet(x, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 2, 25))
/* allBullets.push(new MakeBullet(x - 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 50))
allBullets.push(new MakeBullet(x + 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 25)) */
}
}, 75)
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status > 0) {
var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
childBullets.forEach((childBullet) => {
if (childBullet.lifespan > 0) {
childBullet.update();
childBullet.draw();
if (childBullet.x + childBullet.speedX > canvas.width - childBullet.radius || childBullet.x + childBullet.speedX < childBullet.radius) {
childBullet.speedX = -childBullet.speedX;
}
if (childBullet.y + childBullet.speedY > canvas.width - childBullet.radius || childBullet.y + childBullet.speedY < childBullet.radius) {
childBullet.speedY = -childBullet.speedY;
} else if (childBullet.y + childBullet.speedY > canvas.height - childBullet.radius) {
if (childBullet.x > paddleX && childBullet.x < paddleX + paddleWidth) {
if (childBullet.y = childBullet.y - paddleHeight) {
childBullet.speedY = -childBullet.speedY;
}
}
}
}
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (childBullet.x > b.x && childBullet.x < b.x + brickWidth && childBullet.y > b.y && childBullet.y < b.y + brickHeight) {
b.status -= childBullet.damage;
childBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 5);
score += randomScore;
scoreEarned += randomScore;
damageDealth += childBullet.damage;
}
}
}
}
})
AOEBullets.forEach((AOEBullet) => {
if (AOEBullet.lifespan > 0) {
AOEBullet.update();
AOEBullet.draw();
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (AOEBullet.x + AOEBullet.radius > b.x + brickWidth && AOEBullet.x - AOEBullet.radius < b.x + brickWidth && AOEBullet.y + AOEBullet.radius > b.y + brickHeight && AOEBullet.y - AOEBullet.radius < b.y + brickHeight) {
b.status -= AOEBullet.damage;
AOEBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 10);
score += randomScore;
scoreEarned += randomScore;
damageDealth += AOEBullet.damage;
}
}
}
}
}
})
if (shootAngle !== undefined) {
allBullets.forEach((bullet) => {
if (bullet.lifespan > 0) {
if (bullet.pierce > 0) {
bullet.update();
bullet.draw();
window.BulletX = bullet.x;
window.BulletY = bullet.y;
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
bullet.pierce -= 1;
var randomScore = Math.floor(Math.random() * 100);
score += randomScore;
scoreEarned += randomScore;
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 1.4))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.7))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.5))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.2))
damageDealth += bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
}
}
}
if (bullet.x + bullet.speedX > canvas.width - bullet.radius || bullet.x + bullet.speedX < bullet.radius) {
bullet.speedX = -bullet.speedX;
}
if (bullet.y + bullet.speedY > canvas.width - bullet.radius || bullet.y + bullet.speedY < bullet.radius) {
bullet.speedY = -bullet.speedY;
} else if (bullet.y + bullet.speedY > canvas.height - bullet.radius) {
if (bullet.x > paddleX && bullet.x < paddleX + paddleWidth) {
if (bullet.y = bullet.y - paddleHeight) {
bullet.speedY = -bullet.speedY;
}
}
}
}
}
})
}
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
if (y = y - paddleHeight) {
dy = -dy;
}
} else {
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}
if (rightPressed && x < canvas.width - ballRadius) {
x += 7;
} else if (leftPressed && x > 0 + ballRadius) {
x -= 7;
}
// x += dx;
//y += dy;
}
var interval = setInterval(draw, 10);
setInterval(() => {
allBullets.forEach((bullet) => {
for (var i = 0; i < 1; i++) {
var angle = 2 * Math.PI * Math.random();
var randomx = bullet.speedX * Math.cos(angle);
var randomy = bullet.speedY * Math.sin(angle);
if (bullet.lifespan < 1) {
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 0.24))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.16))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.08))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.04))
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 2), randomy + randomy * Math.floor(Math.random() * 2), 5, 5, 1))
}
}
if (bullet.pierce < 1) {
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 5), randomy + randomy * Math.floor(Math.random() * 5), 5, 5, 1))
}
}
}
})
}, 1)
var lifeSpan = setInterval(() => {
allBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
childBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
AOEBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
}, 100)
setInterval(() => {
for (var i = 0; i < allBullets.length; i++) {
if (allBullets[i].pierce < 1 || allBullets[i].lifespan < 1) {
allBullets.splice(allBullets.indexOf[i], 1)
}
}
}, 50)
setInterval(() => {
for (var i = 0; i < childBullets.length; i++) {
if (childBullets[i].pierce < 1 || childBullets[i].lifespan < 0) {
childBullets.splice(childBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < AOEBullets.length; i++) {
if (AOEBullets[i].pierce < 1 || AOEBullets[i].lifespan < 0) {
AOEBullets.splice(AOEBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < 8; i++) {
allBullets.push(new MakeBullet(x, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x + 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x - 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
}
}, 30000)
setInterval(() => {
document.getElementsByClassName("scrore")[0].innerText = "Score: " + score;
}, 100)
setInterval(() => {
document.getElementsByClassName("scoreEarned")[0].innerText = "Score Earned: " + scoreEarned;
scoreEarned = 0;
}, 1000)
var damage = setInterval(() => {
document.getElementsByClassName("damageDealth")[0].innerText = "Damage: " + damageDealth.toFixed(1);
damageDealth = 0;
}, 1000)
<canvas id="myCanvas" height="320" width="480" style="background-color: #eee"></canvas>
<p class="scrore" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score: 0</p>
<p class="scoreEarned" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score Earned: 0</p>
<p class="damageDealth" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Damage: 0</p>
One idea to speed up the drawing is to prepare the next frame to be shown on an invisible canvas. Then blip the invisible canvas to the canvas shown to the player in one go.
// drawing surface
var visibleCanvas_; // (HTML5 canvas) serves as playfield, visible for user
var visibleCtx2d_; // (HTML5 canvas 2D context) context of visible canvas
// optimization: if drawing with fillRect(), draw on hidden canvas
var hiddenCanvas_; // (HTML5 canvas) invisible canvas on which shapes are drawn each step
var hiddenCtx2d_; // (HTML5 canvas 2D context) context of invisible canvas
function createHiddenCanvas_(mainCanvas) {
hiddenCanvas_= document.createElement("canvas");
hiddenCanvas_.width = mainCanvas.width;
hiddenCanvas_.height = mainCanvas.height;
hiddenCtx2d_= hiddenCanvas_.getContext("2d");
// other settings that do not change while drawing, e.g. brick color
// hiddenCtx2d_.strokeStyle = ...;
// hiddenCtx2d_.fillStyle = ...;
}
// must be called once at startup of the game
function init_() {
visibleCanvas_ = document.getElementById('myCanvas');
visibleCtx2d_= visibleCanvas_.getContext('2d');
createHiddenCanvas_(visibleCanvas_);
}
// to be called before we start building the next frame
function startDraw_() {
// clear hidden canvas
hiddenCtx2d_.clearRect(0, 0, hiddenCanvas_.width, hiddenCanvas_.height);
}
// draws single brick for next frame on hidden canvas
function drawBrick_(brickX, brickY, brickWidth, brickHeight) {
hiddenCtx2d_.fillRect(brickX, brickY, brickWidth, brickHeight);
}
// to be called after we finish building the next frame and want to display it
function finishDraw_() {
// clear visible canvas
visibleCtx2d_.clearRect(0, 0, visibleCanvas_.width, visibleCanvas_.height);
// blip hidden canvas on visible canvas
visibleCtx2d_.drawImage(hiddenCanvas_, 0, 0);
}
Draw all shapes for the next frame between startDraw_ and finishDraw_.
You should also look into window.requestAnimationFrame to manage when the next frame is drawn.

JS: putting 2 liquid buttons in my page instead of 1

Heello everyone!
I hope you feel well and i wish you a happy new year !
I just love this liquid button :
https://codepen.io/waaark/pen/VbgwEM
$(function() {
// Vars
var pointsA = [],
pointsB = [],
$canvas = null,
canvas = null,
context = null,
vars = null,
points = 8,
viscosity = 20,
mouseDist = 70,
damping = 0.05,
showIndicators = false;
mouseX = 0,
mouseY = 0,
relMouseX = 0,
relMouseY = 0,
mouseLastX = 0,
mouseLastY = 0,
mouseDirectionX = 0,
mouseDirectionY = 0,
mouseSpeedX = 0,
mouseSpeedY = 0;
/**
* Get mouse direction
*/
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
$(document).on('mousemove', mouseDirection);
/**
* Get mouse speed
*/
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
/**
* Init button
*/
function initButton() {
// Get button
var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth+100;
canvas.height = buttonHeight+100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
/**
* Add points
*/
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
/**
* Point
*/
function Point(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
/**
* Render canvas
*/
function renderCanvas() {
// rAF
rafID = requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width()/2, 2) + Math.pow(gradientY - $canvas.height()/2, 2)) / Math.sqrt(Math.pow($canvas.width()/2, 2) + Math.pow($canvas.height()/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
// Init
initButton();
});
body {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<a href="http://waaark.com" class="btn-liquid">
<span class="inner">Liquid button ?</span>
</a>
I wanted to put 2 of this lovely button on a same single webpage, but i succeeded only tu put 1 on the same page.
I think it's because of JS because of the name of the variables must be different. So i tried to rename all the variables for the second button but i didn't succeed. I'm a newbie in JS and i think i can't distinguish really what is a real variable than what is not in this script (which seems to have extremly lot of variables).
Could you help me to put 2 of this lovely button on the same webpage ?
PS: To go further :
To try to succeed i tried this pen : https://codepen.io/architechnium/pen/wpYgGY (we would call it the "2nd pen")
but it worked even more bad, for this pen i had only a white page with no button at all on my local webpage (althought i did it exactly as with the first pen).
But i think there is maybe a trick or something special with this 2nd pen because there is only 1 414 views for this one instead of 60 000+ for the first pen (which has only 1 button).
Thank you very much for your attention and thank you very much for your help ! :)
You need to add code twice for the second button. You can optimize the code. I am showing this way you can add two buttons.
$(function() {
// Vars
var pointsA = [],
pointsB = [],
$canvas = null,
canvas = null,
context = null,
vars = null,
points = 8,
viscosity = 20,
mouseDist = 70,
damping = 0.05,
showIndicators = false;
mouseX = 0,
mouseY = 0,
relMouseX = 0,
relMouseY = 0,
mouseLastX = 0,
mouseLastY = 0,
mouseDirectionX = 0,
mouseDirectionY = 0,
mouseSpeedX = 0,
mouseSpeedY = 0;
pointsA2 = [],
pointsB2 = [],
$canvas2 = null,
canvas2 = null,
context2 = null,
vars2 = null,
points2 = 8,
viscosity2 = 20,
mouseDist2 = 70,
damping2 = 0.05,
showIndicators2 = false;
mouseX2 = 0,
mouseY2 = 0,
relMouseX2 = 0,
relMouseY2 = 0,
mouseLastX2 = 0,
mouseLastY2 = 0,
mouseDirectionX2 = 0,
mouseDirectionY2 = 0,
mouseSpeedX2 = 0,
mouseSpeedY2 = 0;
/**
* Get mouse direction
*/
function mouseDirection(e) {
if (mouseX < e.pageX)
mouseDirectionX = 1;
else if (mouseX > e.pageX)
mouseDirectionX = -1;
else
mouseDirectionX = 0;
if (mouseY < e.pageY)
mouseDirectionY = 1;
else if (mouseY > e.pageY)
mouseDirectionY = -1;
else
mouseDirectionY = 0;
mouseX = e.pageX;
mouseY = e.pageY;
relMouseX = (mouseX - $canvas.offset().left);
relMouseY = (mouseY - $canvas.offset().top);
}
function mouseDirection2(e) {
if (mouseX2 < e.pageX)
mouseDirectionX2 = 1;
else if (mouseX2 > e.pageX)
mouseDirectionX2 = -1;
else
mouseDirectionX2 = 0;
if (mouseY2 < e.pageY)
mouseDirectionY2 = 1;
else if (mouseY2 > e.pageY)
mouseDirectionY2 = -1;
else
mouseDirectionY2 = 0;
mouseX2 = e.pageX;
mouseY2 = e.pageY;
relMouseX2 = (mouseX2 - $canvas2.offset().left);
relMouseY2 = (mouseY2 - $canvas2.offset().top);
}
$('.btn-grid-1').on('mousemove', mouseDirection);
$('.btn-grid-2').on('mousemove', mouseDirection2);
/**
* Get mouse speed
*/
function mouseSpeed() {
mouseSpeedX = mouseX - mouseLastX;
mouseSpeedY = mouseY - mouseLastY;
mouseLastX = mouseX;
mouseLastY = mouseY;
setTimeout(mouseSpeed, 50);
}
mouseSpeed();
function mouseSpeed2() {
mouseSpeedX2 = mouseX2 - mouseLastX2;
mouseSpeedY2 = mouseY2 - mouseLastY2;
mouseLastX2 = mouseX2;
mouseLastY2 = mouseY2;
setTimeout(mouseSpeed2, 50);
}
mouseSpeed2();
/**
* Init button
*/
function initButton() {
// Get button
var button = $('.btn-liquid');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas = $('<canvas></canvas>');
button.append($canvas);
canvas = $canvas.get(0);
canvas.width = buttonWidth+100;
canvas.height = buttonHeight+100;
context = canvas.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points; j++) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), 0);
}
addPoints(buttonWidth-buttonHeight/5, 0);
addPoints(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points-1; j > 0; j--) {
addPoints((x+((buttonWidth-buttonHeight)/points)*j), buttonHeight);
}
addPoints(buttonHeight/5, buttonHeight);
addPoints(-buttonHeight/10, buttonHeight/2);
addPoints(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas();
}
function initButton2() {
// Get button
var button = $('.btn-liquid-2');
var buttonWidth = button.width();
var buttonHeight = button.height();
// Create canvas
$canvas2 = $('<canvas></canvas>');
button.append($canvas2);
canvas2 = $canvas2.get(0);
canvas2.width = buttonWidth+100;
canvas2.height = buttonHeight+100;
context2 = canvas2.getContext('2d');
// Add points
var x = buttonHeight/2;
for(var j = 1; j < points2; j++) {
addPoints2((x+((buttonWidth-buttonHeight)/points2)*j), 0);
}
addPoints2(buttonWidth-buttonHeight/5, 0);
addPoints2(buttonWidth+buttonHeight/10, buttonHeight/2);
addPoints2(buttonWidth-buttonHeight/5, buttonHeight);
for(var j = points2-1; j > 0; j--) {
addPoints2((x+((buttonWidth-buttonHeight)/points2)*j), buttonHeight);
}
addPoints2(buttonHeight/5, buttonHeight);
addPoints2(-buttonHeight/10, buttonHeight/2);
addPoints2(buttonHeight/5, 0);
// addPoints(x, 0);
// addPoints(0, buttonHeight/2);
// addPoints(0, buttonHeight/2);
// addPoints(buttonHeight/4, 0);
// Start render
renderCanvas2();
}
/**
* Add points
*/
function addPoints(x, y) {
pointsA.push(new Point(x, y, 1));
pointsB.push(new Point(x, y, 2));
}
function addPoints2(x, y) {
pointsA2.push(new Point2(x, y, 1));
pointsB2.push(new Point2(x, y, 2));
}
/**
* Point
*/
function Point(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
function Point2(x, y, level) {
this.x = this.ix = 50+x;
this.y = this.iy = 50+y;
this.vx = 0;
this.vy = 0;
this.cx1 = 0;
this.cy1 = 0;
this.cx2 = 0;
this.cy2 = 0;
this.level = level;
}
Point.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity*this.level);
this.vy += (this.iy - this.y) / (viscosity*this.level);
var dx = this.ix - relMouseX,
dy = this.iy - relMouseY;
var relDist = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX > 0 && relMouseX > this.x) || (mouseDirectionX < 0 && relMouseX < this.x)) {
if (relDist > 0 && relDist < 1) {
this.vx = (mouseSpeedX / 4) * relDist;
}
}
this.vx *= (1 - damping);
this.x += this.vx;
// Move y
if ((mouseDirectionY > 0 && relMouseY > this.y) || (mouseDirectionY < 0 && relMouseY < this.y)) {
if (relDist > 0 && relDist < 1) {
this.vy = (mouseSpeedY / 4) * relDist;
}
}
this.vy *= (1 - damping);
this.y += this.vy;
};
Point2.prototype.move = function() {
this.vx += (this.ix - this.x) / (viscosity2*this.level);
this.vy += (this.iy - this.y) / (viscosity2*this.level);
var dx = this.ix - relMouseX2,
dy = this.iy - relMouseY2;
var relDist2 = (1-Math.sqrt((dx * dx) + (dy * dy))/mouseDist);
// Move x
if ((mouseDirectionX2 > 0 && relMouseX2 > this.x) || (mouseDirectionX2 < 0 && relMouseX2 < this.x)) {
if (relDist2 > 0 && relDist2 < 1) {
this.vx = (mouseSpeedX2 / 4) * relDist2;
}
}
this.vx *= (1 - damping2);
this.x += this.vx;
// Move y
if ((mouseDirectionY2 > 0 && relMouseY2 > this.y) || (mouseDirectionY2 < 0 && relMouseY2 < this.y)) {
if (relDist2 > 0 && relDist2 < 1) {
this.vy = (mouseSpeedY2 / 4) * relDist2;
}
}
this.vy *= (1 - damping2);
this.y += this.vy;
};
/**
* Render canvas
*/
function renderCanvas() {
// rAF
rafID = requestAnimationFrame(renderCanvas);
// Clear scene
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.fillStyle = '#fff';
context.fillRect(0, 0, $canvas.width(), $canvas.height());
// Move points
for (var i = 0; i <= pointsA.length - 1; i++) {
pointsA[i].move();
pointsB[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX - $canvas.offset().left, 0), $canvas.width());
var gradientY = Math.min(Math.max(mouseY - $canvas.offset().top, 0), $canvas.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas.width()/2, 2) + Math.pow(gradientY - $canvas.height()/2, 2)) / Math.sqrt(Math.pow($canvas.width()/2, 2) + Math.pow($canvas.height()/2, 2));
var gradient = context.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA, pointsB]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context.fillStyle = '#1CE2D8';
} else {
// Foreground style
context.fillStyle = gradient;
}
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context.fill();
}
if (showIndicators) {
// Draw points
context.fillStyle = '#000';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.x - 1, p.y - 1, 2, 2);
}
context.fill();
// Draw controls
context.fillStyle = '#f00';
context.beginPath();
for (var i = 0; i < pointsA.length; i++) {
var p = pointsA[i];
context.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context.fill();
}
}
function renderCanvas2() {
// rAF
rafID = requestAnimationFrame(renderCanvas2);
// Clear scene
context2.clearRect(0, 0, $canvas2.width(), $canvas2.height());
context2.fillStyle = '#fff';
context2.fillRect(0, 0, $canvas2.width(), $canvas2.height());
// Move points
for (var i = 0; i <= pointsA2.length - 1; i++) {
pointsA2[i].move();
pointsB2[i].move();
}
// Create dynamic gradient
var gradientX = Math.min(Math.max(mouseX2 - $canvas2.offset().left, 0), $canvas2.width());
var gradientY = Math.min(Math.max(mouseY2 - $canvas2.offset().top, 0), $canvas2.height());
var distance = Math.sqrt(Math.pow(gradientX - $canvas2.width()/2, 2) + Math.pow(gradientY - $canvas2.height()/2, 2)) / Math.sqrt(Math.pow($canvas2.width()/2, 2) + Math.pow($canvas2.height()/2, 2));
var gradient = context2.createRadialGradient(gradientX, gradientY, 300+(300*distance), gradientX, gradientY, 0);
gradient.addColorStop(0, '#102ce5');
gradient.addColorStop(1, '#E406D6');
// Draw shapes
var groups = [pointsA2, pointsB2]
for (var j = 0; j <= 1; j++) {
var points = groups[j];
if (j == 0) {
// Background style
context2.fillStyle = '#1CE2D8';
} else {
// Foreground style
context2.fillStyle = gradient;
}
context2.beginPath();
context2.moveTo(points[0].x, points[0].y);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var nextP = points[i + 1];
var val = 30*0.552284749831;
if (nextP != undefined) {
// if (nextP.ix > p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y-val;
// p.cx2 = nextP.x-val;
// p.cy2 = nextP.y;
// } else if (nextP.ix > p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x+val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y-val;
// } else if (nextP.ix < p.ix && nextP.iy > p.iy) {
// p.cx1 = p.x;
// p.cy1 = p.y+val;
// p.cx2 = nextP.x+val;
// p.cy2 = nextP.y;
// } else if (nextP.ix < p.ix && nextP.iy < p.iy) {
// p.cx1 = p.x-val;
// p.cy1 = p.y;
// p.cx2 = nextP.x;
// p.cy2 = nextP.y+val;
// } else {
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
p.cx2 = (p.x+nextP.x)/2;
p.cy2 = (p.y+nextP.y)/2;
context2.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
// continue;
// }
// context.bezierCurveTo(p.cx1, p.cy1, p.cx2, p.cy2, nextP.x, nextP.y);
} else {
nextP = points[0];
p.cx1 = (p.x+nextP.x)/2;
p.cy1 = (p.y+nextP.y)/2;
context2.bezierCurveTo(p.x, p.y, p.cx1, p.cy1, p.cx1, p.cy1);
}
}
// context.closePath();
context2.fill();
}
if (showIndicators2) {
// Draw points
context2.fillStyle = '#000';
context2.beginPath();
for (var i = 0; i < pointsA2.length; i++) {
var p = pointsA2[i];
context2.rect(p.x - 1, p.y - 1, 2, 2);
}
context2.fill();
// Draw controls
context2.fillStyle = '#f00';
context2.beginPath();
for (var i = 0; i < pointsA2.length; i++) {
var p = pointsA2[i];
context2.rect(p.cx1 - 1, p.cy1 - 1, 2, 2);
context2.rect(p.cx2 - 1, p.cy2 - 1, 2, 2);
}
context2.fill();
}
}
// Init
initButton();
initButton2();
});
body {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.btn-liquid, .btn-liquid-2 {
display: inline-block;
position: relative;
width: 240px;
height: 60px;
border-radius: 27px;
color: #fff;
font: 700 14px/60px "Droid Sans", sans-serif;
letter-spacing: 0.05em;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.btn-liquid .inner, .btn-liquid-2 .inner {
position: relative;
z-index: 2;
}
.btn-liquid canvas, .btn-liquid-2 canvas {
position: absolute;
top: -50px;
right: -50px;
bottom: -50px;
left: -50px;
z-index: 1;
}
.btn-grid{width: 50%;padding: 0 50px}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="btn-grid btn-grid-1">
<a href="http://waaark.com" class="btn-liquid">
<span class="inner">Liquid button ?</span>
</a>
</div>
<div class="btn-grid btn-grid-2">
<a href="http://waaark.com" class="btn-liquid-2">
<span class="inner">Liquid button ?</span>
</a>
</div>
</body>
</html>

Javascript won't draw the animation taking value from HTML input element

I wanted to create physics simulation with dropping ball. To have more fun I wanted to give to user an access to input his values of dropping ball radius and count. If you would run this code on browser, you could click button 'CREATE' to display animation with default values and it would have worked. When I enter balls count in html input element, it recognises the count and executes the code and the animation appears. When I enter radius value in html input element, nothing appears on canvas. I find this as very strange problem. I've already tried renaming variables and element id names. When I I would appreciate if anyone could help.
The html file called index.html
const canvas = document.getElementById('ball-platform');
const createBtn = document.getElementById('createAnimation');
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext('2d');
const gravity = 0.15;
const friction = 0.9;
let balls = [];
function FillCircle(x0, y0, bRadius, theColor) {
let circle = {
x: x0,
y: y0,
color: theColor
};
let xVel = 5,
yVel = 1;
this.movement = () => {
if (Math.round(circle.x + bRadius + xVel) > W || Math.round(circle.x - bRadius + xVel) < 0) {
xVel = -xVel * friction;
yVel *= friction;
} else if (Math.round(circle.y + bRadius + yVel) > H) {
yVel = -yVel * friction;
xVel *= friction;
} else {
yVel += gravity;
}
circle.x += xVel;
circle.y += yVel;
}
this.draw = () => {
ctx.beginPath();
ctx.fillStyle = circle.color;
ctx.ellipse(circle.x, circle.y, bRadius, bRadius, -90 * Math.PI / 180, 360 * Math.PI / 180, false);
ctx.fill();
ctx.stroke();
}
}
createBtn.addEventListener('mousedown', () => {
balls = [];
let bRadius = document.getElementById('bRadius').value;
let count = document.getElementById('count').value;
if (bRadius == "" || bRadius <= 0) {
bRadius = 5;
}
if (count == "" || count < 0) {
count = 5;
}
initialize(count, bRadius);
});
function initialize(count, bRadius) {
for (let i = 0; i < count; i++) {
let xpos = (Math.random() * (W - bRadius - 10)) + bRadius;
let ypos = (Math.random() * (H - bRadius - 10)) + bRadius;
balls.push(new FillCircle(xpos, ypos, bRadius, 'red'));
}
}
function animation() {
requestAnimationFrame(animation);
ctx.clearRect(0, 0, W, H);
for (let a = 0; a < balls.length; a++) {
let circle = balls[a];
circle.movement();
circle.draw();
}
}
animation();
<nav style='display: block;'>
<button id='createAnimation'>CREATE</button>
<input placeholder='Radius' , id='bRadius'>
<input placeholder='Count' id='count'>
</nav>
<canvas id="ball-platform" width="500" height="500" style="border: 1px solid black"></canvas>
I think you need to convert the input values to numbers,
const canvas = document.getElementById('ball-platform');
const createBtn = document.getElementById('createAnimation');
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext('2d');
const gravity = 0.15;
const friction = 0.9;
let balls = [];
function FillCircle(x0, y0, bRadius, theColor) {
let circle = {
x: x0,
y: y0,
color: theColor
};
let xVel = 5,
yVel = 1;
this.movement = () => {
if (Math.round(circle.x + bRadius + xVel) > W || Math.round(circle.x - bRadius + xVel) < 0) {
xVel = -xVel * friction;
yVel *= friction;
} else if (Math.round(circle.y + bRadius + yVel) > H) {
yVel = -yVel * friction;
xVel *= friction;
} else {
yVel += gravity;
}
circle.x += xVel;
circle.y += yVel;
}
this.draw = () => {
ctx.beginPath();
ctx.fillStyle = circle.color;
ctx.ellipse(circle.x, circle.y, bRadius, bRadius, -90 * Math.PI / 180, 360 * Math.PI / 180, false);
ctx.fill();
ctx.stroke();
}
}
createBtn.addEventListener('mousedown', () => {
balls = [];
let bRadius = parseInt(document.getElementById('bRadius').value);
let count = parseInt(document.getElementById('count').value);
if (bRadius == "" || bRadius <= 0) {
bRadius = 5;
}
if (count == "" || count < 0) {
count = 5;
}
initialize(count, bRadius);
});
function initialize(count, bRadius) {
for (let i = 0; i < count; i++) {
let xpos = (Math.random() * (W - bRadius - 10)) + bRadius;
let ypos = (Math.random() * (H - bRadius - 10)) + bRadius;
balls.push(new FillCircle(xpos, ypos, bRadius, 'red'));
}
}
function animation() {
requestAnimationFrame(animation);
ctx.clearRect(0, 0, W, H);
for (let a = 0; a < balls.length; a++) {
let circle = balls[a];
circle.movement();
circle.draw();
}
}
animation();
<nav style='display: block;'>
<button id='createAnimation'>CREATE</button>
<input placeholder='Radius' , id='bRadius'>
<input placeholder='Count' id='count'>
</nav>
<canvas id="ball-platform" width="500" height="500" style="border: 1px solid black"></canvas>

How can I make the ball bounce off the red bricks without it (the red brick) breaking? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
So basically I want the red bricks to have an extra bounce (but not the blue ones). It means if I hit it once the red brick reflects the ball without it disappearing but when I hit it the second time it does. Thank you in advance.
<!DOCTYPE html>
<html>
<head>
<title>Breakout_Game</title>
</head>
<body>
<canvas id="myCanvas" width="800" height="600"></canvas>
<script type="text/javascript">
var canvas, canvasContext;
var ballX = 75, ballY = 75;
var ballSpeedX = 3, ballSpeedY = 3;
var ballR = 7;
const brickW = 80;
const brickH = 20;
const brickCols = Math.floor(800 / brickW);
const brickRows = Math.floor(600 / (brickH * 3));
const brickGap = 1;
var brickGrid = new Array(brickCols * brickRows);
var bricksLeft = 0;
const paddleW = 100, paddleH = 10;
var paddleX = 400, paddleY = 600;
const distanceBP = 60;
var mouseX, mouseY;
function updateMousePos (evt) {
var rect = canvas.getBoundingClientRect(); // this is for adjustments only (getting the mouse coordinates even if the page is scrollable)
var root = document.documentElement;
mouseX = evt.clientX - rect.left - root.scrollLeft; // clientX is the X of mouse
mouseY = evt.clientY - rect.top - root.scrollTop;
paddleX = mouseX - paddleW/2;
/* //Cheats Help debugging
ballX = mouseX;
ballY = mouseY;*/
}
function brickReset () {
bricksLeft = 0;
var i;
for(i = 0; i < 3 * brickCols; i++) {
brickGrid[i] = false;
}
for (; i < brickCols * brickRows; i++) {
brickGrid[i] = true;
bricksLeft++;
}
randBrickColor();
}
window.onload = function () {
canvas = document.getElementById("myCanvas");
canvasContext = canvas.getContext("2d");
var fps = 60;
setInterval(updateAll, 1000 / fps);
canvas.addEventListener("mousemove", updateMousePos); // everytime the mouse moves we call the function updateMousePos()
brickReset();
ballReset();
}
function updateAll () {
drawAll();
moveAll();
}
function ballReset () {
ballX = canvas.width / 2;
ballY = canvas.height / 2;
}
function ballMove () {
ballX += ballSpeedX;
ballY += ballSpeedY;
//COLLISION
//left
if (ballX - ballR < 0 && ballSpeedX < 0.0) {
ballSpeedX = -ballSpeedX;
}
//right
if (ballX + ballR > canvas.width && ballSpeedX > 0.0) {
ballSpeedX = -ballSpeedX;
}
//top
if (ballY - ballR < 0 && ballSpeedY < 0.0) {
ballSpeedY = -ballSpeedY;
}
//bottom
if (ballY > canvas.height) {
ballReset();
brickReset();
}
}
function isBrickAtColRow (col, row) {
if (col >= 0 && col < brickCols && row >= 0 && row < brickRows) {
var brickIndexUnderCoord = rowColToArrayIndex(col, row);
return brickGrid[brickIndexUnderCoord];
} else {
return false;
}
}
function ballBrickHandling () {
var ballBrickCol = Math.floor(ballX / brickW);
var ballBrickRow = Math.floor(ballY / brickH);
var brickIndexUnderBall = rowColToArrayIndex(ballBrickCol, ballBrickRow);
if (brickIndexUnderBall >= 0 && brickIndexUnderBall < brickCols * brickRows) {
if (isBrickAtColRow( ballBrickCol,ballBrickRow)) {
brickGrid[brickIndexUnderBall] = false;
bricksLeft--;
//console.log( bricksLeft)
var prevBallX = ballX - ballSpeedX;
var prevBallY = ballY - ballSpeedY;
var prevBrickCol = Math.floor(prevBallX / brickW);
var prevBrickRow = Math.floor(prevBallY / brickH);
var bothTestsFailed = true;
if (prevBrickCol != ballBrickCol) {
if (isBrickAtColRow(prevBrickCol, ballBrickRow) == false) {
ballSpeedX = -ballSpeedX;
bothTestsFailed = false;
}
}
if (prevBrickRow != ballBrickRow) {
if (isBrickAtColRow(ballBrickCol, prevBrickRow) == false) {
ballSpeedY = -ballSpeedY;
bothTestsFailed = false;
}
}
if (bothTestsFailed) {
ballSpeedX = -ballSpeedX;
ballSpeedY = -ballSpeedY;
}
}
}
}
function ballPaddleHandling () {
var paddleTopEdgeY = canvas.height - distanceBP;
var paddleBottomEdgeY = paddleTopEdgeY + paddleH;
var paddleLeftEdgeX = paddleX;
var paddleRightEdgeX = paddleLeftEdgeX + paddleW;
if (ballY + ballR > paddleTopEdgeY &&
ballY - ballR < paddleBottomEdgeY &&
ballX + ballR > paddleLeftEdgeX &&
ballX - ballR < paddleRightEdgeX
) {
ballSpeedY *= -1;
var centerOfPaddleX = paddleX + paddleW / 2;
var ballDistFromPadlleCenterX = ballX - centerOfPaddleX;
ballSpeedX = ballDistFromPadlleCenterX * 0.2;
if (bricksLeft == 0) {
brickReset();
}
}
}
function moveAll () {
//console.log("X: " + ballSpeedX,"Y: " + ballSpeedY);
ballMove();
ballBrickHandling();
ballPaddleHandling();
}
function rowColToArrayIndex (col, row) {
return col + brickCols * row;
}
// Random COLOR
var brickColors = [];
function randBrickColor () {
for (var eachRow = 0; eachRow < brickRows; eachRow++) {
brickColors[eachRow] = [];
for (var eachCol = 0; eachCol < brickCols; eachCol++) {
if (Math.random() > 0.7) {
brickColors[eachRow][eachCol] = "red";
} else {
brickColors[eachRow][eachCol] = "blue";
}
}
}
}
//end of Random COLOR
function drawBricks () {
for (var eachRow = 0; eachRow < brickRows; eachRow++) {
for (var eachCol = 0; eachCol < brickCols; eachCol++) {
var arrayIndex = brickCols * eachRow + eachCol;
if (brickGrid[arrayIndex]) {
colorRect(brickW * eachCol, brickH * eachRow, brickW-brickGap, brickH-brickGap, brickColors[eachRow][eachCol]);
}
}
}
}
function drawAll () {
// Black Screen
colorRect(0,0, canvas.width, canvas.height, "black");
// Ball
colorCircle(ballX,ballY, ballR, "white");
// Paddle
colorRect(paddleX, paddleY - distanceBP, paddleW, paddleH, "white");
// Bricks
drawBricks();
// Position of the mouse
colorText(mouseX+","+mouseY, mouseX,mouseY, "yellow");
}
function colorRect (topLeftX, topLeftY, boxWidth, boxHeight, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.fillRect(topLeftX, topLeftY, boxWidth, boxHeight);
}
function colorCircle(centerX, centerY, radius, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.beginPath();
canvasContext.arc(centerX, centerY, radius, 0, Math.PI * 2, true);
canvasContext.fill();
}
function colorText(showWords, textX, textY, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.fillText(showWords, textX, textY);
}
</script>
</body>
</html>
in ballBrickHandling() replace
brickGrid[brickIndexUnderBall] = false;
bricksLeft--;
with
if(brickColors[ballBrickRow][ballBrickCol] != "red") {
brickGrid[brickIndexUnderBall] = false;
bricksLeft--;
} else brickColors[ballBrickRow][ballBrickCol] = "blue"

Categories

Resources