5

I am trying to create an effect over a grid with many small elements, I want the cursor to leave a trail over the grid when mouse moves over it.

Working example in codepen: https://codepen.io/SrPunta/pen/bGNORmW

loadGrid([]);

function loadGrid(imageElements) {
  let emptySquare = {
    width: 8,
    height: 8,
    imageUrl: '',
    isEmpty: true
  };
  const gridElements = [];

  // this for only to fill 10000 empty squares
  for (let row = 0; row < 100; row++) {
    for (let column = 0; column < 100; column++) {
      emptySquare.offsetLeft = column * 10;
      emptySquare.offsetTop = row * 10;

      gridElements.push(_.clone(emptySquare));

    }
  }
  const gridContainer = $('.grid-container');
  console.log('container2', gridContainer);
  const resultGrid = gridElements.concat(imageElements);
  resultGrid.forEach(element => addEmptySquare(element));
}


function addEmptySquare(element, container) {
  const square = document.createElement('div');
  square.style.width = element.width + 'px';
  square.style.height = element.height + 'px';
  square.style.left = element.offsetLeft + 'px';
  square.style.top = element.offsetTop + 'px';
  square.className = 'empty-square';
  document.getElementById('grid-container').appendChild(square);
}
.empty-square {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRF9/X1s+1L5AAAAAtJREFUeJxjYEAFAAAQAAE5vY9lAAAAAElFTkSuQmCC');
  border: 1px solid #CCCCCC;
  position: absolute;
  transition: background-image 1s ease;
  -moz-transition: background-image 1s ease;
  -webkit-transition: background-image 1s ease;
}

.empty-square:hover {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRFgpD+bo+nNQAAAAtJREFUeJxjYEAFAAAQAAE5vY9lAAAAAElFTkSuQmCC');
  transition: background-image 0s ease;
  -moz-transition: background-image 0s ease;
  -webkit-transition: background-image 0s ease;
}
<html>

<head>
  <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

</head>

<body>
  <div id="grid-container"> </div>
</body>

</html>

But as you can see when mouse moves fast some element are skipped and the hover animation is not triggered.

How I can achieve this or have a continuous trail without skip elements?

NOTE: I use base64 image as background because it is much faster with many elements.

Juan Marco
  • 3,081
  • 2
  • 28
  • 32
Sergio
  • 51
  • 1
  • 5
    This isn't something you really have control over. It has to do with the mouse dpi. Cursors don't actually move over top of every pixel on the screen. Depending on your DPI and sensitivity, it is skipping quite a lot of pixels when moving across the screen quickly. The only way you could make it smooth, would be to use a canvas and calculate the cursor path. But at that point it wouldn't be the same code whatsoever. With css hovers, it's not possible. – garetmckinley Jan 21 '20 at 20:04
  • Make sense but I try with other single elements and as fast I passed the mouse it always trigger the hover animation, for example the "Products" button at the top of this page at left on the search input, this button always fires the event. – Sergio Jan 21 '20 at 20:16
  • Is there any proof behind your claim on using background images to be faster? Any specific browser/version? Changing the transition to change background-color, while not firing on every single element (re: @garetmckinley's comment), seems much faster – chazsolo Jan 21 '20 at 20:16
  • I don't have any proof on using backgound images but I feel that is faster but at the end have the same result, skip elements on hover. – Sergio Jan 21 '20 at 20:24
  • @garetmckinley I don't think that the problem is related with dpi, I test it with gaming mouse with different dpi settings and same effect, I also test with bigger squares and small grid and same result. – Sergio Jan 21 '20 at 20:26
  • 1
    @Sergio I dont know exactly how it works, but I think its safe to assume that :hover is an event on the browser and therefor has a listener looking for it. So its only going to update so often; You'll still have to use a different approach as garetmckinley said. – BenDubs Jan 21 '20 at 22:11
  • You could *try* [`will-change`](https://developer.mozilla.org/en-US/docs/web/css/will-change) but you should read that article on MDN; using it can lead to other issues. – Heretic Monkey Jan 21 '20 at 22:34
  • You could change the styles using `element.style` in javaScript. That might speed things up. There's going to be more than one way to solve this problem. here's a relevant question https://stackoverflow.com/questions/608788/css-hover-vs-javascript-mouseover – admcfajn Jan 21 '20 at 22:37
  • The gist of what @garetmckinley is saying is true: the mouse position is only going to be updated fast enough to ensure 60fps (i.e. every ~16ms). Updating more frequently would hinder performance unnecessarily. – coreyward Jan 21 '20 at 22:55

0 Answers0