clientY is not displaying the right thing - javascript

I know that the title seems a bit weird, but i'm trying to create a drawing app. I have a javascript generated table that is 17 by 36 and I am trying to make it so that whenever you click in a box it colors it black. Below is the code (here it acts weirder because they are not 30 by 30 pixels)
var array = [];
var body = document.body, tbl = document.createElement("table");
tbl.style.border = "1px solid black";
tbl.style.borderCollapse = "collapse";
tbl.setAttribute("border", "1px");
tbl.style.margin = "0px";
tbl.setAttribute("onClick", "color(event)");
var id = 1;
for (var j = 0; j < 17; j++) {
var row = tbl.insertRow();
row.setAttribute("id", id.toString());
id++;
for (var ij = 0; ij < 36; ij++) {
var cell = row.insertCell();
cell.style.width = "28px";
cell.style.height = "28px";
}
}
body.appendChild(tbl);
function color(event) {
var x = event.clientX;
var y = event.clientY;
console.log(x + " = x");
console.log(y + " = y");
console.log((x/30) + " = x/30");
console.log((y/30) + " = y/30");
x = Math.ceil(x / 30);
y = Math.ceil(y / 30);
if (x == 37) {x = 36}
if (y == 18) {y = 17}
console.log(x + "x after");
console.log(y + "y after");
document.getElementById(y.toString()).childNodes[x - 1].style.background = "black";
}
<!DOCTYPE html>
<html>
<head>
<title>Program</title>
<style>
body {
margin: 0px;
}
</style>
</head>
<body>
<script src="program.js"></script>
<button onClick="calculate()"></button>
</body>
</html>
When I click a square in the 10th row, it colors it black. When I click it in a row near the bottom, starting from the 13th row, it goes 5 squares up. Also, if I click in the second half of a square (from the left or from the top) it thinks it's the next square over! Please help!

As already mentioned in a comment, you are making this problem more complicated than it actually is. When you click an element, it generates a click event which contains a reference to the element that the event is for. In your case it already references the td-element that you want to change.
So: Simply use event.target and you are good to go.
/* Creating the table */
var array = [];
var body = document.body,
tbl = document.createElement("table");
tbl.style.border = "1px solid black";
tbl.style.borderCollapse = "collapse";
tbl.setAttribute("border", "1px");
tbl.style.margin = "0px";
tbl.setAttribute("onClick", "color(event)");
var id = 1;
for (var j = 0; j < 17; j++) {
var row = tbl.insertRow();
row.setAttribute("id", id.toString());
id++;
for (var ij = 0; ij < 36; ij++) {
var cell = row.insertCell();
cell.style.width = "28px";
cell.style.height = "28px";
}
}
body.appendChild(tbl);
function color(event) {
var node = event.target;
var parent = node.parentNode;
//Probably a tbody, but we don't care as long as it is the parent
var table = parent.parentNode;
var column = [].slice.call(parent.childNodes).indexOf(node);
var row = [].slice.call(table.childNodes).indexOf(parent);
console.log(column);
console.log(row);
node.style.background = "black";
}
Edit: Since you asked how to update your array, I'll expand a bit on this. You have a reference to the DOM. If you need to track if the particular item is black, you can simply check it's style in the DOM. No need to keep a global array for this. Use console.log( node ) if you are curious as to what you have available to you, or (better) use the documentation on MDN.
If you need the array for a different reason, you can use the node.parentNode and node.childNodes methods. Please note that the last method returns a NodeList; it looks like an Array, but it is actually not an array. To use array-specific functions on it, we convert it to an array with [].slice.call( NodeList ). Instead of [] you could use Array.prototype. I can't tell if it would behave any differently in some browsers.

Related

Javascript how to change the color of a button when clicked?

