Painting Cells in Grid - javascript

I have a JSfiddle set up here. I'm drawing a canvas grid and want to allow a user to select a color and 'paint' the grid cells like pixel art. Can someone point me in the right direction?
http://jsfiddle.net/g51bx1nb/
var c_canvas = document.getElementById("c");
var context = c_canvas.getContext("2d");
for (var x = 0.5; x < 501; x += 20) {
context.moveTo(x, 0);
context.lineTo(x, 381);
}
for (var y = 0.5; y < 381; y += 20) {
context.moveTo(0, y);
context.lineTo(500, y);
}
context.strokeStyle = "#ddd";
context.stroke();

Well this should get you closer.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function getNearestSquare(position) {
var x = position.x;
var y = position.y;
if (x < 0 || y < 0) return null;
x = (Math.floor(x / 20) * 20) + 0.5
y = (Math.floor(y / 20) * 20) + 0.5
return {x: x, y: y};
}
$(c_canvas).click(function(evt) {
var pos = getNearestSquare(getMousePos(c_canvas, evt));
if (pos != null) {
context.fillStyle="#FF0000";
context.fillRect(pos.x,pos.y,20,20);
}
});
I tried this out on your fiddle, adding this JS code gives you an on click event that'll let you click and paint an area the size of one of your squares red, you just need to use the fill style as a variable that the user can change.
Edit:
I added the logic to find the top left.

Related

Ball not coming back after colliding in p5.js

