0

In a web application that I am writing, I have a series of divs which create a grid. The grid is X divs by Y divs, based on user input. Using jQuery hover function, I would like to change the background color of all surrounding divs within a certain distance. Basically, if I hover over a div, all divs within 4 rows and 4 columns away should also change their background color. I can get this functioning fine, but when the grid becomes 32 by 128 divs there is a real performance issue and the hover effect noticeably lags behind the mouse. I am almost certain that it is because of the large amount of similar divs within the DOM because the issue is not there when the grid is something like 30 by 30.

This is the basic structure of my html:

<div class="table_area">
    <div class="table_row" id="row-0">
        <div class="cap" data-row="0" data-column="0"></div>
        <div class="cap" data-row="0" data-column="1"></div>
        ...
    </div>
    <div class="table_row" id="row-1">
        <div class="cap" data-row="1" data-column="0"></div>
        <div class="cap" data-row="1" data-column="1"></div>
        ...
    </div>
    ...
</div>

To try to speed up the search of the DOM, I have added each row to an array. Thus, $('div.table_row[data-row="0"]') would be in arr[0]. So when a div in row 8 is hovered, I only check arr[4] through arr[12] for the necessary divs.

I would think that this would speed up the process quite a bit, since I am eliminating a substantial amount of the searching, but there is still a very noticeable lag in the hover.

Is there anything blatantly wrong with how I set this up? I am using the latest version of Chrome, if that matters.

Jaak Kütt
  • 2,566
  • 4
  • 31
  • 39
cspada
  • 75
  • 1
  • 7
  • 1
    care to create a jsfiddle.net of what you have? – Brad Christie Jan 18 '13 at 18:24
  • can you setup a small demo? there may be other areas that you can optimize. – Kevin B Jan 18 '13 at 18:25
  • How about sharing some code? – Matt Burland Jan 18 '13 at 18:27
  • Without seeing your code, I suspect at least part of your problem is that you are probably firing a whole slew of `hover` events as you move across your table. You might look at this [question](http://stackoverflow.com/questions/435732/delay-jquery-hover-event) and see if you can delay the hover for a few milliseconds. – Matt Burland Jan 18 '13 at 18:29
  • Does [this work fast enough](http://jsfiddle.net/R3xqF/)? – Brad Christie Jan 18 '13 at 19:11
  • @BradChristie maybe I am being a little too critical, that is the effect that I am getting with my application. For your example, a 20 by 20 grid a very fluid, while large is a bit laggy. Maybe I am crazy! Do you know what I mean? I guess it just come with the territory of having a large amount of divs. Thanks for the input. I was trying to get everything to change exactly as the mouse moves, but I guess it is a bit too much for the hover function to process with so many div changes.. – cspada Jan 18 '13 at 19:24
  • @NerdEcho. I'd recommend using a canvas then if you're looking to be _that_ fluid. – Brad Christie Jan 18 '13 at 21:06

2 Answers2

1

Selecting by class name is native to the browser, whereas selecting by data within an element depends on looping within jQuery.

Use class names to label your rows and columns and your selector will be much faster.

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • Thanks I'll try it out! I always thought that class name was the slowest. Good to know! – cspada Jan 18 '13 at 18:27
  • this depends on browser, selecting by data attribute is done with queryselectorall. – Kevin B Jan 18 '13 at 18:28
  • 1
    I use arr[0].children('[data-column=1][data-row=3]'); I assumed that would be efficient enough to the point where using class OR data attribute wouldn't matter – cspada Jan 18 '13 at 18:33
  • The OP says they are already caching rows in an array, which is a good idea. I'd probably just cache all the cells in a 2D array for quicker lookup of both rows and columns. – Matt Burland Jan 18 '13 at 18:33
0

If you add a class to each of the caps, you can then dynamically build a massive selector:

  var sel = "";
$(".cap").hover(function () {
    var row  = $(this).data("row");
    var col = $(this).data("column");
    sel = "";
    for(var i=row-2; i<=row+2; i++)
    {
      for(var j=col-2; j<=col+2; j++)
      {
        sel += ".r" + i + ".c" + j + ",";
      }
    }
  sel = sel.slice(0,-1);
  $(sel).css("background-color","blue");
},function () {
    $(sel).css("background-color","white");
  });
});

Example: http://jsbin.com/izeyal/38/edit

Since I was dynamically creating the rows and columns, I also added ids to each of the rows, which you can use for testing if you want by changing the selector generation code:

  sel += "#r" + i + "c" + j + ",";

For completeness, the code I used to generate the grid:

  for(i=0; i<128; i++)
  {
    var newRow = $('<div/>', {
    id: 'row-' + i
}).appendTo('.table_area');
    for (j=0; j<32; j++)
    {
      var rowid= "r" +i + "c" + j;
      $('<div/>', {id: rowid }).data("row",i).data("column",j).addClass("cap r" + i + " c" + j).appendTo(newRow);  
    }
  }
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • Thank you! I believe that this is the most responsive I will get it with the way that I have the grouping of divs set up! I was unaware that the same selector could be used for the mouse exit as well. Makes sense! Thanks a lot! – cspada Jan 18 '13 at 21:58