How to stop line colouring over transparent canvas? - javascript

I need some expert help. When I make canvas background transparent the line colors the whole canvas (shown in code below).
How do I stop/fix this? I want the line stay as a single line that doesn't color the canvas.
Math.clamp = function(x, min, max) {
return x < min ? min : (x > max ? max : x);
};
// canvas settings
var viewWidth = window.innerWidth,
viewHeight = window.innerHeight,
drawingCanvas = document.getElementById("drawing_canvas"),
ctx,
timeStep = (10 / 100),
time = 0;
var lineTension = 0.067,
lineDamping = 0.068,
waveSpreadFactor = 0.1;
var previousMousePosition = {
x: 0,
y: 0
},
currentMousePosition = {
x: 0,
y: 0
},
actualMousePosition = {
x: 0,
y: 0
};
var line,
lineSegmentCount = 64,
lineMaxForce = 32,
lineStrokeGradient;
var audioCtx,
nodeCount = 64,
oscillatorNodes = [],
gainNodes = [];
var segmentsPerNode = lineSegmentCount / nodeCount;
function initGui() {
}
function goBananas() {
lineTension = 0.2;
line.anchors[Math.floor(Math.random() * line.anchors.length)].
vel = lineMaxForce;
}
function resetLine() {
line.reset();
for (var i = 0; i < nodeCount; i++) {
oscillatorNodes[i].detune.value = 100;
gainNodes[i].gain.value = 0;
}
lineTension = 0.0025;
lineDamping = 0.05;
waveSpreadFactor = 0.1;
}
function initDrawingCanvas() {
drawingCanvas.width = viewWidth;
drawingCanvas.height = viewHeight;
window.addEventListener('resize', resizeHandler);
window.addEventListener('mousemove', mouseMoveHandler);
setInterval(updateMousePosition, (1000 / 30));
ctx = drawingCanvas.getContext('2d');
ctx.lineWidth = 5;
line = new Line(0, viewHeight * 0.5, viewWidth, lineSegmentCount);
// line.anchors[0].vel = viewHeight * 0.25;
lineStrokeGradient = ctx.createLinearGradient(0, 0, 0, viewHeight);
lineStrokeGradient.addColorStop(0, '#0ff');
}
function initWebAudio() {
audioCtx = new(window.AudioContext || window.webkitAudioContext)();
for (var i = 0; i < nodeCount; i++) {
var oscillatorNode = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
oscillatorNode.connect(gainNode);
gainNode.connect(audioCtx.destination);
gainNode.gain.value = 0;
oscillatorNode.type = 'saw';
oscillatorNode.detune.value = 200;
oscillatorNode.frequency.value = 1200 * (i / 60);
oscillatorNode.start();
oscillatorNodes[i] = oscillatorNode;
gainNodes[i] = gainNode;
}
}
function resizeHandler() {
drawingCanvas.width = viewWidth = window.innerWidth;
drawingCanvas.height = viewHeight = window.innerHeight;
if (ctx) {
ctx.lineWidth = 4;
line.resize(viewWidth, viewHeight * 0.5);
}
}
function mouseMoveHandler(event) {
actualMousePosition.x = Math.floor(event.clientX);
actualMousePosition.y = Math.floor(event.clientY);
}
function updateMousePosition() {
previousMousePosition.x = currentMousePosition.x;
previousMousePosition.y = currentMousePosition.y;
currentMousePosition.x = actualMousePosition.x;
currentMousePosition.y = actualMousePosition.y;
}
function update() {
var px = Math.min(previousMousePosition.x, currentMousePosition.x),
py = Math.min(previousMousePosition.y, currentMousePosition.y),
pw = Math.max(1, Math.abs(previousMousePosition.x - currentMousePosition.x)),
ph = Math.max(1, Math.abs(previousMousePosition.y - currentMousePosition.y)),
force = Math.clamp(currentMousePosition.y -
previousMousePosition.y, -lineMaxForce, lineMaxForce);
var pixels = ctx.getImageData(px, py, pw, ph),
data = pixels.data;
for (var i = 0; i < data.length; i += 3) {
var r = data[i + 0],
g = data[i + 1],
b = data[i + 2],
x = (i % ph) + px;
if (r + g + b > 0) {
line.ripple(x, force);
}
}
line.update();
for (var j = 0; j < gainNodes.length; j++) {
var anchor = line.anchors[j * segmentsPerNode],
gain = Math.clamp(Math.abs(anchor.vel) / viewHeight * 0.5, 0, 3),
detune = Math.clamp(anchor.pos / viewHeight * 100, 0, 300);
gainNodes[j].gain.value = gain;
oscillatorNodes[j].detune.value = detune;
}
}
function draw() {
ctx.strokeStyle = lineStrokeGradient;
line.draw();
}
window.onload = function() {
initDrawingCanvas();
initWebAudio();
initGui();
requestAnimationFrame(loop);
};
function loop() {
update();
draw();
time += timeStep;
requestAnimationFrame(loop);
}
Line = function(x, y, length, segments) {
this.x = x;
this.y = y;
this.length = length;
this.segments = segments;
this.segmentLength = this.length / this.segments;
this.anchors = [];
for (var i = 0; i <= this.segments; i++) {
this.anchors[i] = {
target: this.y,
pos: this.y,
vel: 0,
update: function() {
var dy = this.pos - this.target,
acc = -lineTension * dy - lineDamping * this.vel;
this.pos += this.vel;
this.vel += acc;
},
reset: function() {
this.pos = this.target;
this.vel = 0;
}
};
}
};
Line.prototype = {
resize: function(length, targetY) {
this.length = length;
this.segmentLength = this.length / this.segments;
for (var i = 0; i <= this.segments; i++) {
this.anchors[i].target = targetY;
}
},
reset: function() {
for (var i = 0; i <= this.segments; i++) {
this.anchors[i].reset();
}
},
ripple: function(origin, amplitude) {
var i = Math.floor((origin - this.x) / this.segmentLength);
if (i >= 0 && i <= this.segments) {
this.anchors[i].vel = amplitude;
}
},
update: function() {
var lDeltas = [],
rDeltas = [],
i;
for (i = 0; i <= this.segments; i++) {
this.anchors[i].update();
}
for (i = 0; i <= this.segments; i++) {
if (i > 0) {
lDeltas[i] = waveSpreadFactor * (this.anchors[i].pos - this.anchors[i - 1].pos);
this.anchors[i - 1].vel += lDeltas[i];
}
if (i < this.segments) {
rDeltas[i] = waveSpreadFactor * (this.anchors[i].pos - this.anchors[i + 1].pos);
this.anchors[i + 1].vel += rDeltas[i];
}
}
for (i = 0; i <= this.segments; i++) {
if (i > 0) {
this.anchors[i - 1].pos += lDeltas[i];
}
if (i < this.segments) {
this.anchors[i + 1].pos += rDeltas[i];
}
}
},
draw: function() {
ctx.beginPath();
for (var i = 0; i <= this.segments; i++) {
ctx.lineTo(
this.x + this.segmentLength * i,
this.anchors[i].pos
);
}
ctx.stroke();
}
};

