How can I implement click-and-hold drawing with plain JavaScript - javascript

I'm making a pixel art maker, and I can color individual divs in my grid; however, I want the user to be able to click, hold, and drag to continually draw. There've been similar questions to mine, but they seemed to need jQuery or not exactly apply to me.
https://jsfiddle.net/8okf4yg0/2/
//create cell listeners
function listenCells() {
let cell = document.querySelectorAll('.grid-square');
cell.forEach((cell) => {
cell.addEventListener('mouseenter', function() {
cell.style.backgroundColor = color;
});
});
}
is there someway to combine mouseenter and mousedown? Or is there a better solution?

Add mousedown and mouseup listeners to the parent container and have them toggle a flag variable.
Then check that flag before changing the cells.
Simple demo using a table
/* Flag to know if mosue is down on table */
let MDOWN = false;
const tbl = document.querySelector('table')
createRows();
['mousedown', 'mouseup'].forEach(eName => tbl.addEventListener(eName, () => MDOWN = !MDOWN));
function cellEnter() {
if (MDOWN) {
this.style.backgroundColor = 'black';
}
}
function createRows() {
for (let i = 0; i < 50; i++) {
const row = tbl.insertRow()
for (let j = 0; j < 50; j++) {
let cell = row.insertCell();
cell.addEventListener('mouseenter', cellEnter)
}
}
}
td {
height: 10px;
width: 10px;
border: 1px solid #ccc
}
table {
border-collapse: collapse;
}
<table>
</table>

Related

Javascript: cannot access "style" property for div elements in array

I'm making a simple tic tac toe game as my introduction to JS and I ran into a problem almost immediately. I have a div with the class="container", and I use JS to create 9 more div elements inside it.
I have created the div elements with and put them in the cells[] array with no problem. The problem arrises when i try to access .style from the array elements.
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) {
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} //this line is where the problem is
i++;
}
I have gone about this using addEventHandler() too, still with me not being able to access the .style property. When I type it in it doesn't show up on that autofill thing VSCode does.
Help?
Ps. I have noticed the cells[] array can't always access it's elements when inside a block.
This issue is due to how closures work in JavaScript.
Here's a demo with your current code (plus some CSS to make it clear what's happening):
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) { // actually, the problem is here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} // ...here...
i++; // ...and here
}
div:not([class]) {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
Note that the next div is always highlighted, not the one that was clicked.
Because you increment i within the block itself, that value is captured by the onclick callback, so it's always 1 higher than it should be.
Instead, you need to increment i within the parentheses as the third setup statement for the loop itself.
Here's the fix:
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9; ++i) { // increment here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function() { cells[i].style.backgroundColor = "red"; }
// ...not here
}
div {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}
.setWidth {
width: 100px;
height: 100px;
border: 1px solid black;
}
<div class="container"></div>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}

8x8 div matrix onclick effectivization

I would like to have an 8x8 matrix where I can click on each square and the color will change, for use in a project.
I have made a 2d array and the entire 8x8 "board" but now I want to change to color on click, although the only way I can think of is through heavy code, for example writing div[row][column] 64 times...
var div = new Array(8);
for(var i = 0; i<8; i++){
div[i] = new Array(8)
}
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
div[i][j] = document.createElement("div");
div[i][j].style.width = "50px";
div[i][j].style.height = "50px";
div[i][j].style.backgroundColor = "white";
document.getElementById("container").appendChild(div[i][j]);
}
var jump = document.createElement("br");
document.getElementById("container").appendChild(jump);
}
div[0][0].onclick = function(){
if(div[0][0].style.backgroundColor == "white"){
div[0][0].style.backgroundColor = "red"
d00 = 1
}
else{div[0][0].style.backgroundColor = "white"
d00 = 0
}
}
I don't wish to write the above 64 times, surely there must be a better way.
#container {
margin: auto;
width:400px;
height:400px;
}
#container div {
display:inline-block;
vertical-align:top;
outline: 1px solid black
}
You can attach the onclick event to the parent container and use event.target to get the div which triggered the event:
document.getElementById("container").onclick = function(event){
if(event.target.style.backgroundColor == "white"){
event.target.style.backgroundColor = "red";
}
else{
event.target.style.backgroundColor = "white";
}
}
Indeed, there is a better way.
Inside the for-loop you're already setting important properties of your DIVs. It's the perfect place to attach an click eventListener whose callback function will handle the color switching.
Modify the for-loop like this:
var divElement;
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
divElement = document.createElement("div");
divElement.style.width = "50px";
divElement.style.height = "50px";
divElement.style.backgroundColor = "white";
divElement.addEventListener("click", changeColor);
document.getElementById("container").appendChild(divElement);
}
and use this function to actually change the color:
function changeColor(e) {
if (e.target.style.backgroundColor == "white") {
e.target.style.backgroundColor = "red"
d00 = 1
} else {
e.target.style.backgroundColor = "white"
d00 = 0
}
}
e.target refers to the object that triggered the event.
Forgive me, I don't know the purpose of d00.

