I am trying to catch when user press left button on mouse while hovering over cells in a html table using vanilla javascript. The purpose is to paint a cell in black when user is clicking with mouse while dragging (drawing like in MsPaint, when you draw a line for example)

I added an "over" event listener on each td of my table and used buttons property to check if left button is pressed or not:

celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("mouseover", function(e){
if(e.buttons == 1 ){
    e.target.style.backgroundColor="black";
}
})

This code works but not always and not perfectly. First it starts setting the background color of the next element, not the one on which I pressed the mouse. Moreover, sometimes it doesn't set any color at all (there is a small icon like "accessed denied" in Chrome's window). It appears to work quite randomly and unpredicatably.

I tried also with jQuery, but I found similar problems. Anyone can help me? Thanks a lot

4 Answers

-3
Sergiu On

Isn't it easier to just add a listener for "click" ? If the element is clicked it also over the cell.

celle[i].addEventListener("click", function(e){
   e.target.style.backgroundColor="black";
}
0
Auskennfuchs On

Split the problem into several parts. I would add a mousedown and mouseup eventlistener to the whole window and set a global state if you're currently drawing:

var drawState=false
window.addEventListener("mousedown",function(e){
if(e.button===1){
   drawState = true;
}});

window.addEventListener("mouseup",function(e){
if(e.button===1){
   drawState = false;
}});

You can improve the window listeners with some checks, if the mouse is over a cell.

After this you can add a mouseenter listener to all your cells. Mouseenter is only fired once you enter a cell and not on every move inside the element:

celle[i].addEventListener("mouseenter", function(e){
   if(drawState){
      e.target.style.backgroundColor="black";
   }
})
0
Anakin On

Instead of tracking mouseover, track three events:

  1. mousemove - to constantly get the mouse position
  2. mousedown - to set the mouse state as currently clicked down
  3. mouseup - to set the mouse state as currently released

It works this way:

  1. handleMousemove constantly updates the mouse position and check mouse state
  2. When the mouse is clicked down, handleMousedown is fired
  3. handleMousedown set the state as 'down'
  4. When handleMousemove sees that mouse state is 'down', it fires click event at the current mouse position
  5. When the mouse is released, handleMouseup is fired
  6. handleMouseup set the state as 'released' and everything returns to normal
  7. Repeat

    var mouseIsDown = false;
    var mousePosition = { x:-1, y:-1 };
    
    let handleMousemove = (event) => {
        // get the mouse position
      mousePosition.x = event.x;
      mousePosition.y = event.y;
      if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
      {
        let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
        // you can add some conditions before clicking
        if(something)
        {
          elem.click();
        }
      }
    };
    
    let handleMousedown = (event) => {
        mouseIsDown = true;
      // set the mouse state as 'down'
    };
    
    let handleMouseup = (event) => {
        mouseIsDown = false;
      // set the mouse state as 'release'
    };
    
    document.addEventListener('mousemove', handleMousemove);
    document.addEventListener('mousedown', handleMousedown);
    document.addEventListener('mouseup', handleMouseup);
    

Working fiddle: https://jsfiddle.net/Black3800/9wvh8bzg/5/

0
Giancarlo On

Thanks to everybody for your kind answers. Proposed codes work almost ok. The only problem is that sometimes browser shows the NO SYMBOL cursor. Unfortunately I can't post an image but you can find it here:

NO Symbol

and the only way to keep on drawing is clicking outside the table and then clicking again inside.

This is my code:

var mouseIsDown = false;
var mousePosition = { x:-1, y:-1 };

let handleMousemove = (event) => {
    // get the mouse position
  mousePosition.x = event.x;
  mousePosition.y = event.y;
  if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
  {
    let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
    // you can add some conditions before clicking
    if (event.buttons==1)
    {
      elem.click();
    }
  }
};

let handleMousedown = (event) => {
    mouseIsDown = true;
  // set the mouse state as 'down'
};

let handleMouseup = (event) => {
    mouseIsDown = false;
  // set the mouse state as 'release'
};

document.addEventListener('mousemove', handleMousemove);
document.addEventListener('mousedown', handleMousedown);
document.addEventListener('mouseup', handleMouseup);

celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("click", function(e){
        e.target.style.backgroundColor="black";
    }
)