I am new to Javascript. I want to create a 15x15 table full of buttons and change the color of the button to red when clicking each one. The table is fine but the color is not working.
function createTable(){
var table = document.createElement('table');
for(var x = 0; x < 15; x++) {
var row = table.insertRow();
for(var y = 0; y < 15; y++) {
var cell = row.insertCell();
var button = cell.appendChild(document.createElement('button'));
var buttID = String('butt' + '_' + x + '_' + y);
button.setAttribute('id', 'buttID');
button.setAttribute('onclick', 'mark()');
}
}
document.getElementById('puzzle').appendChild(table);
}
function mark(){
document.getElementById('buttID').style.color = "red";
}
I am not sure if the button.setAttribute is wrong. I also tried the following way, but the entire table just disappears this time. Any ideas about that?
button.onclick = mark();
Maybe the way I create id for every cell is wrong? I am not sure about that.
This line is wrong and will not work:
document.getElementById('buttID').style.color = "red";
That is attempting to access a button with id equal to the string "buttID", but there is no such button.
But you don't need ids on the buttons at all. Instead, you can set the button's onclick function like this:
button.onclick = mark;
Then, define your mark function like this:
function mark() {
let button = this; // 'this' is the button that was clicked
button.style.color = 'red';
}
function createTable() {
var table = document.createElement('table');
for (var x = 0; x < 15; x++) {
var row = table.insertRow();
for (var y = 0; y < 15; y++) {
var cell = row.insertCell();
var button = cell.appendChild(document.createElement('button'));
button.className = 'btn';
button.onclick = mark;
}
}
puzzle.innerHTML = '';
puzzle.appendChild(table);
}
function mark() {
let button = this;
button.style.backgroundColor = "red";
}
const puzzle = document.getElementById('puzzle');
.btn {
border: none;
margin: 0;
width: 1em;
height: 1em;
background-color: white;
}
body {
background-color: #eee;
}
<button onclick="createTable();">Create Table</button>
<div id="puzzle"></div>
Change this:
var cell = row.insertCell();
var button = cell.appendChild(document.createElement('button'));
var buttID = String('butt' + '_' + x + '_' + y);
button.setAttribute('id', 'buttID');
button.setAttribute('onclick', 'mark()');
To this:
var cell = row.insertCell();
// Store the reference to the actual button and not the cell that contains it
var button = document.createElement('button');
// Bind the onclick event of the button to your mark function
// Also remember that you only need the parenthesis if you are calling a function, here we are only passing it
button.onclick = mark;
// Add your button to your table cell
cell.appendChild(button);
You will also have to edit your mark function to look like this:
function mark(e){
e.target.style.background = 'red';
}
This may seem confusing and you are probably asking where that variable 'e' comes from. Basically events like 'onclick' will always pass an event object to their handling functions. By putting a variable in the handling functions parenthesis the event object will automatically be placed into that variable.
The event object has lots of information about the event. You can see all of the information it provides here.
The one we want is the 'target' - the element that triggered the event which will be whatever button that was clicked in this case.
The target is an HTML element so we can then set it's style.background to a value of 'red'.

How to prevent additional table creation

I've been looking for workarounds to ensure that only one table is created. So far the only one i have come up with is to disable the button after it had been pressed. Here is my code:
function bikeData() {
// Select the Table
var tbl = document.getElementById('bikeInnerTable');
var th = document.getElementById('tableHead_B');
var headerText = ["ID", "Bike Status", "Bike Location", "Depot ID"];
// Set number of rows
var rows = 10;
// Set number of columns
var columns = headerText.length;
// create table header
for (var h = 0; h < columns; h++) {
var td = document.createElement("td");
td.innerText = headerText[h];
th.appendChild(td);
}
// create table data
for (var r = 0; r < rows; r++) {
var cellText = ["UNDEFINED", "UNDEFINED", "UNDEFINED", "UNDEFINED"];
// generate ID
x = getRandomNumber(1000, 1);
cellText[0] = x;
// generate Status
x = getStatus();
cellText[1] = x;
// generate Name
x = getLocation();
cellText[2] = x;
// generate depot ID
x = getRandomNumber(1000, 1);
cellText[3] = x;
var tr = document.getElementById("b_row" + r);
for (var c = 0; c < columns; c++)
{
var td = document.createElement("td");
td.innerText = cellText[c];
tr.appendChild(td);
}
}
}
If the button is pressed multiple times then the table is created multiple times. However how can I adapt the code to ensure that it if the table is already present within the div, then it doesn't continue in creating the table additional times.
You can set a flag and then only execute the code when applicable.
let firstTime = true;
function(){
...
if (firstTime) {
firstTime = false;
...
}
}
This is what Javascript variables are for. You can make a variable, then test that against a condition in the function. Let me show you what I mean:
window.timesRan = 0;
function bikeData() {
//Check if the variable is > 1
if (timesRan > 1) {
return false;
}
//code here
//then just add 1 to the variable every time
timesRan += 1;
}
All the best, and I hope my answer works for you :)

How to make button.onClick not run at start