From the code you posted, the problem seems to be a missing
ctx.clearRect(0, 0, viewWidth, viewHeight)
at the beginning of your "draw" function.
See a working example here

Related

Need help optimizing my Javascript for canvas rendering

I've written this quick script for random moving lines for the background for my portfolio. It works smoothly alone but when I start working with other CSS animations and stuff, there's a frame drop at the beginning (later it runs smooth). At least on my PC, struggles on low-end PC.
Some tips to optimize it would be helpful.
Here's my code:
/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];
var ctx = c.getContext("2d");
var ctx2 = c.getContext("2d");
var posx = [100, 200, 150, 100, 0];
var posy = [100, 200, 300, 100, -100];
var posx2 = [600, 400, 200, 600];
var posy2 = [500, 200, 100, 150, 500, 500];
var posx3 = [];
var posy3 = [];
/*Generate random values for array( random starting point ) */
for (var i = 0; i < 2; i++) {
posx2.push(500 + Math.round(Math.random() * 700));
posy2.push(Math.round(Math.random() * 900));
}
for (var i = 0; i < 5; i++) {
posx3.push(1000 + Math.round(Math.random() * 300));
posy3.push(0 + Math.round(Math.random() * 1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa, ya;
var opa = 1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
document.body.addEventListener('mousemove', (function(event) {
xa = event.clientX;
ya = event.clientY;
}));
/*Render Lines */
function draw() {
ctx.clearRect(0, 0, 10000, 10000);
ctx.beginPath();
ctx.moveTo(posx[0], posy[0]);
for (var i = 0; i < posx_len; i++) {
ctx.lineTo(posx[i], posy[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx[i], posy[i], 5, 0, 2 * Math.PI, false);
}
if (opa > 1) {
amount = -0.01 * Math.random();
}
if (opa < 0) {
amount = 0.01 * Math.random();
}
opa = opa + amount;
ctx.moveTo(posx2[0], posy2[0]);
for (var i = 0; i < posx2_len; i++) {
ctx.lineTo(posx2[i], posy2[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx2[i], posy2[i], 5, 0, 2 * Math.PI, false);
}
ctx.moveTo(posx3[0], posy3[0]);
for (var i = 0; i < posx3_len; i++) {
ctx.lineTo(posx3[i], posy3[i]);
ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
ctx.stroke();
ctx.arc(posx3[i], posy3[i], 5, 0, 2 * Math.PI, false);
}
sinang = sinang + 0.01;
/*Frame Render Ends here*/
/*Calculation for next frame*/
for (var i = 0; i < posx_len; i++) {
posx[i] = posx[i] + (Math.cos(sinang) * i) / 2; /* Sin curve for smooth value transition. Smooth assss Butter */
posy[i] = posy[i] + (Math.cos(sinang) * i) / 2;
/* Can't believe Distance Formula is useful ahaha */
distance1 = Math.sqrt(Math.pow((posx[i] - xa), 2) + Math.pow((posy[i] - ya), 2));
if (distance1 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(xa, ya);
}
for (var j = 0; j < posx2_len; j++) {
distance12 = Math.sqrt(Math.pow((posx[i] - posx2[j]), 2) + Math.pow((posy[i] - posy2[j]), 2));
if (distance12 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(posx2[j], posy2[j]);
}
}
for (var j = 0; j < posx3_len; j++) {
distance13 = Math.sqrt(Math.pow((posx[i] - posx3[j]), 2) + Math.pow((posy[i] - posy3[j]), 2));
if (distance13 <= 500) {
ctx.moveTo(posx[i], posy[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx[posx.length - 1] = posx[0];
posy[posy.length - 1] = posy[0];
/*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
for (var i = 0; i < posx2_len; i++) {
posx2[i] = posx2[i] + (Math.sin(sinang) * i) / 2;
posy2[i] = posy2[i] - (Math.sin(sinang) * i) / 2;
distance2 = Math.sqrt(Math.pow((posx2[i] - xa), 2) + Math.pow((posy2[i] - ya), 2));
if (distance2 <= 500) {
ctx.moveTo(posx2[i], posy2[i]);
ctx.lineTo(xa, ya);
}
for (var j = 0; j < posx3_len; j++) {
distance22 = Math.sqrt(Math.pow((posx2[i] - posx3[j]), 2) + Math.pow((posy2[i] - posy3[j]), 2));
if (distance22 <= 500) {
ctx.moveTo(posx2[i], posy2[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx2[posx2.length - 1] = posx2[0];
posy2[posy2.length - 1] = posy2[0];
for (var i = 0; i < posx3_len; i++) {
posx3[i] = posx3[i] - (Math.sin(sinang) * i) / 1.2;
posy3[i] = posy3[i] - (Math.sin(sinang) * i) / 1.2;
distance2 = Math.sqrt(Math.pow((posx3[i] - xa), 2) + Math.pow((posy3[i] - ya), 2));
if (distance2 <= 500) {
ctx.moveTo(posx3[i], posy3[i]);
ctx.lineTo(xa, ya);
}
}
posx3[posx3.length - 1] = posx3[0];
posy3[posy3.length - 1] = posy3[0];
ctx.restore();
ctx.stroke();
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
body {
background: #1f1f1f;
}
<canvas height="1080px" width="1100px" id="graph">
</canvas>
So, what I've done is used square colliders instead of circular(distance formula) and it has faster runtime now. (not much but still)
<html>
<head>
</head>
<style>
body{
background: #1f1f1f;
}
canvas{
}
</style>
<body >
<canvas height="1080px" width="1100px" id="graph">
</canvas>
</body>
<script>
/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];
var ctx = c.getContext("2d");
var posx = [100,200,150,100,0];
var posy = [100,200,300,100,-100];
var posx2 = [600,400,200,600];
var posy2 = [500,200,100,150,500,500];
var posx3 = [];
var posy3 = [];
/*Generate random values for array( random starting point ) */
for(var i=0; i<2;i++){
posx2.push(500+Math.round(Math.random()*700));
posy2.push(Math.round(Math.random()*900));
}
for(var i=0; i<5;i++){
posx3.push(1000+Math.round(Math.random()*300));
posy3.push(0+Math.round(Math.random()*1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa,ya;
var opa =1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
var t1, t2;
document.body.addEventListener('mousemove', (function (event) {
xa = event.clientX;
ya = event.clientY;
}));
/*Render Lines */
function draw(){
t1 =performance.now();
ctx.clearRect(0, 0, 1920,1080);
ctx.beginPath();
ctx.moveTo(posx[0], posy[0]);
for(var i= 0; i<posx_len;i++){
ctx.lineTo(posx[i], posy[i]);
ctx.arc(posx[i],posy[i], 5, 0, 2 * Math.PI, false);
}
if(opa>1){
amount = -0.01*Math.random();
}
if(opa<0){
amount =0.01*Math.random();
}
opa =opa +amount;
ctx.moveTo(posx2[0], posy2[0]);
for(var i = 0; i<posx2_len;i++){
ctx.lineTo(posx2[i], posy2[i]);
ctx.arc(posx2[i],posy2[i], 5, 0, 2 * Math.PI, false);
}
ctx.moveTo(posx3[0], posy3[0]);
for(var i = 0; i<posx3_len;i++){
ctx.lineTo(posx3[i], posy3[i]);
ctx.arc(posx3[i],posy3[i], 5, 0, 2 * Math.PI, false);
}
sinang = sinang+0.01;
/*Frame Render Ends here*/
/*Calculation for next frame*/
for(var i = 0;i<posx_len;i++){
posx[i] = posx[i]+ (Math.cos(sinang)*i)/2;/* Sin curve for smooth value transition. Smooth assss Butter */
posy[i] = posy[i]+ (Math.cos(sinang)*i)/2;
/* Can't believe Distance Formula is useful ahaha */
if(Math.abs(posx[i]-xa)<500 && Math.abs(posy[i]-ya)<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(xa, ya);
}
for(var j = 0;j<posx2_len;j++){
if(Math.abs(posx[i]-posx2[j])<500 && Math.abs(posy[i]-posy2[j])<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(posx2[j], posy2[j]);
}
}
for(var j = 0;j<posx3_len;j++){
if(Math.abs(posx[i]-posx3[j])<500 && Math.abs(posy[i]-posy3[j])<500){
ctx.moveTo(posx[i],posy[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx[posx.length-1]=posx[0];
posy[posy.length-1] = posy[0];
/*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
for(var i = 0;i<posx2_len;i++){
posx2[i] = posx2[i]+ (Math.sin(sinang)*i)/2;
posy2[i] = posy2[i]-(Math.sin(sinang)*i)/2;
if(Math.abs(posx2[i]-xa)<500 && Math.abs(posy2[i]-ya)<500){
ctx.moveTo(posx2[i],posy2[i]);
ctx.lineTo(xa, ya);
}
for(var j = 0;j<posx3_len;j++){
if(Math.abs(posx2[i]-posx3[j])<500 && Math.abs(posy2[i]-posy3[j])<500){
ctx.moveTo(posx2[i],posy2[i]);
ctx.lineTo(posx3[j], posy3[j]);
}
}
}
posx2[posx2.length-1]=posx2[0];
posy2[posy2.length-1] = posy2[0];
for(var i = 0;i<posx3_len;i++){
posx3[i] = posx3[i]- (Math.sin(sinang)*i)/1.2;
posy3[i] = posy3[i]-(Math.sin(sinang)*i)/1.2;
if(Math.abs(posx3[i]-xa)<500 && Math.abs(posy3[i]-ya)<500){
ctx.moveTo(posx3[i],posy3[i]);
ctx.lineTo(xa, ya);
}
}
posx3[posx3.length-1]=posx3[0];
posy3[posy3.length-1] = posy3[0];
ctx.restore();
ctx.strokeStyle = 'rgba(255,255,255,'+opa+')';
ctx.stroke();
window.requestAnimationFrame(draw);
t2=performance.now();
console.log(t2-t1);
}
window.requestAnimationFrame(draw);
</script>
</html>

An error in the checkers code, how to fix it?

Made a small game, the main goal is to remove all the pieces by jumping over the checkers. The first time it is possible to remove the checker, the second time it gives an error?
Uncaught TypeError: Cannot read property 'theRow' of undefined
On line 180. I looked at the line, here it is.
Code:
Point = function(x, y) {
this.x = x;
this.y = y;
}
window.onload = function() {
var canvas;
var context;
var BB;
var offsetX;
var offsetY;
var dragok = false;
var startX;
var startY;
var oldX, oldY;
var fieldArray = [
[1, 0, 1, 1, 0, 0],
[1, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 0, 0]
];
var shapes = [];
var possibleLandings = [];
var localX, localY;
var pickedMonster;
var sx = 0;
var sy = 0;
var i1 = 0;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
context.lineWidth = 1;
context.strokeRect(j * 60, i * 60, 60, 60);
context.fillRect(j * 60, i * 60, 60, 60);
}
}
for (var i = 0; i < shapes.length; i++) {
circle(shapes[i]);
}
context.restore();
if (possibleLandings.length > 0) {
context.save();
context.fillStyle = "#4CFF00";
context.fillRect(oldX, oldY, 20, 20);
context.restore();
} else {
context.save();
context.fillStyle = "#FF0000";
context.fillRect(oldX, oldY, 20, 20);
context.restore();
}
}
function circle(c) {
context.fillStyle = c.fill;
context.beginPath();
context.arc(c.x, c.y, c.r, 0, Math.PI * 2);
context.closePath();
context.fill();
}
function myDown(e) {
e.preventDefault();
e.stopPropagation();
var mx = parseInt(e.clientX - offsetX);
var my = parseInt(e.clientY - offsetY);
dragok = false;
for (var i = 0; i < shapes.length; i++) {
var s = shapes[i];
var dx = s.x - mx;
var dy = s.y - my;
if (dx * dx + dy * dy < s.r * s.r) {
dragok = true;
s.isDragging = true;
pickedMonster = {
x: s.x,
y: s.y,
i: i,
theRow: s.theRow,
theCol: s.theCol
};
oldX = s.x;
oldY = s.y;
localX = mx - s.x + (30 / 2);
localY = my - s.y + (30 / 2);
checkMonster(s);
canvas.onmousemove = moveMonster;
canvas.onmouseup = dropMonster;
}
}
startX = mx;
startY = my;
}
function moveMonster(e) {
if (dragok) {
e.preventDefault();
e.stopPropagation();
var mx = parseInt(e.clientX - offsetX);
var my = parseInt(e.clientY - offsetY);
var dx = mx - startX;
var dy = my - startY;
for (var i = 0; i < shapes.length; i++) {
var s = shapes[i];
if (s.isDragging) {
s.x += dx;
s.y += dy;
pickedMonster.x = e.clientX - localX;
pickedMonster.y = e.clientY - localY;
}
}
draw();
startX = mx;
startY = my;
}
}
function dropMonster(e) {
e.preventDefault();
e.stopPropagation();
var legalMove = false;
var dropX = Math.floor((pickedMonster.x + 30) / 60);
var dropY = Math.floor((pickedMonster.y + 30) / 60);
console.log(dropX);
for (var i = 0; i < possibleLandings.length; i++) {
if (possibleLandings[i].x == dropY && possibleLandings[i].y == dropX) {
legalMove = true;
break;
}
}
if (!legalMove) {
shapes[pickedMonster.i].x = oldX;
shapes[pickedMonster.i].y = oldY;
} else {
var rowOffset = (dropY - pickedMonster.theRow) / 2;
var colOffset = (dropX - pickedMonster.theCol) / 2;
fieldArray[pickedMonster.theRow][pickedMonster.theCol] = 0;
fieldArray[pickedMonster.theRow + rowOffset][pickedMonster.theCol + colOffset] = 0;
fieldArray[pickedMonster.theRow + 2 * rowOffset][pickedMonster.theCol + 2 * colOffset] = 1;
for (i = 0; i < 5; i++) {
var currentMonster = shapes[i];
if (currentMonster.theRow == pickedMonster.theRow + rowOffset &&
currentMonster.theCol == pickedMonster.theCol + colOffset) {
shapes.splice(i, 1);
}
}
}
dragok = false;
for (var i = 0; i < shapes.length; i++) {
shapes[i].isDragging = false;
}
draw();
}
function checkMonster(s) {
for (var i = 0; i < 4; i++) {
var deltaRow = (1 - i) * (i % 2 - 1);
var deltaCol = (2 - i) * (i % 2);
if (checkField(s, deltaRow, deltaCol)) {
possibleLandings.push(new Point(s.theRow + 2 * deltaRow, s.theCol + 2 * deltaCol));
}
}
}
function checkField(s, rowOffset, colOffset) {
if (fieldArray[s.theRow + 2 * rowOffset] != undefined &&
fieldArray[s.theRow + 2 * rowOffset][s.theCol + 2 * colOffset] != undefined) {
if (fieldArray[s.theRow + rowOffset][s.theCol + colOffset] == 1 &&
fieldArray[s.theRow + 2 * rowOffset][s.theCol + 2 * colOffset] == 0) {
return true;
}
}
return false;
}
function main() {
canvas = document.getElementById("drawingCanvas"),
context = canvas.getContext("2d");
canvas.style.background = "#A0A0A0"
BB = canvas.getBoundingClientRect();
context.fillStyle = 'rgb(150,190,255)';
context.globalAlpha = 0.7;
offsetX = BB.left;
offsetY = BB.top;
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
if (fieldArray[i][j] == 1) {
shapes.push({
x: j * 60 + 30,
y: i * 60 + 30,
r: 30,
theRow: i,
theCol: j,
fill: "#444444",
isDragging: false
});
}
}
}
draw();
canvas.onmousedown = myDown;
}
main();
}
<canvas id="drawingCanvas" width="500" height="500">
How to fix?
At the end of the game shapes is empty but you are getting shapes[i]. That would return undefined. And that's what the error means undefined doesn't have a property theRow.
You should maybe rerun main() or only rerun this:
for (var i = 0; i < fieldArray.length; i++) {
for (var j = 0; j < fieldArray[i].length; j++) {
if (fieldArray[i][j] == 1) {
shapes.push({
x: j * 60 + 30,
y: i * 60 + 30,
r: 30,
theRow: i,
theCol: j,
fill: "#444444",
isDragging: false
});
}
}
}

p5.js within html not working (Using instantiation)

Im trying to implement this p5.js code within a html/css flexbox and it isn't working. I know that it needs p. before many of the lines of code, but I am not sure where. Ive done it in the past and it has worked, but not on this scale. Can anyone help?
var phase, speed, maxCircleSize, numRows, numCols, numStrands, colorA, colorB;
var sketch4 = function (p) {
p.setup = function() {
p.createCanvas(500, 500);
p.noStroke();
phase = 0;
speed = 0.03;
maxCircleSize = 20;
numRows = 10;
numCols = 16;
numStrands = 2;
colorA = p.color(253, 174, 120);
colorB = p.color(226, 129, 161);
}
draw = function() {
p.background(4, 58, 74);
phase = frameCount * speed;
for (var strand = 0; strand < numStrands; strand += 1) {
var strandPhase = phase + map(strand, 0, numStrands, 0, TWO_PI);
for (var col = 0; col < numCols; col += 1) {
var colOffset = map(col, 0, numCols, 0, TWO_PI);
var x = map(col, 0, numCols, 50, width - 50);
for (var row = 0; row < numRows; row += 1) {
var y = height / 2 + row * 10 + sin(strandPhase + colOffset) * 50;
var sizeOffset =
(cos(strandPhase - row / numRows + colOffset) + 1) * 0.5;
var circleSize = sizeOffset * maxCircleSize;
p.fill(p.lerpColor(colorA, colorB, row / numRows));
p.ellipse(x, y, circleSize, circleSize);
}
}
}
}
};
let node4 = document.createElement('div');
window.document.getElementById('p5-3').appendChild(node4);
new p5(sketch4, node4);
Here is an example of one that works fine:
var sketch3 = function(p) {
p.setup = function() {
p.createCanvas(100, 100, p.WEBGL);
};
p.draw = function() {
p.background("#A9927D");
p.rotateZ(p.frameCount * 0.01);
p.rotateX(p.frameCount * 0.01);
p.rotateY(p.frameCount * 0.01);
p.normalMaterial()
p.cone(25, 25);
};
};
let node3 = document.createElement('div');
window.document.getElementById('p5-3').appendChild(node3);
new p5(sketch3, node3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-3"></div>
So many little things missing, but mainly p. everywhere.
var phase, speed, maxCircleSize, numRows, numCols, numStrands, colorA, colorB;
var sketch4 = function (p) {
p.setup = function() {
p.createCanvas(500, 500);
p.noStroke();
phase = 0;
speed = 0.03;
maxCircleSize = 20;
numRows = 10;
numCols = 16;
numStrands = 2;
colorA = p.color(253, 174, 120);
colorB = p.color(226, 129, 161);
};
p.draw = function() { // [HERE]
p.background(4, 58, 74);
phase = p.frameCount * speed; // [HERE]
for (var strand = 0; strand < numStrands; strand += 1) {
var strandPhase = phase + p.map(strand, 0, numStrands, 0, p.TWO_PI); // [HERE]
for (var col = 0; col < numCols; col += 1) {
var colOffset = p.map(col, 0, numCols, 0, p.TWO_PI); // [HERE]
var x = p.map(col, 0, numCols, 50, p.width - 50); // [HERE]
for (var row = 0; row < numRows; row += 1) {
var y = p.height / 4 + row * 10 + p.sin(strandPhase + colOffset) * 50; // [HERE]
var sizeOffset =
(p.cos(strandPhase - row / numRows + colOffset) + 1) * 0.5; // [HERE]
var circleSize = sizeOffset * maxCircleSize;
p.fill(p.lerpColor(colorA, colorB, row / numRows));
p.ellipse(x, y, circleSize, circleSize);
}
}
}
};
};
let node4 = document.createElement('div');
window.document.getElementById('p5-3').appendChild(node4);
new p5(sketch4, node4);
body {
background-color:#e9e9e9;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-3"></div>
Or using the with statement for less Psss.
var phase, speed, maxCircleSize, numRows, numCols, numStrands, colorA, colorB;
var sketch4 = function (p) {
with(p) { // [HERE]
p.setup = function() {
createCanvas(500, 500);
noStroke();
phase = 0;
speed = 0.03;
maxCircleSize = 20;
numRows = 10;
numCols = 16;
numStrands = 2;
colorA = p.color(253, 174, 120);
colorB = p.color(226, 129, 161);
};
p.draw = function() {
background(4, 58, 74);
phase = frameCount * speed;
for (var strand = 0; strand < numStrands; strand += 1) {
var strandPhase = phase + map(strand, 0, numStrands, 0, TWO_PI);
for (var col = 0; col < numCols; col += 1) {
var colOffset = map(col, 0, numCols, 0, TWO_PI);
var x = map(col, 0, numCols, 50, width - 50);
for (var row = 0; row < numRows; row += 1) {
var y = height / 4 + row * 10 + sin(strandPhase + colOffset) * 50;
var sizeOffset =
(cos(strandPhase - row / numRows + colOffset) + 1) * 0.5;
var circleSize = sizeOffset * maxCircleSize;
fill(lerpColor(colorA, colorB, row / numRows));
ellipse(x, y, circleSize, circleSize);
}
}
}
};
}
};
let node4 = document.createElement('div');
window.document.getElementById('p5-3').appendChild(node4);
new p5(sketch4, node4);
body {
background-color:#e9e9e9;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-3"></div>

Circle to circle collision resolution

I'm trying to resolve circle to circle collisions. The problem is, the balls never settle to the bottom -- they continue to jiggle around. What can I do to make the balls settle to the bottom at the end of their cycle (without jiggling)?
CodePen: https://codepen.io/KriegersVan/pen/gOpXzwE?editors=0010
var _bouncingBalls = (function() {
document.getElementById("canvas").width = window.innerWidth;
document.getElementById("canvas").height = window.innerHeight;
function _randomNumBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function _negativeOrPositiveOne() {
return Math.random() < 0.50 ? -1 : 1;
}
function _random10Chars() {
return Math.random().toString(36).substr(2, 10);
}
var _balls = {
numOf: 10,
colors: ["#6a00ff", "#9500ff", "#d000ff", "#ff00ff", "#00f2ff", "#f59b42", "#e9f542"],
particles: [],
ctx: document.getElementById("canvas").getContext("2d"),
lastFrameTime: 0,
startTime: 0,
inProgress: false,
init: function(x, y) {
for (var i = 0; i < this.numOf; i++) {
this.particles.push({
x: x+(i*(window.innerWidth * 0.02)), //So they don't overlap at the beginning
y: y,
vy: Math.random() * _negativeOrPositiveOne(),
vx: 2 * Math.random() * _negativeOrPositiveOne(),
color: this.colors[_randomNumBetween(0, this.colors.length - 1)],
radius: window.innerWidth * 0.008,
gravity: 0.70,
damping: 0.50,
id: _random10Chars() + _random10Chars()
});
}
this.startTime = window.performance.now();
if (!this.inProgress) {
this.inProgress = true;
window.requestAnimationFrame(this.render);
}
},
isBallCollision: function(particle) {
//https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
for (var j = 0; j < _balls.particles.length; j++) {
var comparisonParticle = _balls.particles[j];
var dx = particle.x - comparisonParticle.x;
var dy = particle.y - comparisonParticle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (particle.id === comparisonParticle.id) {
continue;
}
var minDist = comparisonParticle.radius + particle.radius;
if (distance < minDist) {
//https://www.youtube.com/watch?v=nlwtgvZCz0k
var distance_x = dx;
var distance_y = dy;
var radii_sum = particle.radius+comparisonParticle.radius;
var length = Math.sqrt(distance_x * distance_x + distance_y * distance_y) || 1;
var unit_x = distance_x/length;
var unit_y = distance_y/length;
particle.x = comparisonParticle.x+(radii_sum+1)*unit_x;
particle.y = comparisonParticle.y+(radii_sum+1)*unit_y;
return comparisonParticle;
}
}
return null;
},
isBottomHit: function(obj, comparisonObj){
return obj.y+obj.radius > comparisonObj.y-comparisonObj.radius &&
obj.y+obj.radius < comparisonObj.y+comparisonObj.radius;
},
isTopHit: function(obj, comparisonObj){
return obj.y-obj.radius < comparisonObj.y+comparisonObj.radius &&
obj.y-obj.radius > comparisonObj.y-comparisonObj.radius;
},
isLeftHit: function(obj, comparisonObj){
return obj.x-obj.radius < comparisonObj.x+comparisonObj.radius &&
obj.x-obj.radius > comparisonObj.x-comparisonObj.radius;
},
isRightHit: function(obj, comparisonObj){
return obj.x+obj.radius > comparisonObj.x-comparisonObj.radius &&
obj.x+obj.radius < comparisonObj.x+comparisonObj.radius;
},
bottomReached: function(obj) {
return (obj.y + obj.radius) >= window.innerHeight;
},
topReached: function(obj) {
return (obj.y - obj.radius) <= 0;
},
leftSideReached: function(obj) {
return (obj.x - obj.radius) <= 0;
},
rightSideReached: function(obj) {
return (obj.x + obj.radius) >= window.innerWidth;
},
draw: function(deltaNum, timestamp) {
var r = _balls;
var ctx = r.ctx;
var elapsed = timestamp - r.startTime;
for (var i = 0; i < r.particles.length; i++) {
var obj = r.particles[i];
ctx.beginPath();
ctx.fillStyle = obj.color;
ctx.moveTo(
obj.x,
obj.y
);
ctx.arc(
obj.x,
obj.y,
obj.radius,
0,
2 * Math.PI,
false
);
ctx.fill();
ctx.closePath();
obj.y += (obj.vy * deltaNum);
obj.vy += (obj.gravity * deltaNum);
obj.x += (obj.vx * deltaNum);
var otherBall = r.isBallCollision(obj);
if (otherBall) {
if (r.isBottomHit(obj, otherBall)){
//Bounce up
obj.vy = -Math.abs(obj.vy*obj.damping);
} else if (r.isTopHit(obj, otherBall)){
//bounce down
obj.vy = Math.abs(obj.vy*obj.damping);
}
if (r.isLeftHit(obj, otherBall)){
//Bounce right
obj.vx = Math.abs(obj.vx*obj.damping);
} else if (r.isRightHit(obj, otherBall)){
//Bounce left
obj.vx = -Math.abs(obj.vx*obj.damping);
}
}
if (r.bottomReached(obj)) {
obj.y = window.innerHeight - obj.radius;
if (obj.vy > 5){
//Bounce
obj.vy = -(obj.vy * 0.70);
} else {
//Stop bouncing
obj.vy = 0;
if (otherBall) {
obj.vx = -(obj.vx * obj.damping);
}
obj.vx += obj.vx > 0 ? -0.008 : 0.008;
if (obj.vx < 0.010 && obj.vx > -0.010) {
obj.vx = 0;
}
}
} else if (r.topReached(obj)) {
obj.vy = Math.abs(obj.vy);
}
if (r.rightSideReached(obj)) {
obj.vx = -obj.vx;
} else if (r.leftSideReached(obj)) {
obj.vx = Math.abs(obj.vx);
}
}
},
render: function(timestamp) {
var a = _balls;
var delta = timestamp - (a.lastFrameTime || timestamp);
a.lastFrameTime = timestamp;
if (a.particles.length) {
a.ctx.clearRect(
0,
0,
window.innerWidth,
window.innerHeight
);
a.draw(delta / 16.6, timestamp);
}
window.requestAnimationFrame(a.render);
}
};
var _mouseControl = (function() {
var _el = document.getElementById("canvas");
_el.addEventListener("click", function(e) {
_balls.init.call(_balls, e.clientX, e.clientY);
});
}());
}());

Memory leak in JavaScript

What's the memory leak in the following script?
function postars(canvas) {
var _this = this,
ctx = canvas.getContext('2d');
_this.config = {
star: {
color: '#ffffff'
},
line: {
color: '#ffffff',
width: 0.1
},
position: {
x: canvas.width * 0.5,
y: canvas.height * 0.5
},
velocity: 0.1,
length: 100,
distance: 120,
radius: 150,
stars: []
};
function Star() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = (_this.config.velocity - (Math.random() * 0.5));
this.vy = (_this.config.velocity - (Math.random() * 0.5));
this.radius = Math.random();
}
Star.prototype = {
create: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.fill();
},
animate: function() {
var i;
for (i = 0; i < _this.config.length; i++) {
var star = _this.config.stars[i];
if (star.y < 0 || star.y > canvas.height) {
star.vx = star.vx;
star.vy = -star.vy;
} else if (star.x < 0 || star.x > canvas.width) {
star.vx = -star.vx;
star.vy = star.vy;
}
star.x += star.vx;
star.y += star.vy;
}
},
line: function() {
var length = _this.config.length,
iStar, jStar, i, j;
for (i = 0; i < length; i++) {
for (j = 0; j < length; j++) {
iStar = _this.config.stars[i];
jStar = _this.config.stars[j];
if ((iStar.x - jStar.x) < _this.config.distance && (iStar.y - jStar.y) < _this.config.distance && (iStar.x - jStar.x) > -_this.config.distance && (iStar.y - jStar.y) > -_this.config.distance) {
if ((iStar.x - _this.config.position.x) < _this.config.radius && (iStar.y - _this.config.position.y) < _this.config.radius && (iStar.x - _this.config.position.x) > -_this.config.radius && (iStar.y - _this.config.position.y) > -_this.config.radius) {
ctx.beginPath();
ctx.moveTo(iStar.x, iStar.y);
ctx.lineTo(jStar.x, jStar.y);
ctx.stroke();
ctx.closePath();
}
}
}
}
}
};
_this.createStars = function() {
var length = _this.config.length,
star, i;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (i = 0; i < length; i++) {
_this.config.stars.push(new Star());
star = _this.config.stars[i];
star.create();
}
star.line();
star.animate();
};
_this.setCanvas = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
_this.setContext = function() {
ctx.fillStyle = _this.config.star.color;
ctx.strokeStyle = _this.config.line.color;
ctx.lineWidth = _this.config.line.width;
};
_this.loop = function(callback) {
callback();
reqAnimFrame(function() {
_this.loop(function() {
callback();
});
});
};
_this.bind = function() {
$(window).on('mousemove', function(e) {
_this.config.position.x = e.pageX;
_this.config.position.y = e.pageY;
});
};
_this.init = function() {
_this.setCanvas();
_this.setContext();
_this.loop(function() {
_this.createStars();
});
_this.bind();
};
return _this;
}
var reqAnimFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
It's working for a few hours and then Chrome crashes (displays an error page saying something went wrong) or outputs "stack overflow" to console.
The answer is not to use new Star() in a function's parameter, instead of that do:
var newStar = new Star()
_this.config.stars.push(newStar)
newStar = null
And to modify the code not to create new stars continously.

Categories