最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Selecting a table cell by row and column while compensating for rowspan and colspan - Stack Overflow

programmeradmin0浏览0评论

I'd like to be able to select a table cell by row and column indices, while pensating for rowspan and colspan. For example, in the following table,

I would expect coloring (1,2) red, (2,3) green, and (3,3) blue, to yield:

I tried the answer to the question, "Selecting an arbitrary cell in a table by row and column number", but this yielded:

Here is the jsFiddle: /

I understand what is happening, and I even found another question, "Table cellIndex and rowIndex with colspan/rowspan", where an answer was supplied as a plugin, but it just seems unbelievable that there isn't a simpler way! After all, the coloring of the actual result seems understandable, yet unintuitive, while the coloring of the expected result seems far more intuitive and easily graspable.

Can anyone think of a clever and simpler way to implement this?


Update

Here's a new jsFiddle with my (poor) attempt, in case it might inspire a new idea in someone else. Basically, if we assumed the row and col headers weren't spanned (which, of course, isn't a valid assumption), then we could use offsets to "target" the correct cell:

function getCell(table, r, c)
{
    var rowHead = $(table.rows[r].cells[0]);
    var colHead = $(table.rows[0].cells[c]);
    var y = rowHead.offset().top + rowHead.outerHeight(true)/2;
    var x = colHead.offset().left + colHead.outerWidth(true)/2;
    return $(document.elementFromPoint(x, y));
}

While the demo appears to work, there are a number of problems:

  1. Can't assume row and col headers aren't spanned.
  2. Doesn't work if midpoint of row or col is off the viewport; elementFromPoint seems to depend on the viewport.
  3. Doesn't work reliably when scrolling, margins, etc. e into play; flimsy in general; would rather not rely on coordinate-math.

I'd like to be able to select a table cell by row and column indices, while pensating for rowspan and colspan. For example, in the following table,

I would expect coloring (1,2) red, (2,3) green, and (3,3) blue, to yield:

I tried the answer to the question, "Selecting an arbitrary cell in a table by row and column number", but this yielded:

Here is the jsFiddle: http://jsfiddle/acheong87/27HuN/

I understand what is happening, and I even found another question, "Table cellIndex and rowIndex with colspan/rowspan", where an answer was supplied as a plugin, but it just seems unbelievable that there isn't a simpler way! After all, the coloring of the actual result seems understandable, yet unintuitive, while the coloring of the expected result seems far more intuitive and easily graspable.

Can anyone think of a clever and simpler way to implement this?


Update

Here's a new jsFiddle with my (poor) attempt, in case it might inspire a new idea in someone else. Basically, if we assumed the row and col headers weren't spanned (which, of course, isn't a valid assumption), then we could use offsets to "target" the correct cell:

function getCell(table, r, c)
{
    var rowHead = $(table.rows[r].cells[0]);
    var colHead = $(table.rows[0].cells[c]);
    var y = rowHead.offset().top + rowHead.outerHeight(true)/2;
    var x = colHead.offset().left + colHead.outerWidth(true)/2;
    return $(document.elementFromPoint(x, y));
}

While the demo appears to work, there are a number of problems:

  1. Can't assume row and col headers aren't spanned.
  2. Doesn't work if midpoint of row or col is off the viewport; elementFromPoint seems to depend on the viewport.
  3. Doesn't work reliably when scrolling, margins, etc. e into play; flimsy in general; would rather not rely on coordinate-math.
Share Improve this question edited Aug 30, 2018 at 16:03 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Dec 27, 2012 at 18:51 Andrew CheongAndrew Cheong 30.3k17 gold badges100 silver badges167 bronze badges 2
  • 1 And what of more plex models? You are asking for something generic to solve every situation not just this one you say, so here is a worst case scenario example of the table: jsfiddle/27HuN/25 . – Travis J Commented Dec 27, 2012 at 21:53
  • @TravisJ - You deserve half the accepted-answer rep just for creating the plex scenario to test against. Thanks. (Karma is ing your way ;-) – Andrew Cheong Commented May 4, 2013 at 5:10
Add a ment  | 

3 Answers 3

Reset to default 4

Here's a different approach which does 'pre-processing':

var grid = (function(){

  var table = $("#table")[0], a=[], cell, i, j, k, l, y;

  for (i=0;i<table.rows.length;i++) a[i] = [];

  for (i=0;i<table.rows.length;i++) {
      y = 0;
      for (j=0;j<table.rows[i].cells.length;j++) {
          while (a[i][j + y]) y++;
          cell = $(table.rows[i].cells[j]);
          xspan = parseInt(cell.attr('rowspan') || 1);
          yspan = parseInt(cell.attr('colspan') || 1);
          for (k=0;k<xspan;k++) {
              for (l=0;l<yspan;l++) {
                  if(i + k < table.rows.length) a[i + k][j + y + l] = [i,j];
              }
          }
      }
  }

  return a;

})();

colorCell(1,2,'red');
colorCell(2,3,'green');
colorCell(3,3,'blue');

function colorCell(i,j,s){
    var a = grid[i][j];
    $(table.rows[a[0]].cells[a[1]]).css('background-color', s);
}

jsfiddle

Your design is custom, and so your solution must also be custom. There is no simple generic way to approach this because of how departed the table is from the expected structure. Remove the mented out td elements and you will see the true shape of what the script is dealing with.

As in all good optimization, you should do some work up front. Use class names or data-attributes to mark which cell is which when you prepare them, and the work afterwards will dramatically decrease. Doing no work up front will cost you later in the end, as you can see from costly calculations and workarounds such as the suggested plugin.

See this jsfiddle for an example of what I mean: http://jsfiddle/27HuN/2/

In case something happens to it, here is a copy

html

<table id="table" border="1" cellpadding="10" style="text-align:center;">
<tbody>
    <tr class="0">
        <td class="0-0">(0,0)</td>
        <td class="0-1">(0,1)</td>
        <td class="0-2">(0,2)</td>
        <td class="0-3">(0,3)</td>
    </tr>
    <tr class="1">
        <td class="1-0">(1,0)</td>
        <td colspan="2" class="1-1 1-2">(1,1) (1,2)</td>
        <!--<td></td>-->
        <td rowspan="2" class="1-3 2-3">(1,3)<br/>(2,3)</td>
    </tr>
    <tr class="2">
        <td class="2-0">(2,0)</td>
        <td class="2-1">(2,1)</td>
        <td class="2-2">(2,2)</td>
        <!--<td></td>-->
    </tr>
    <tr class="3">
        <td class="3-0">(3,0)</td>
        <td class="3-1">(3,1)</td>
        <td class="3-2">(3,2)</td>
        <td class="3-3">(3,3)</td>
    </tr>
</tbody>
</table>​

js

$('.1-2').css('background-color', 'red');
$('.2-3').css('background-color', 'green');
$('.3-3').css('background-color', 'blue');

Note that this is a simple example, and you would probably want to use class names which were not just numbers. Perhaps r0c0, r2c3 type of markup, or something more verbose to logically represent these positions.

I have tried it in JSFiddle... Took some time though...

var table = $("#table")[0];

SetColumnColor(1, 2, 'red');
SetColumnColor(2, 3, 'green');
SetColumnColor(3, 3, 'blue');

function SetColumnColor(rowIndex, cellIndex, color){

    var actualRowIndex = GetActualRowIndex(table, rowIndex, cellIndex);
    var actualCellIndex = GetActualCellIndex(table.rows[actualRowIndex], cellIndex);
    $(table.rows[actualRowIndex].cells[actualCellIndex]).css('background-color', color);
}

function GetActualCellIndex(row, cellIndex) {
    var actualCellIndex = cellIndex;
    $(row.cells).each(function(index) {
        var colSpan = parseInt($(this).attr('colspan'));
        if(colSpan != NaN && colSpan > 0)
        {
            //alert(colSpan);
            actualCellIndex = actualCellIndex - colSpan + 1;
        }
    });

    return actualCellIndex;
}

function GetActualRowIndex(table, rowIndex, cellIndex) {
    var actualRowIndex = rowIndex;

    if(table.rows[rowIndex].cells[cellIndex] != null)
        return rowIndex;

    $(table.rows).each(function(index) {
        if(rowIndex <= index)
            return actualRowIndex;
        var realCellIndex = GetActualCellIndex(this, cellIndex);
        //alert("Row:" + index + "(" + realCellIndex + "," + cellIndex+ ")");
        var rowSpan = parseInt($(table.rows[index].cells[realCellIndex]).attr('rowspan'));
        if(rowSpan != NaN && rowSpan > 0)
        {
            //alert(rowSpan + "(" + index + "," + realCellIndex + ")");
            actualRowIndex = actualRowIndex - rowSpan + 1;
        }
    });

    return actualRowIndex;
}

A working demo is available here

发布评论

评论列表(0)

  1. 暂无评论