I am confused at to why my function executes before the start button is pressed. I looked around and they said the onclick will run at the start if you don't but the code to be executed when the button is clicked in a function. But mine is a function... This code is supposed to create 4 buttons when the start button is pressed. But right now the 4 buttons appear right away.
EDIT: Here is the full code.
var log = document.getElementById("Log");
log.addEventListener("click", login); // Runs the Login Function
var email;
var password;
// Makes an alert to test input values.
function login() {
form = document.getElementById("form");
var text = "E-Mail: " + form.elements[0].value + " Password: " + form.elements[1].value;
alert (text);
}
// Testing Function
function helloWorld() {
alert ("Hello World");
}
//create the snake
function createSnake() {
var bodyLength = 5; //snake length
var body = []; //snake body
var head = [10, 10]; //snake head starting position;
// create the variables to edit for the body positions loop
var row = head[0];
var col = head[1];
// set the snake body positions
for (var i=0;i<bodyLength; i++) {
body[body.length] = [row, col];
var cord = row + "_" + col;
// Set the head Green
if (i == 0) { document.getElementById(cord).style.backgroundColor = 'green';
}
// Set the Body blue
else {document.getElementById(cord).style.backgroundColor = 'blue';}
row++;
}
}
var snakeBool = false; //Bool to test if the snake game has been pressed.
// Create a table function. Creates a gray table for Snake.
function createTable() {
if (!snakeBool) {
// create a table of data
//target the activity div
var activity = document.getElementById("activity");
//create table
var tbl = document.createElement("table");
//table styles
tbl.style.borderCollapse = "collapse";
tbl.style.marginLeft = '12.5px';
//create size var
//var size = '5px';
//set the row and column numbers
var tr_num = 30;
var td_num = 25;
//start the loops for creating rows and columns
for (var i = 0; i < tr_num; i++) {
var tr = document.createElement("tr"); // create row
//tr style
tr.style.height = '7px';
for (var j = 0; j < td_num; j++) { //start loop for creating the td
var td = document.createElement("td"); //create td
td.style.width = '5px';
if (i == 0 || i == (tr_num-1) || j == 0 || j == (td_num-1)) {
td.style.backgroundColor = "white";
}
else {
td.style.backgroundColor = "gray";
}
td.id = i + "_" + j; //set id to td
//td.appendChild("data"); //append data to td
tr.appendChild(td); //append td to row
}
tbl.appendChild(tr); //append tr to the table
}
activity.appendChild(tbl); //append the table to activity div
createSnake(); //Creates the snake body.
snakeBool = true; //Sets the Snake Bool to true since game has been created.
//create Start button
var b1 = document.createElement("input");
b1.type = "button";
b1.value = "Start";
b1.onClick = startGame;
activity.appendChild(b1);
} // end of if Function
}
function startGame() {
createButtons();
}
function createButtons() {
var b1 = document.createElement("input");
b1.type = "button";
b1.value = "Up";
//b1.onClick = func
activity.appendChild(b1);
var b2 = document.createElement("input");
b2.type = "button";
b2.value = "Down";
//b1.onClick = func
activity.appendChild(b2);
var b3 = document.createElement("input");
b3.type = "button";
b3.value = "Left";
//b1.onClick = func
activity.appendChild(b3);
var b4 = document.createElement("input");
b4.type = "button";
b4.value = "Right";
//b1.onClick = func
activity.appendChild(b4);
}
// when button is pressed, do createTable function
document.getElementById("gamesButton").addEventListener("click", createTable);
Using the brackets, you’re immediately invoking the startGame function. Its return value is then assigned to the onClick property.
You most likely want to assign the function itself, so it’s executed when the onClick event fires. To do so, change this
b1.onClick = startGame();
to this
b1.onClick = startGame;

chess board using javascript and dom