In a grid built in javascript and html, how do I assign a new text-node value to all cells in the grid that fulfils a condition

I am relatively new to DOM manipulation with JS and html. Here I am having to build a 10 * 10 grid, with sequential numbers in each cells representing its text node. And the requirement is that, when I click on any cell in the grid, if its text node value is 5 or a multiple of 5, then the text node of this cell and also all other cells in the grid which are multiples of 5 should be replaced with a "**".
Here's my code till now, but I am just failing to implement the conditional replacement of the cell's text node value on a click event. And here's my jsfiddle
Many thanks in advance.
<html>
<head>
<meta charset="utf-8">
<title>Grid with random numbers</title>
<style>
#grid {
margin: 10px;
font-size: 1.25em;
}
table {
border-collapse: collapse;
border: 1px solid #7f7f7f;
}
td {
border: 1px solid #7f7f7f;
width: 50px;
height: 50px;
text-align: center;
}
</style>
</head>
<body>
<div id="grid"></div>
<script>
let totalRows = 10;
let cellsInRow = 10;
let min = 1;
let max = 100;
function drawTable() {
let cellNumber = 1;
let grid = document.getElementById('grid');
let tbl = document.createElement("table");
// Create rows in the table
for (var r = 0; r < totalRows; r++) {
let row = document.createElement("tr");
row.setAttribute('id', (r));
// In each row now create cells
for (var c = 0; c < cellsInRow; c++) {
let cell = document.createElement("td");
let cellText = document.createTextNode(cellNumber++);
let cellFillingStar = document.createTextNode("**");
// each cell should have its 'id' attribute set, as its corresponding cellText value
cell.setAttribute('id', (cellNumber - 1));
cell.appendChild(cellText);
row.appendChild(cell);
// Code to check that each cell got its 'id' attribute set, as its corresponding cellText value.
cell.addEventListener(
"click",
function(e) {
var id = e.target.id;
if (id % 5 == 0) {
$('.table').each(function() {
$(this).find('id').each(function() {
alert("Multiple of 5");
cell.appendChild(cellFillingStar);
})
})
}
},
false);
}
tbl.appendChild(row);
}
grid.appendChild(tbl);
}
window.onload = drawTable;
</script>
</body>
First of all there are some error in your script, like you're trying to loop on a .table object that doesn't exist, as table has no class.
I've tried to simplify it a little bit, using jquery.
the main snippet I've added is this one:
$( "#grid table tr td" ).on( "click", function(event) {
var id = event.target.id;
if (id % 5 == 0) {
$( "#grid table tr td" ).each(function( index ) {
if ($(this).text() % 5 == 0) {
$(this).text($(this).text()+'**');
}
});
}
});
where you assign the event to all td elements, and then, based on their content or id value, you change the text of all relevant td that are multiple of 5.
here is the full working example:
https://jsfiddle.net/xpvt214o/88139/

selecting multiple table row using shift key and control key is not working

