I'm coding a maze generator using the backtracking algorithm and p5.js library, but when I was coding a loop to set random positions in the maze, I noticed an error in javascript: "maze[(x - 2)] is undefined", but this variable is declared! I tried to read about data structures, but I couldn't find a solution for this problem.
What is happening?
Can someone help me?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset = "utf-8">
<title>Maze</title>
</head>
<body>
<script src = "https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
<script>
var width = 720;
var height = 400;
var x, y;
var maze = Array(39).fill(Array(71).fill(0));
function setup()
{
createCanvas(720, 400);
}
function draw()
{
//inicial position
x = 1;
y = 1;
maze[x][y] = 1;
//grid
strokeWeight(1);
stroke('BLACK');
for (x = 0; x <= 720; x += 10) line(x, 0, x, 400);
for (y = 0; y <= 400; y += 10) line(0, y, 720, y);
found = 0;
do
{
direction = Math.floor(Math.random() * 4);
if (direction == 0 && (y != width - 2 && maze[x][y + 2] == 0))
{
x2 = x;
y2 = y;
y += 2;
maze[x][y] = 1;
maze[x][y-1] = 1;
found = 1;
}
else if (direction == 1 && (x > 1 && maze[x - 2][y] == 0))
{
x2 = x;
y2 = y;
x -= 2;
maze[x][y] = 1;
maze[x + 1][y] = 1;
found = 1;
}
else if (direction == 2 && (y > 1 && maze[x][y - 2] == 0))
{
x2 = x;
y2 = y;
y -= 2;
maze[x][y] = 1;
maze[x][y + 1] = 1;
found = 1;
}
else if (direction == 3 && (x != height - 2 && maze[x + 2][y] == 0))
{
x2 = x;
y2 = y;
x += 2;
maze[x][y] = 1;
maze[x - 1][y] = 1;
found = 1;
}
} while (found == 0);
noLoop();
}
</script>
</body>
</html>
There a few issues with this code.
Lets start with why you getting that error. The issue is that you are reusing global x and y variables in for loop that draw lines, when the loop is done, it set these variables larger than your maze array.
This brings us to second issue: maze array is smaller than width/height of the canvas.
The code is not 100% working so I don't exactly understand what it supposed to do, but it seems x and y should not exceed width/height, however you have a condition y != width - 2 which will be true even if y is bigger than width (btw, shouldn't it be height instead??)
And finally, through out the code you have multiple places with 720 and 400, instead of using width and height variables. This is a bad practice.
const width = 720;
const height = 400;
var x, y;
var maze = Array(width+1).fill(Array(height+1).fill(0));
function setup()
{
createCanvas(width, height);
}
function draw()
{
//inicial position
x = 1;
y = 1;
maze[x][y] = 1;
//grid
strokeWeight(1);
stroke('BLACK');
for (let x = 0; x <= width; x += 10) line(x, 0, x, height);
for (let y = 0; y <= height; y += 10) line(0, y, width, y);
found = 0;
do
{
direction = Math.floor(Math.random() * 4);
if (direction == 0 && (y <= height - 2 && maze[x][y + 2] == 0))
{
x2 = x;
y2 = y;
y += 2;
maze[x][y] = 1;
maze[x][y-1] = 1;
found = 1;
}
else if (direction == 1 && (x > 1 && maze[x - 2][y] == 0))
{
x2 = x;
y2 = y;
x -= 2;
maze[x][y] = 1;
maze[x + 1][y] = 1;
found = 1;
}
else if (direction == 2 && (y > 1 && maze[x][y - 2] == 0))
{
x2 = x;
y2 = y;
y -= 2;
maze[x][y] = 1;
maze[x][y + 1] = 1;
found = 1;
}
else if (direction == 3 && (x <= width - 2 && maze[x + 2][y] == 0))
{
x2 = x;
y2 = y;
x += 2;
maze[x][y] = 1;
maze[x - 1][y] = 1;
found = 1;
}
} while (found == 0);
noLoop();
}
<script src = "https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
I'm new to HTML5 canvas & JavaScript, I'm trying to draw multiple mouse click, move rectangles on file uploaded image over a canvas, how to do this? I tried some ideas, but the image suddenly disappeared when I draw the rectangle over an image canvas.
Here, it is my code:
<script>
(function() {
var canvas = new fabric.Canvas('panel');
var line, isDown, startPosition={}, rect,drawingMode=true;
canvas.on('mouse:down', function(event){
if (!drawingMode) return;
isDown = true;
console.log(event.e.clientX,event.e.clientY);
startPosition.x=event.e.clientX;
startPosition.y=event.e.clientY;
console.log(startPosition);
rect=new fabric.Rect({
left:event.e.clientX,
top:event.e.clientY,
width:0,
height:0,
stroke:'red',
strokeWidth:3,
fill:''
});
canvas.add(rect);
});
canvas.on('mouse:move', function(event){
if (!isDown || !drawingMode) return;
rect.setWidth(Math.abs( event.e.clientX-startPosition.x ));
rect.setHeight(Math.abs( event.e.clientY -startPosition.y ));
canvas.renderAll();
});
canvas.on('mouse:up', function(){
isDown = false;
canvas.add(rect);
// window.alert("hi");
});
canvas.on('object:selected', function(){
drawingMode = false;
});
canvas.on('object:selected', function(){
drawingMode = false;
});
canvas.on('selection:cleared', function(){
drawingMode = true;
});
})();
</script>
<input type='file' id="fileUpload" onChange="readURL(this);" accept="image/*" style="margin-top: 30px; margin-left: 80px;" >
<script>
function el(id){return document.getElementById(id);} // Get elem by ID
var canvas = el("panel");
var context = canvas.getContext("2d");
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
var img = new Image();
img.addEventListener("load", function() {
context.drawImage(img, 0, 0, 700, 450);
});
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);
</script>
<html lang="en" >
<head>
<meta charset="utf-8" />
<title></title>
<link href="index.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.1.0/fabric.all.min.js" ></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<div class="column1">
<canvas id="panel" width="700" height="450" style="border: 2px solid black; width: 500px;height: 400px;"></canvas>
<input type='file' id="fileUpload" onChange="readURL(this);" accept="image/*" style="margin-top: 30px; margin-left: 80px;" >
</div>
</div>
Also, I have this fiddle the code:
jsfiddle.net/mahbub_rahman/m04c3smj/5
Thanks for your help.
Do you want like this?
check this fiddle link.
<canvas id="canvas" width="400" height="233" style="border:1px solid red"></canvas>
#canvas {
background-color: white;
}
<script>
var lineOffset = 4;
var anchrSize = 2;
var mousedown = false;
var clickedArea = {box: -1, pos:'o'};
var x1 = -1;
var y1 = -1;
var x2 = -1;
var y2 = -1;
var boxes = [];
var tmpBox = null;
document.getElementById("panel").onmousedown = function(e) {
mousedown = true;
clickedArea = findCurrentArea(e.offsetX, e.offsetY);
x1 = e.offsetX;
y1 = e.offsetY;
x2 = e.offsetX;
y2 = e.offsetY;
};
document.getElementById("panel").onmouseup = function(e) {
if (clickedArea.box == -1 && tmpBox != null) {
boxes.push(tmpBox);
} else if (clickedArea.box != -1) {
var selectedBox = boxes[clickedArea.box];
if (selectedBox.x1 > selectedBox.x2) {
var previousX1 = selectedBox.x1;
selectedBox.x1 = selectedBox.x2;
selectedBox.x2 = previousX1;
}
if (selectedBox.y1 > selectedBox.y2) {
var previousY1 = selectedBox.y1;
selectedBox.y1 = selectedBox.y2;
selectedBox.y2 = previousY1;
}
}
clickedArea = {box: -1, pos:'o'};
tmpBox = null;
mousedown = false;
console.log(boxes);
};
document.getElementById("panel").onmouseout = function(e) {
if (clickedArea.box != -1) {
var selectedBox = boxes[clickedArea.box];
if (selectedBox.x1 > selectedBox.x2) {
var previousX1 = selectedBox.x1;
selectedBox.x1 = selectedBox.x2;
selectedBox.x2 > previousX1;
}
if (selectedBox.y1 > selectedBox.y2) {
var previousY1 = selectedBox.y1;
selectedBox.y1 = selectedBox.y2;
selectedBox.y2 > previousY1;
}
}
mousedown = false;
clickedArea = {box: -1, pos:'o'};
tmpBox = null;
};
document.getElementById("panel").onmousemove = function(e) {
if (mousedown && clickedArea.box == -1) {
x2 = e.offsetX;
y2 = e.offsetY;
redraw();
} else if (mousedown && clickedArea.box != -1) {
x2 = e.offsetX;
y2 = e.offsetY;
xOffset = x2 - x1;
yOffset = y2 - y1;
x1 = x2;
y1 = y2;
if (clickedArea.pos == 'i' ||
clickedArea.pos == 'tl' ||
clickedArea.pos == 'l' ||
clickedArea.pos == 'bl') {
boxes[clickedArea.box].x1 += xOffset;
}
if (clickedArea.pos == 'i' ||
clickedArea.pos == 'tl' ||
clickedArea.pos == 't' ||
clickedArea.pos == 'tr') {
boxes[clickedArea.box].y1 += yOffset;
}
if (clickedArea.pos == 'i' ||
clickedArea.pos == 'tr' ||
clickedArea.pos == 'r' ||
clickedArea.pos == 'br') {
boxes[clickedArea.box].x2 += xOffset;
}
if (clickedArea.pos == 'i' ||
clickedArea.pos == 'bl' ||
clickedArea.pos == 'b' ||
clickedArea.pos == 'br') {
boxes[clickedArea.box].y2 += yOffset;
}
redraw();
}
}
function redraw() {
// canvas.width = canvas.width;
var context = document.getElementById("panel").getContext('2d');
context.globalCompositeOperation='destination-over';
context.clearRect(0, 0, 800, 600);
context.beginPath();
for (var i = 0; i < boxes.length; i++) {
drawBoxOn(boxes[i], context);
}
if (clickedArea.box == -1) {
tmpBox = newBox(x1, y1, x2, y2);
if (tmpBox != null) {
drawBoxOn(tmpBox, context);
}
}
}
function findCurrentArea(x, y) {
for (var i = 0; i < boxes.length; i++) {
var box = boxes[i];
xCenter = box.x1 + (box.x2 - box.x1) / 2;
yCenter = box.y1 + (box.y2 - box.y1) / 2;
if (box.x1 - lineOffset < x && x < box.x1 + lineOffset) {
if (box.y1 - lineOffset < y && y < box.y1 + lineOffset) {
return {box: i, pos:'tl'};
} else if (box.y2 - lineOffset < y && y < box.y2 + lineOffset) {
return {box: i, pos:'bl'};
} else if (yCenter - lineOffset < y && y < yCenter + lineOffset) {
return {box: i, pos:'l'};
}
} else if (box.x2 - lineOffset < x && x < box.x2 + lineOffset) {
if (box.y1 - lineOffset < y && y < box.y1 + lineOffset) {
return {box: i, pos:'tr'};
} else if (box.y2 - lineOffset < y && y < box.y2 + lineOffset) {
return {box: i, pos:'br'};
} else if (yCenter - lineOffset < y && y < yCenter + lineOffset) {
return {box: i, pos:'r'};
}
} else if (xCenter - lineOffset < x && x < xCenter + lineOffset) {
if (box.y1 - lineOffset < y && y < box.y1 + lineOffset) {
return {box: i, pos:'t'};
} else if (box.y2 - lineOffset < y && y < box.y2 + lineOffset) {
return {box: i, pos:'b'};
} else if (box.y1 - lineOffset < y && y < box.y2 + lineOffset) {
return {box: i, pos:'i'};
}
} else if (box.x1 - lineOffset < x && x < box.x2 + lineOffset) {
if (box.y1 - lineOffset < y && y < box.y2 + lineOffset) {
return {box: i, pos:'i'};
}
}
}
return {box: -1, pos:'o'};
}
function newBox(x1, y1, x2, y2) {
boxX1 = x1 < x2 ? x1 : x2;
boxY1 = y1 < y2 ? y1 : y2;
boxX2 = x1 > x2 ? x1 : x2;
boxY2 = y1 > y2 ? y1 : y2;
if (boxX2 - boxX1 > lineOffset * 2 && boxY2 - boxY1 > lineOffset * 2) {
return {x1: boxX1,
y1: boxY1,
x2: boxX2,
y2: boxY2,
lineWidth: 2,
color: 'red'};
} else {
return null;
}
}
function drawBoxOn(box, context) {
xCenter = box.x1 + (box.x2 - box.x1) / 2;
yCenter = box.y1 + (box.y2 - box.y1) / 2;
context.strokeStyle = box.color;
context.fillStyle = box.color;
context.rect(box.x1, box.y1, (box.x2 - box.x1), (box.y2 - box.y1));
context.lineWidth = box.lineWidth;
context.stroke();
context.fillRect(box.x1 - anchrSize, box.y1 - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(box.x1 - anchrSize, yCenter - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(box.x1 - anchrSize, box.y2 - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(xCenter - anchrSize, box.y1 - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(xCenter - anchrSize, yCenter - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(xCenter - anchrSize, box.y2 - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(box.x2 - anchrSize, box.y1 - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(box.x2 - anchrSize, yCenter - anchrSize, 2 * anchrSize, 2 * anchrSize);
context.fillRect(box.x2 - anchrSize, box.y2 - anchrSize, 2 * anchrSize, 2 * anchrSize);
}
function el(id){return document.getElementById(id);} // Get elem by ID
var canvas = el("panel");
var context = canvas.getContext("2d");
var cx=100;
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
var img = new Image();
img.addEventListener("load", function() {
context.drawImage(img, 0, 0, 400, 233);
});
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);
<script>
I've got some code for part of a game where an absolutely positioned div (id = 'cursor') follows your mouse's cursor around. When the cursor div runs into another div (class = 'thing') (these are the white boxes in the jsfiddles), the cursor speed changes.
In this JSfiddle you'll see that it works perfectly fine. When cursor hits thing, cursor speeds up. This is the conditional used to change the speed (newSpeed is what determines the speed for cursor):
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 200;
changeCursorSpeed();
} else {
newSpeed = 12;
changeCursorSpeed();
console.log('hit');
}
The problem I'm having is when I switch around the values for newSpeed in the conditional:
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
Here's the JSFiddle for this. This causes the collision to not change newSpeed in the else part of the condition. However, using console.log('hit'), you can clearly see that the collision is detected.
Logically, this doesn't seem to make sense. I'd like to hear input from others about this as well as possible solutions. Thanks for any help.
Here's the entire code for the collision detection. The JSfiddles have a more complete code for the program.
var newSpeed;
var newInt = setInterval(function() {
function collision($cursor, $thing) {
var x1 = $cursor.offset().left;
var y1 = $cursor.offset().top;
var h1 = $cursor.outerHeight(true);
var w1 = $cursor.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
$thing.each(function(i){
var x2 = $(this).offset().left;
var y2 = $(this).offset().top;
var h2 = $(this).outerHeight(true);
var w2 = $(this).outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
});
function changeCursorSpeed(){
$xp += (($mouseX - $xp)/newSpeed);
$yp += (($mouseY - $yp)/newSpeed);
$("#cursor").css({left:$xp +'px', top:$yp +'px'});
}
}
$(collision($('#cursor'), $('.thing')));
}, 20);
I'm trying to draw a one pixel width line going form the canvas center and evolving with the canvas width/height ratio as it's drawn.
var x = 0;
var y = 0;
var dx = 0;
var dy = -1;
var width = 200;
var height = 40;
//var i = width * height;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
setInterval(function(){
//for (i = Math.pow(Math.max(width, height), 2); i>0; i--) {
if ((-width/2 < x <= width/2) && (-height/2 < y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if (x === y || (x < 0 && x === -y) || (x > 0 && x === 1-y) || ( -width/2 > x > width/2 ) || ( -height/2 > y > height/2 ) ) {
// change direction
var tempdx = dx;
dx = -dy;
dy = tempdx;
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);
I want the spiral to evolve as such:
I'd like to be able to get the ratio between height and width on the equation, so I don't need to calculate the coordinates for points outside the canvas. Also, the purpose is for it to adjust the spiral drawing to the canvas proportions.
Any help would be appreciated.
A friend helped me handling a proper solution. I only have a 1 pixel offset to solve where I need to move all the drawing to the left by one pixel.
Here's the fiddle for the solution achieved: http://jsfiddle.net/hitbyatruck/c4Kd6/
And the Javascript code below:
var width = 150;
var height = 50;
var x = -(width - height)/2;
var y = 0;
var dx = 1;
var dy = 0;
var x_limit = (width - height)/2;
var y_limit = 0;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
setInterval(function(){
if ((-width/2 < x && x <= width/2) && (-height/2 < y && y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if( dx > 0 ){//Dir right
if(x > x_limit){
dx = 0;
dy = 1;
}
}
else if( dy > 0 ){ //Dir up
if(y > y_limit){
dx = -1;
dy = 0;
}
}
else if(dx < 0){ //Dir left
if(x < (-1 * x_limit)){
dx = 0;
dy = -1;
}
}
else if(dy < 0) { //Dir down
if(y < (-1 * y_limit)){
dx = 1;
dy = 0;
x_limit += 1;
y_limit += 1;
}
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);
I nearly crashed my browser trying this. Here, have some code before I hurt myself!
It computes y=f(x) for the diagonal, and y2=f(x) for the antidiagonal, then checks if we're above or below the diagonals when needed.
var x = 0;
var y = 0;
var dx = 0;
var dy = -1;
var width = 200;
var height = 40;
//var i = width * height;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
function diag1(x) {
return x*height/width;
}
function diag2(x) {
return -1/diag(x);
}
setInterval(function(){
//for (i = Math.pow(Math.max(width, height), 2); i>0; i--) {
if ((-width/2 < x && x <= width/2) && (-height/2 < y && y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if (dx == 0) {
if (dy == 1) {
// moving up
if (y >= diag1(x)) {
// then move left
dy = 0;
dx = -1;
}
}
else {
// moving down
if (y <= diag2(x)) {
// then move right
dy = 0;
dx = 1;
}
}
}
else {
if (dx == 1) {
// moving right
if (y <= diag1(x)) {
// then move up
dy = 1;
dx = 0;
}
}
else {
// moving left
if (y <= diag2(x)) {
// then move down
dy = -1;
dx = 0;
}
}
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);
$(document).ready(function(){
var x1 = Math.random()*$(window).width(); var y1 = Math.random()*$(window).height();
var x2 = 1; var y2 = 1;
var paper = Raphael(document.body);
setInterval(function() {
randx = Math.random(); randy = Math.random();
if (randx > 0.9) {
if (x2 = 1) {
if (randx > 0.99) x2 = -1;
}
else if (x2 = -1) {
if (randx > 0.99) x2 = 1;
}
} else x2 = 0;
if (randy > 0.9) {
if (y2 = 1) {
if (randy > 0.99) y2 = -1;
}
else if (y2 = -1) {
if (randy > 0.99) y2 = 1;
}
} else y2 = 0;
paper.path("M"+x1+" "+y1+"L"+(x1+x2)+" "+(y1+y2));
x1 = x1+x2;
y1 = y1+y2;
}, 0);
});
This is my "random line" generating script. I know it must look terrible, I am just learning. But I am trying to get something resembling this: http://i.stack.imgur.com/R7Kkv.png
I'd really appreciate some tips/suggestions for the algorithm that will make the line smoother and more likely to turn do a u-turn etc.
Thanks
The answer is to generate points within a 40x40 or so box around the previous point, and interpolate between them with a cubic spline.