I'm trying to create a chessboard just like this.
I did create a table And don'r know how to colour it. A also need to print the board name (like A1, A2, ... H8) and be able to pust any figuere in any of the cell.
For start this is the code to create a table:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ChessBoard</title>
<script type="text/javascript">
function CreateTable(){
var poz = document.getElementById('space');
// createing table adn inserting into document
tab = document.createElement('table');
poz.appendChild(tab);
tab.border = '5';
for (var i = 0; i < 8; i++){
// creating row and inserting into document
var row = tab.insertRow(i);
for(var j = 0; j < 8; j++){
// creating cells and fill with data (numbers)
var cell = row.insertCell(j);
cell.innerHTML = i*j;
cell.style.backgroundColor = 'blue';
cell.style.color = 'white';
cell.style.height = '50px';
cell.style.width = '50px';
};
};
}
</script>
</head>
<body onload="CreateTable()" id ="space">
</body>
</html>
How do i fill specific cell with figure (like A3, E5, H8, ...)? Figure are imgages.
Part 2:
I did create a board with your help.
Now I'm trying to do some more from this code.
How do I put several different images into several cells? I'm trying to get right working code, but with no success. This images should appear when the tabel will be loaded (when i press button CreateTable).
I try to create with this code:
In this point I would like to put figures on board. When i create table it should be blank. Then there will be buttons to add figures. At the beginning for each different figure own button
something like this:
function addKing(idStr){
cell = document.getElementById(idStr);
if(cell != null){
// works for color, doesn't work for images!!
// cell.style.backgroundColor = 'red';
cell.src = 'http://akramar.byethost8.com/images/SplProg/DN3/images/50px/king_m.png'
}
}
Button addKing in html:
<button id="king" onclick="addKing(prompt('Insert field'))">Add King</button>
upgrading previousu code to even better if i can put all together and select which one I like to insert (promtpt window 1: what figure:'king, queen, ...', prompt window 2: on what position would you like to insert: 'A1, B3, ...')).
function addImage (type, position){
var img = ??
}
When I pres button add image the prompt window should appear and ask for type (king, queen, root, ...) and location (A1, B4, ...) (for further update perhaps even color (black or white) but let build step by step).
All tis chessboard I would like to build just in javascript and with dom.
link to not working exaple: jsfiddle
Assuming you need to support only modern browsers, the chess-board is entirely do-able with CSS using counters, and generated-content:
table {
empty-cells: show;
}
td {
width: 2em;
height: 2em;
line-height: 2em;
text-align: center;
border: 1px solid #000;
}
tbody tr:nth-child(odd) td:nth-child(even),
tbody tr:nth-child(even) td:nth-child(odd) {
color: #fff;
background-color: #00f;
}
tbody tr:nth-child(even) td:nth-child(even),
tbody tr:nth-child(odd) td:nth-child(odd) {
background-color: #999;
}
tbody {
counter-reset: rowNumber;
}
tr {
counter-increment: rowNumber;
counter-reset: cellNumber;
}
td {
counter-increment: cellNumber;
}
td::before {
content: counter(rowNumber, upper-alpha) counter(cellNumber, decimal);
}
JS Fiddle demo.
The above tested in Chromium 24 and Firefox 19, both on Ubuntu 12.10.
And for a JavaScript approach:
var chess = {
createBoard: function (dimension) {
if (!dimension || isNaN(dimension) || !parseInt(dimension, 10)) {
return false;
} else {
dimension = typeof dimension === 'string' ? parseInt(dimension, 10) : dimension;
var table = document.createElement('table'),
tbody = document.createElement('tbody'),
row = document.createElement('tr'),
cell = document.createElement('td'),
rowClone,
cellClone;
table.appendChild(tbody);
for (var r = 0; r < dimension; r++) {
rowClone = row.cloneNode(true);
tbody.appendChild(rowClone);
for (var c = 0; c < dimension; c++) {
cellClone = cell.cloneNode(true);
rowClone.appendChild(cellClone);
}
}
document.body.appendChild(table);
chess.enumerateBoard(table);
}
},
enumerateBoard : function (board) {
var rows = board.getElementsByTagName('tr'),
text = document.createTextNode(),
rowCounter,
len,
cells;
for (var r = 0, size = rows.length; r<size; r++){
rowCounter = String.fromCharCode(65 + r);
cells = rows[r].getElementsByTagName('td');
len = cells.length;
rows[r].className = r%2 == 0 ? 'even' : 'odd';
for (var i = 0; i<len; i++){
cells[i].className = i%2 == 0 ? 'even' : 'odd';
cells[i].appendChild(text.cloneNode());
cells[i].firstChild.nodeValue = rowCounter + i;
}
}
}
};
chess.createBoard(10);
JS Fiddle demo.
You can tie an ID to the cell, and then use that ID to reference and updated the background as needed. Here is one example using your code: http://jsfiddle.net/7Z6hJ
function CreateTable(){
var poz = document.getElementById('space');
// createing table adn inserting into document
tab = document.createElement('table');
poz.appendChild(tab);
tab.border = '5';
for (var i = 0; i < 8; i++){
// creating row and inserting into document
var row = tab.insertRow(i);
for(var j = 0; j < 8; j++){
// creating cells and fill with data (numbers)
var cell = row.insertCell(j);
var idStr = String.fromCharCode(97 + i).toUpperCase() + (j+1);
cell.innerHTML = idStr;
cell.id = idStr;
cell.style.backgroundColor = 'blue';
cell.style.color = 'white';
cell.style.height = '50px';
cell.style.width = '50px';
};
};
}
function updateRow(idStr)
{
cell = document.getElementById(idStr);
if(cell != null)
{
cell.style.backgroundColor = 'red';
}
}
As some have mentioned, there is probably a better way to go about this (using css and jQuery, etc) but this answer sticks with what you have so far.
Create a new variable inside the top loop to save the "letter" name of the row (eg. A, B, C).
// creating row and inserting into document
var row = tab.insertRow(i);
var row_letter = String.fromCharCode(65 + i);
Then in the second loop combine the row name and column number.
cell.innerHTML = row_letter + j;
Actually, you need to do some math for correctly coloring and adding labels. Here is the part of code for doing magic:
1 cell.innerHTML = String.fromCharCode(65 + i) + (j + 1);
2 if((i+j)%2){ cell.style.backgroundColor = 'white'; }
3 else{ cell.style.backgroundColor = 'blue'; }
4 cell.style.color = 'black';
5 cell.style.height = '50px';
6 cell.style.width = '50px';
Let me explain. In first line, you take constant 65, which is ASCII code for letter 'A'. While you change the letter by rows, you add i counter to it, so you get 65+0, 65+1, ..., 65+7. Their ASCII equivalents (which you get with String.fromCharCode()) are A, B, ..., H. Now when you have that letter, easily add number of cell to it (j + 1). You can remove '1' and leave just j and make inner loop go from 1 to 8.
Lines 2, 3: Colors are alternating - every second row have the same color. So, just test if is i+j dividable by 2.
For adding figure, you have to make some function that will do cell.innerHTML = <SOME IMAGE>. But, I guess, it's for second question.
Hope I helped you understand the logic.
I case if someone is looking for a way to visualize a chessboard using JS (as I was doing and accidentally came to this question), here is an excellent JS library to do this.
It can create something like this
and much more in no time just by doing the following:
JavaScript
var ruyLopez = 'r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R';
var board = new ChessBoard('board', ruyLopez);
HTML
<div id="board" style="width: 400px"></div>