hi i have a editable table which is created by using java script.here i use some code for selection process .i want select table row using control key and shift key . i get the code from
[1]: http://jsfiddle.net/g8Rpe/ here. this example shown for html table .but my table is daynamic one
the code is here:
/******for table**************/
$(function () {
function tableCreate() {
var body = document.body,
tbl = document.createElement('table');
tbl.style.width = '100%';
tbl.style.borderCollapse = 'collapse';
for (var i = 0; i < 30; i++) {
var tr = tbl.insertRow();
tr.setAttribute("data-id", i, 0);
for (var j = 0; j < 3; j++) {
var td = tr.insertCell();
td.appendChild(document.createTextNode(''));
}
}
$("body").append(tbl);
$("td").addClass("mainheading4")
$("tr").on("onmousedown=RowClick(this,false)")
}
tableCreate();
//******************for editable table*************************//
$('td').click(function () {
$('td').attr('contenteditable', 'true');
})
//************for multiple selection*****************//
var lastSelectedRow;
var trs = document.getElementById('table').tBodies[0].getElementsByTagName('tr');
// disable text selection
document.onselectstart = function () {
return false;
}
function RowClick(currenttr, lock) {
if (window.event.ctrlKey) {
toggleRow(currenttr);
}
if (window.event.button === 0) {
if (!window.event.ctrlKey && !window.event.shiftKey) {
clearAll();
toggleRow(currenttr);
}
if (window.event.shiftKey) {
selectRowsBetweenIndexes([lastSelectedRow.rowIndex, currenttr.rowIndex])
}
}
}
function toggleRow(row) {
row.className = row.className == 'selected' ? '' : 'selected';
lastSelectedRow = row;
}
function selectRowsBetweenIndexes(indexes) {
indexes.sort(function (a, b) {
return a - b;
});
for (var i = indexes[0]; i <= indexes[1]; i++) {
trs[i - 1].className = 'selected';
}
}
function clearAll() {
for (var i = 0; i < trs.length; i++) {
trs[i].className = '';
}
}
});
body{font-size:62.5%;}
td { padding: 0.2em 0.4em; }
.selected { background: lightBlue }
.mainheading4{
border: 1px solid;
border-color: lightgray;
width:33.3%;
height:17px;
font-size:15px;
padding-left: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
i use
$("tr").on("mousedown=RowClick(this,false)") <
for getting mouse event.
but its not taken.
There are couple of wrong doings.
1) Assign id to table without which you will not get table rows as in below line
var trs = document.getElementById('table').tBodies[0].getElementsByTagName('tr');
E.g. In your tableCreate method add below lines of code.
var body = document.body,
tbl = document.createElement('table'),
tableId = document.createAttribute('id');
tableId.value = "table";
tbl.setAttributeNode(tableId);
2) Second register mouse down event like suggested by feela,
$(document).on('click', 'tr', function () {
RowClick(this, false);
});
Hope it will resolve your issue.
This is not a valid syntax for on. See: http://api.jquery.com/on/
What you probably meant was:
$("tr").on("mousedown", function(event) {
RowClick(event.target, false);
});

How to change a cell's background color javascript

The goal is to change the color of a cell when it is clicked. There is my js code below. As you can see I tried the style.backgroundColor, but only the right bottom cell changed it's color regardless the clicked cell.
var board = document.getElementById("tab"),
lvl1 = {rows: 5, cols: 5};
for(var i=0; i<lvl1.rows; i++){
var row=board.insertRow();
for(var j=0; j<lvl1.cols; j++) {
var cell = row.insertCell();
}
}
board.onclick = function(e) {
var cellIndex = e.target.cellIndex;
var rowIndexx = e.target.parentNode.rowIndex;
console.log(cellIndex + ".." + rowIndexx);
cell.style.backgroundColor = "red";
};
table { margin: 0 auto; }
td {
height: 20px;
width: 20px;
border: 1px solid;
cursor: pointer;
}
<table id="tab"></table>
Replace:
cell.style.backgroundColor="red";
with
e.target.style.backgroundColor="red";
This will set the background for whatever is clicked on, which will be your elements. The alternative is to keep a two-deminsional array around of your cells ( cell[row][column] ) that you can get the proper cell from using your indexes.

Categories