var x, y, speed, speed2, speedx, speedy;
function setup() {
createCanvas(1200, 630);
x = 50;
y = 300;
speed = 20;
speed2 = 20;
speedx = createSlider(2, 50, 20);
speedx.position(1000, 100);
speedx.style('width', '200px');
speedy = createSlider(10, 50, 20);
speedy.position(1000, 150);
speedy.style('width', '200px');
}
function draw() {
background("white");
x = x + speedx.value();
y = y + speedy.value();
if (x > 1170) {
x = x - speedx.value();
}
if (x < 10) {
x = x + speedx.value();
}
if (y > 610) {
y = y - speedy.value();
}
if (y < 15) {
x = x + speedx.value();
}
let color1 = color("black");
fill(color1);
ellipse(x, y, 20);
}
**
I am new to p5.js and made this (my first code) but it is not working as I expected
Please help me by answering this code
**
Currently your code isn't going to make the ball "come back" because while it is limiting the x and y positions, it doesn't change the x and y velocities (so once the ball gets to the edge it is just going to stick there). You also have a few defects in to edge limiting logic.
Your sliders are always positive so the ball can only move down and to the right.
When you check the y position against the minimum you modify the x position instead of the y position.
When you check the x position against the minimum value you are adding the speeds, but presumably when this happens speed would be negative (i.e. moving to the left), so you still want to subtract.
var x, y, speedx, speedy;
function setup() {
// make the canvas cover the window
createCanvas(windowWidth, windowHeight);
x = width / 2;
y = height / 2;
// create slider ranges such that things don't always go down and to the right
speedx = createSlider(-10, 10, 2);
speedx.position(10, 10);
speedx.style("width", "200px");
speedy = createSlider(-10, 10, 2);
speedy.position(10, 50);
speedy.style("width", "200px");
}
function draw() {
background("white");
x = x + speedx.value();
y = y + speedy.value();
if (x > width - 10) {
x = x - speedx.value();
}
if (x < 10) {
// presumably the reason we're going off the screen is that speedx is negative.
x = x - speedx.value();
}
if (y > height - 10) {
y = y - speedy.value();
}
if (y < 10) {
y = y - speedy.value();
}
let color1 = color("black");
fill(color1);
ellipse(x, y, 20);
}
html, body {margin:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
You can do something like this (visit codecademy for details: https://www.codecademy.com/courses/learn-p5js/lessons/p5js-animation)
speedx *= -1
You can do the same thing with speedy

How to Centre an object in any cell of an 8x8 grid in p5.js framework

This is my code of making a chess game.
let pawn1; //variable for object
var offset = 10;
function setup(){
createCanvas(600,600); // canvas
pawn1 = new Pawn(); // pawn1 is a new Pawn object
}
function draw(){
background(0); //black background
checkboard(); //to make an 8x8 grid
pawn1.show(); //shows pawn1 object on canvas
drag(); //allows the pawn object to be dragged
}
function Pawn(){
this.x = 25; // x position of object
this.y = 25; // y position of object
this.w = 20; // width of object
this.h = 20; // height of object
this.show = function(){
fill(255); // object is white
rect(this.x, this.y, this.w, this.h); //object is a rectangle with x,y,w,h variables
}
}
// grid maker function
function checkboard(){
for (var x = 0; x < width; x += width / 8) {
for (var y = 0; y < height; y += height / 8) {
stroke(255); //grid lines is white
strokeWeight(1); // lines drawn are 1 units thick
line(x, 0, x, height); // vertical lines
line(0, y, width, y); // horizontal lines
}
}
}
function drag(){
// if mouse is clicked down and inside of the dimensions of the object then:
if(mouseIsPressed){
if(mouseX > pawn1.x && mouseY > pawn1.y){
if(mouseX<(pawn1.x+pawn1.w) && mouseY<(pawn1.y+pawn1.h)){
//square will move with the mouse pointer
pawn1.x = mouseX - offset;
pawn1.y = mouseY - offset;
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
I do not have any idea of how to make sure when the dragged object is dropped, that it will be centered in the cell it has been dropped in. I suppose the code would go in the " drag function " as an else statement but other than that I am stuck. Can anyone help?
Thanks in advance!
Calculate the width and height of a cell. e.g:
var cell_w = width / 8;
var cell_h = height / 8;
I the width and height of a cell is fixed then you can use constant values, too. e.g:
var cell_w = 75;
var cell_h = 75;
Calculate the index of the current cell, be dividing the current mouse position, by the size of a cell and truncating the result by int() . e.g.:
var cell_ix = int(mouseX / cell_w);
var cell_iy = int(mouseY / cell_h);
Calculate the center point of the cell where the mouse is on:
var cell_cx = (cell_ix+0.5) * cell_w;
var cell_cy = (cell_iy+0.5) * cell_h;
Calculate the new position of the object, dependent on the center of the cell and the size of the object:
pawn1.x = cell_cx - pawn1.w/2;
pawn1.y = cell_cy - pawn1.h/2;
You can do that in the mouseReleased() call back. That causes, that the object can be smoothly dragged, but immediately "jumps" to the center of the cell when the mouse is released:
function mouseReleased() {
if (mouseX > pawn1.x && mouseY > pawn1.y &&
mouseX<(pawn1.x+pawn1.w) && mouseY<(pawn1.y+pawn1.h)) {
var cell_w = width / 8;
var cell_h = height / 8;
var cell_ix = int(mouseX / cell_w);
var cell_iy = int(mouseY / cell_h);
var cell_cx = (cell_ix+0.5) * cell_w;
var cell_cy = (cell_iy+0.5) * cell_h;
pawn1.x = cell_cx - pawn1.w/2;
pawn1.y = cell_cy - pawn1.h/2;
}
}
See the example, where I've added the function to your original code:
let pawn1; //variable for object
var offset = 10;
function setup(){
createCanvas(600,600); // canvas
pawn1 = new Pawn(); // pawn1 is a new Pawn object
}
function draw(){
background(0); //black background
checkboard(); //to make an 8x8 grid
pawn1.show(); //shows pawn1 object on canvas
drag(); //allows the pawn object to be dragged
}
function Pawn(){
this.x = 25; // x position of object
this.y = 25; // y position of object
this.w = 20; // width of object
this.h = 20; // height of object
this.show = function(){
fill(255); // object is white
rect(this.x, this.y, this.w, this.h); //object is a rectangle with x,y,w,h variables
}
}
// grid maker function
function checkboard(){
for (var x = 0; x < width; x += width / 8) {
for (var y = 0; y < height; y += height / 8) {
stroke(255); //grid lines is white
strokeWeight(1); // lines drawn are 1 units thick
line(x, 0, x, height); // vertical lines
line(0, y, width, y); // horizontal lines
}
}
}
function drag(){
// if mouse is clicked down and inside of the dimensions of the object then:
if(mouseIsPressed){
if(mouseX > pawn1.x && mouseY > pawn1.y){
if(mouseX<(pawn1.x+pawn1.w) && mouseY<(pawn1.y+pawn1.h)){
//square will move with the mouse pointer
pawn1.x = mouseX - offset;
pawn1.y = mouseY - offset;
}
}
}
}
function mouseReleased() {
if (mouseX > pawn1.x && mouseY > pawn1.y &&
mouseX<(pawn1.x+pawn1.w) && mouseY<(pawn1.y+pawn1.h)) {
var cell_w = width / 8;
var cell_h = height / 8;
var cell_ix = int(mouseX / cell_w);
var cell_iy = int(mouseY / cell_h);
var cell_cx = (cell_ix+0.5) * cell_w;
var cell_cy = (cell_iy+0.5) * cell_h;
pawn1.x = cell_cx - pawn1.w/2;
pawn1.y = cell_cy - pawn1.h/2;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>

How to find out which part of the circle was clicked, using HTML5 canvas?

I am trying to create Simon game using HTML5 canvas and vanilla JavaScript. I am confused about the coordinate system in the arc() method. I have divided the circle into 4 quadrants and would like to alert the number of the quadrant clicked. But, I am not sure how to find out which part of the circle was clicked. https://jsfiddle.net/xawpLdys/1/
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var pads = [];
var angle = 2 * Math.PI / 4;
var color = ["green","red","blue","yellow"];
var Pads = function(x, y, radius, start, end) {
this.x = x;
this.y = y;
this.radius = radius;
this.start = start;
this.end = end;
};
function drawSimon(radius) {
for (var i = 0; i < 4; i++) {
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, i*angle, (i+1)*angle, false);
context.lineWidth = radius;
context.fillStyle = color[i];
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#444';
context.stroke();
var pad = new Pads(x, y, radius, i*angle, (i+1)*angle);
pads.push(pad);
}
}
drawSimon(150);
$('#myCanvas').click(function (e) {
/*for (var i = 0; i < pads.length; i++) {
if (//condition matches) {
alert (i);
}
}*/
});
Try This
This example just translates the clicked e.pageX and e.pageY to normal quadrant system. And after some condition, you can determine which part has been clicked.
$('#myCanvas').click(function (e) {
var nx,ny;
nx=-(x- e.pageX);
ny=y- e.pageY;
if (nx>0 && ny>0){
alert('Yellow');
}else if (nx<0 && ny>0){
alert('Blue');
}else if (nx>0 && ny<0){
alert('Green');
}else if (nx<0 && ny<0){
alert('Red');
}
});
Here is the fiddle https://jsfiddle.net/xawpLdys/3/
UPDATE
John S was right, (It counts clicks that are outside the circle). To prevent the clicks outside the circle from considering, we need to just find the distance from the center of the circle and the clicked point. Then compare the distance with the circle's radius to see it is inside radius.
The updated code :
$('#myCanvas').click(function (e) {
var nx,ny;
nx=-(x- e.pageX);
ny=y- e.pageY;
var dx = Math.abs(Math.abs(x)-Math.abs(e.pageX));
var dy = Math.abs(Math.abs(y)-Math.abs(e.pageY));
var distance_clicked = Math.sqrt((dx*dx)+(dy*dy));
if(distance_clicked <= radius){
if (nx>0 && ny>0){
alert('Yellow');
}else if (nx<0 && ny>0){
alert('Blue');
}else if (nx>0 && ny<0){
alert('Green');
}else if (nx<0 && ny<0){
alert('Red');
}
}
});
Here is the updated fiddle https://jsfiddle.net/xawpLdys/8/
It still have the limitations of dividing the circle more than 4 slices.
The accepted answer seems a bit limited. It counts clicks that are outside the circle. That could be fixed fairly easily, but it would still be limited to four sections.
To determine if a point is in a sector:
First check if it is within the circle. The Pythagorean theorem comes into play here. Square the x and y values, if their sum is less than or equal to the radius squared, the point is in the circle.
If the point is in the circle, then check if its angle is between the start and end angles for the sector. You can get the point's angle using the arc tangent function from trigonometry.
Try this jsfiddle.
Here are the types that help make this work:
var Circle = function(center, radius) {
this.center = center;
this.radius = radius;
this._radiusSquared = Math.pow(this.radius, 2);
}
$.extend(Circle.prototype, {
containsPoint: function(point) {
var relPoint = this.pointToRelPoint(point);
return Math.pow(relPoint.x, 2) + Math.pow(relPoint.y, 2)
<= this._radiusSquared;
},
getAngleForPoint: function(point) {
var relPoint = this.pointToRelPoint(point);
return Math.atan2(-relPoint.y, -relPoint.x) + Math.PI;
},
pointToRelPoint: function(point) {
return { x: point.x - this.center.x, y: point.y - this.center.y }
}
});
var CircleSector = function(startAngle, endAngle) {
this.startAngle = startAngle;
this.endAngle = endAngle;
};
$.extend(CircleSector.prototype, {
containsAngle: function(angle) {
return (angle >= this.startAngle) && (angle < this.endAngle);
},
containsPoint: function(circle, point) {
return circle.containsPoint(point)
&& this.containsAngle(circle.getAngleForPoint(point));
}
});

HTML Canvas - Draw Rectangles at selected location

I'm making a simple game with AngularJS and I wanted to add a canvas to the game. I never used it before and I'm still learning. I don't know how to do the following:
I made a grid to be easier to look at it. So what I want is when the user click on a rectangle, that rectangle should be filled with a color.
var builder = function () {
var build_canvas = document.getElementById("builder-canvas");
var build_context = build_canvas.getContext("2d");
var x;
for (x = 0.5; x <= 800; x += 15) {
build_context.moveTo(x, 0);
build_context.lineTo(x, 390);
}
var y;
for (y = 0.5; y < 400; y += 10) {
build_context.moveTo(0, y);
build_context.lineTo(796, y);
}
build_context.strokeStyle = "#000000";
build_context.stroke();
};
builder();
Here is a fiddle: http://jsfiddle.net/JQd4j/
Thank you in advance.
Simply quantize the x and y values you get from mouse position on click:
build_canvas.onclick = function(e) {
var rect = build_canvas.getBoundingClientRect(), // canvas abs. position
x = e.clientX - rect.left, // relative x to canvas
y = e.clientY - rect.top; // relative y to canvas
x = ((x / 15)|0) * 15; // quantize x by 15
y = ((y / 10)|0) * 10; // quantize y by 10
build_context.fillRect(x+1, y+1, 14, 9); // fill rectangle
}
This quantizing does:
(x / 15)|0
divide by 15 and remove fraction. Then multiply it up again by the same number to get the start position of the cell:
((x / 15)|0) * 15
and the same for y.
Modified fiddle

Canvas: How would you properly interpolate between two points using Bresenham's line algorithm?

I am making a simple HTML5 Canvas drawing app where a circle is placed at a x and y position each time the mouse moves. The (quite common but unsolved) problem is: when the mouse is moved very fast (as in faster than the mouse move events are triggered), you end up with space in between the circles.
I have used Bresenham's line algorithm to somewhat successfully draw circles between the gaps. However, I have encountered another problem: when the color is one of translucency I get an unintentional fade-to-darker effect.
Here's an example:
I don't understand why this is happening. How would you properly interpolate between two points using Bresenham's line algorithm? Or some other algorithm?
Here's my code: http://jsfiddle.net/E5NBs/
var x = null;
var y = null;
var prevX = null;
var prevY = null;
var spacing = 3;
var drawing = false;
var size = 5;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function createFlow(x1, y1, x2, y2, callback) {
var dx = x2 - x1;
var sx = 1;
var dy = y2 - y1;
var sy = 1;
var space = 0;
if (dx < 0) {
sx = -1;
dx = -dx;
}
if (dy < 0) {
sy = -1;
dy = -dy;
}
dx = dx << 1;
dy = dy << 1;
if (dy < dx) {
var fraction = dy - (dx >> 1);
while (x1 != x2) {
if (fraction >= 0) {
y1 += sy;
fraction -= dx;
}
fraction += dy;
x1 += sx;
if (space == spacing) {
callback(x1, y1);
space = 0;
} else {
space += 1;
}
}
} else {
var fraction = dx - (dy >> 1);
while (y1 != y2) {
if (fraction >= 0) {
x1 += sx;
fraction -= dy;
}
fraction += dx;
y1 += sy;
if (space == spacing) {
callback(x1, y1);
space = 0;
} else {
space += 1;
}
}
}
callback(x1, y1);
}
context.fillStyle = '#FFFFFF';
context.fillRect(0, 0, 500, 400);
canvas.onmousemove = function(event) {
x = parseInt(this.offsetLeft);
y = parseInt(this.offsetTop);
if (this.offsetParent != null) {
x += parseInt(this.offsetParent.offsetLeft);
y += parseInt(this.offsetParent.offsetTop);
}
if (navigator.appVersion.indexOf('MSIE') != -1) {
x = (event.clientX + document.body.scrollLeft) - x;
y = (event.clientY + document.body.scrollTop) - y;
} else {
x = event.pageX - x;
y = event.pageY - y;
}
context.beginPath();
if (drawing == true) {
if (((x - prevX) >= spacing || (y - prevY) >= spacing) || (prevX - x) >= spacing || (prevY - y) >= spacing) {
createFlow(x, y, prevX, prevY, function(x, y) {
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
});
prevX = x, prevY = y;
}
} else {
prevX = x, prevY = y;
}
};
canvas.onmousedown = function() {
drawing = true;
};
canvas.onmouseup = function() {
drawing = false;
};
HTML Canvas supports fractional / floating point coordinates, so using an algorithm for integer coordinate based pixel canvas is not necessary and could be considered even counter-productive.
A simple, generic solution would be something along these lines:
when mouse_down:
x = mouse_x
y = mouse_y
draw_circle(x, y)
while mouse_down:
when mouse_moved:
xp = mouse_x
yp = mouse_y
if (x != xp or y != yp):
dir = atan2(yp - y, xp - x)
dist = sqrt(pow(xp - x, 2) + pow(yp - y, 2))
while (dist > 0):
x = x + cos(dir)
y = y + sin(dir)
draw_circle(x, y)
dist = dist - 1
That is, whenever the mouse is moved to a location different from the location of the last circle drawn, walk towards the new location with steps having distance one.
If I understand well, you want to have rgba(0, 0, 0, 0.1) on every point. If so, then you can clear the point before drawing new one.
// this is bad way to clear the point, just I don't know canvas so well
context.fillStyle = 'rgba(255, 255, 255, 1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
I've figured it out.
"context.beginPath();" needed to be in the createFlow callback function like so:
createFlow(x, y, prevX, prevY, function(x, y) {
context.beginPath();
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
});

Categories

Resources