Trouble with Javascript table colspan

I'm trying to make some of my columns span for readability, as well as pattern recognition. I'm also changing the background color of the cells to show patterns. If the data in my array is null, I use red. If it is not null and spans at least 2 columns, it is blue, otherwise, it is grey. I'm finding that some of my columns are wider than they should be, and some are shorter. With my data, the first columns are the only ones too wide, and the last are the only ones too short. So far as I can tell however, their colors are correct. I can give example code, but not example data as it is highly confidential. I can give the code, and will. Why are some of my columns wider, and others shorter than I expect them to be?
function loadTable() {
var fields = JSON.parse(localStorage.getItem("boxFields"));
var report = JSON.parse(localStorage.getItem("boxReport"));
var space = document.getElementById("batchReport");
var baseList = document.createElement("ul");
space.appendChild(baseList);
for (var i = 0; i < fields.length; i++) {
var li = document.createElement("li");
baseList.appendChild(li);
var header = document.createElement("h2");
header.textContent = fields[i] + ":";
li.appendChild(header);
if (report.length > 0) {
var table = document.createElement("table");
table.className += "wide";
li.appendChild(table);
var tr = document.createElement("tr");
table.appendChild(tr);
var td = document.createElement("td");
td.colSpan = report.length;
tr.appendChild(td);
tr = document.createElement("tr");
table.appendChild(tr);
var compare = "NeverEqual";
var count = 0;
td = null;
for (var j = 0; j < report.length; j++) {
if (compare == report[j][i]) {
count++;
td.colSpan = count;
if (compare != null)
td.style.backgroundColor = "#336";
} else {
count = 1;
compare = report[j][i];
td = document.createElement("td");
tr.appendChild(td);
td.textContent = report[j][i];
//td.colSpan = 1;
if (compare != null)
td.style.backgroundColor = "#333";
else {
td.style.backgroundColor = "#633";
}
}
}
}
}
space.style.height = "93%";
space.style.overflow = "auto";
}
Your not specifying explicit widths for the table cells so they'll be auto calculated based on their content and the fallback logic the browser / IE does. If you want to have a cell have a specific width apply either a class to it or set it's with property explicity, e.g.:
td.style.width = "50px";
Or
td.className = "myCell";
// and in css somewhere define the class
.myCell{
width: 50px;
}

Categories