user1069609 user1069609 - 18 days ago 7
CSS Question

How to color table cell groups of equal elements

For an HTML table with numbers, I am looking for an elegant JavaScript/CSS way to identify groups of equal values in each column, and color the background of corresponding cells accordingly. I will use it in a web presentation of regression test results.

In python I would probably have used something like itertools.groupby().

To illustrate, I include a screenshot example and the corresponding HTML code (constructed manually).




<head>
<style>
td {font-family: Monospace; font-size:16; }
</style>
</head>

<body>
<table border=1>
<tr><td>1.111</td></tr>
<tr><td>1.111</td></tr>
<tr><td bgcolor="LightBlue">2.222</td></tr>
<tr><td>1.111</td></tr>
<tr><td bgcolor="LightBlue">2.222</td></tr>
<tr><td> 1.111</td></tr>
<tr><td bgcolor="LightBlue">2.222</td></tr>
<tr><td bgcolor="Goldenrod">3.333</td></tr>
<tr><td> 1.111</td></tr>
</table>
</body>




enter image description here

Answer

Here's a pure JavaScript solution (with jsFiddle) that works on your posted sample source:

function colorTableCells() {
    'use strict';
    var i = 0; //counter variable
    var j = 0; //counter variable
    var k = 0; //counter variable
    var m = 0; //counter variable
    var n = 0; //counter variable
    var tables = document.getElementsByTagName('table'); //All tables as a collection.
    var rows = []; //table rows collection, needed to determine columns
    var cells = []; //td collection
    var cell = {}; //used first as a Cell object (custom, see below) and then as a td (after all unique values by column have been determined
    var values = []; //array of Cell objects (custom, see below).
    var columnColorMap = {
        'column0': 'gray',
        'column1': 'purple',
        'column2': 'pink',
        'column3': 'mint',
        'column4': 'cyan'
    }; //columnColorMap holds the shade with which to color the column.
    var C = function () {
        //Cell Object, holds properties unique to the cells for coloring
        this.value = 0; //Cell value
        this.color = {
            'red': 255,
            'green': 255,
            'blue': 255
        }; //Cell color, determined by column
        this.shades = {
            'gray': [this.color.red, this.color.green, this.color.blue],
            'purple': [this.color.red, this.color.green],
            'pink': [null, this.color.green, this.color.blue],
            'mint': [this.color.red, , this.color.blue],
            'cyan': [this.color.red],
            'magenta': [null, this.color.green],
            'yellow': [null, null, this.color.blue]
        }; //A quick way to determine the shade for the column. It holds color values to modify (and always in RGB order) or a null value if R, G, or B should be left alone.
        this.column = 0; //Column the cell is in, relative to the table it is in.
        this.darken = function (stepValue, hue) {
            //function that returns a new color, based on the hue that is passed in
            var decrement = 8;
            var i = 0;
            var ret = {
                'red': 255,
                'green': 255,
                'blue': 255
            };
            if (!stepValue) {
                stepValue = 0;
            }
            decrement = decrement * stepValue;
            for (i = 0; i < hue.length; i += 1) {
                if (hue[i]) {
                    hue[i] = hue[i] - decrement;
                }
            }
            if (hue[0]) {
                ret.red = hue[0];
            }
            if (hue[1]) {
                ret.green = hue[1];
            }
            if (hue[2]) {
                ret.blue = hue[2];
            }
            return ret;
        };
        this.getHexBackgroundColorString = function () {
            //returns `rbg(val, val, val) as '#RRGGBB'
            var s = '';
            var red = this.color.red.toString(16);
            var green = this.color.green.toString(16);
            var blue = this.color.blue.toString(16);
            if (red.length < 2) {
                red = '0' + red;
            }
            if (green.length < 2) {
                green = '0' + green;
            }
            if (green.length < 2) {
                blue = '0' + blue;
            }
            s = '#' + red + green + blue;
            return s.toUpperCase();
        };
    };
    var colHasValue = function (array, cell) {
        //loop through array, returns 'if cell.value && cell.column are found or otherwise'
        var i = 0;
        var found = false;
        for (i = 0; i < array.length; i += 1) {
            if (array[i].value === cell.value && array[i].column === cell.column) {
                found = true;
                i = array.length;
            }
        }
        return found;
    };
    for (i = 0; i < tables.length; i += 1) {
        cells = tables[i].getElementsByTagName('td'); //get all td elements per table
        for (j = 0; j < cells.length; j += 1) {
            cell = new C(); //grab a new Cell object
            cell.value = parseFloat(cells[j].innerText); //capture cell value
            cell.column = cells[j].cellIndex; //capture cell column
            if (!colHasValue(values, cell)) {
                //hasn't been previously stored yet, so darken according to column and store
                cell.color = cell.darken(j, cell.shades[columnColorMap['column' + cell.column.toString()]]);
                values.push(cell); //capture all unique values
            }
        }
        rows = tables[i].getElementsByTagName('tr'); //grab all rows by table
        for (k = 0; k < rows.length; k += 1) {
            //start looping through all the rows
            for (m = 0; m < rows[k].childNodes.length; m += 1) {
                //start looping through all of the row's children
                if (rows[k].childNodes[m].nodeName.toLowerCase() === 'td') {
                    cell = rows[k].childNodes[m]; //found a td element, alias to cell for easier use
                    for (n = 0; n < values.length; n += 1) {
                        //loop through stored cell values
                        if (parseFloat(cell.innerText) === values[n].value && cell.cellIndex === values[n].column) {
                            //value and column matches
                            cell.style.backgroundColor = values[n].getHexBackgroundColorString(); //set background-color
                            n = values.length; //exit for
                        }
                    }
                }
            }
        }
    }
}
colorTableCells();

Modify any (or all) of the following to change the colors:

  • The shades collection
  • The columnColorMap object
  • The darken function