views:

560

answers:

4

In an application I write that uses a large HTML table of numbers the design requires that the row and column of the hovered cell will be highlighted.

I develop all the JS for this project using jQuery 1.3.x, and I found the tableHover plugin that does exactly what I need.

But:

on IE6 the performance of this plugin drops down as the number of cell elements rise to a point where the page is almost unresponsive.

I thought that the problems lies in the plugin and I actually rewrote it's entire functionality from scratch, just to discover that I have the same performance issues.

After debugging the code I now know that selecting a large amount of elements plus applying className (jQuery.addClass()) is extremely slow on IE6.

I tried to use jQuery.css() instead with only background-color, the performance is better, but again, when the number of table cells rise the performance drops to an unusable state, and on all other browsers the performance of jQuery.css() is way slower than jQuery.addClass().

The main problem here is that there is no common parent to a table column, so in order to style a column one needs to traverse the entire table, select each row and then find the right nth-child td. my jQuery code for this one looks like that:

//col_num is the current td element
//table is the parent table    
var col_num = cur_cell.prevAll().length + 1;
var this_col = $('tr td:nth-child(' + col_num + ')', table);

I won't paste my entire code here because it's irrelevant for the issue. The only answer I'm looking for is: Is there a known method to do what I need in a better performance margin? I'm not looking for "Chrome" performance speed, just something faster than "non responsive".

Thnaks

Tom.

+1  A: 

I wonder whether in searching for better responsiveness from jQuery, you're not seeing the forest for the trees?

Why don't you include a <colgroup> element at the top of your table (either explicitly or, if necessary, by adding it dynamically with jQuery) and then assign a background color value to the column matching your selected cell's index?

IE6 does support the <colgroup> element, but only in limited properties. However, background-color is one of those supported so this should see a significant improvement in your performance.

Phil.Wheeler
WTF? Was that answer really that unhelpful or wrong? Why was it downvoted? Someone's showing bad SO etiquette.
Phil.Wheeler
Beats me. You might not need `colgroup` (`col` on its own should do), but, yeah, seems to me like it should work, for the limited range of styles that work with columns.
bobince
+1  A: 

I should have noted this - I'm a much better CSS/HTML developer than a Javascript one, I tried every non-script method I know before digging into JS.

I actually started from colgroup, I even use it for column widths on the same table, but the colgroup and col elements are set visually behind the table elements, so if tbody, tr, td or any other element in the table has a background (which in my case, many of them has), colgroup will not show over these elements, and it did not respond to positioning or any other advanced CSS manipulation I tried to apply on it.

Tombigel
+2  A: 

I have dealt with performance complex jquery on very large tables in IE6. Here is what i can offer you in terms of help:

  • encode as much data in the html as possible. for example, encode the row number and col numbers in the TDs class or name attribute
  • add a mouse listener to the entire table, and then use event.target to get the TDs
  • parse out the location of the cell you are hovering form point #1
  • again, you will probably have to add a ton of classes, but have a class for each column and each row, that way you can select both entire row and entire column with 2 class selectors, and add css to them
  • cache as much as possible. if the user moves from one cell to another, check if its in a row you have already highlighted. i think this is pretty much guaranteed to happen, so you will have 1/2 the selector operations
  • cache entire columns you have selected, so you dont have to select twice, same for rows
  • check out this responsiveness plugin i wrote, you may want to use it.
  • also, there is another post i wrote on the topic of writing fast jquery plugins.
mkoryak
Thanks.I tried to avoid encoding data in the HTML (adds complexity from the server side..), a parent eventHandler and caching...It's just a visual effert. but I guess you are right, for the sake of compatibility I need to uglify my code.
Tombigel
IE6 is the greatest uglifying agent in web dev
mkoryak
+1  A: 

Reduce the number of className changes and subsequent reflows by letting the browser's CSS matching engine do the work for you. For example, for a 3x3 table:

<style type="text/css">
    .sel-row-0 .row-0 td, .sel-row-1 .row-1 td, .sel-row-2 .row-2 td,
    .sel-col-0 .col-0, .sel-col-1 .col-1, .sel-col-1 .col-1 {
        background: red;
    }
</style>

<table id="foo">
    <tr class="row-0">
        <td class="col-0">a</td>
        <td class="col-1">b</td>
        <td class="col-2">c</td>
    </tr>
    <tr class="row-1">
        <td class="col-0">d</td>
        <td class="col-1">e</td>
        <td class="col-2">f</td>
    </tr>
    <tr class="row-2">
        <td class="col-0">g</td>
        <td class="col-1">h</td>
        <td class="col-2">i</td>
    </tr>
</table>

Now all you need to do is set className on the outer table to "sel-row-(num) sel-col-(num)" and all the cells will update at once, which will be much quicker than looping and setting classes.

For a very large number of cols/rows the amount of data in the stylesheet can become unwieldy. You can get around this a bit by dynamically changing the rules in the stylesheet through the document.styleSheets list, but this takes some cross-browser work that jQuery won't help you with. Or for a table with, say, many rows but few columns, you can put the selected-row class directly on the row, and only do the column highlighting this way, which is still only 2-3 class changes.

(It would be nice if we could use the CSS3 nth-child selector as you did in the jQuery selector, but browser support isn't there yet.)

bobince