Riaan Walters
Riaan Walters

Reputation: 2676

Color range - table values in angular

Lets assume we have the following setup (bellow), I want the table to have 5 cells, which it will, but i want the 5 cells to have a dynamic color range which goes from green to red (1 = green, 3 = yellow, 5 = red, ect)

The only technologies I am allowed to work with is : CSS3 / HTML5 / Angular - I am allowed to work with any angular lib

In excel its trivial doing this, but since im fairly new to angular, i'm admittedly a bit lost.

~ Script
var arrayWith5Values = [1,2,3,4,5]
~
    <table>
        <tr>
           <td ng-repeat='numericValue in arrayWith5Values'>
              {{numericValue}}}
           </td>
        </tr>
    </table>

It's basicly the angular version of this question : Coloring HTML table cells from "Low to High Color Shades" depending on Cell Value in Python HTML Email and this Color Cell Based on Value in Cell

I have been searching StackOverflow for the majority of last night and could not find an answer.

Here is an example (screenshot from excel) Example

Upvotes: 1

Views: 3355

Answers (3)

Artisan
Artisan

Reputation: 2124

If anyone else stumbled upon this and wasn't as satisfied as I was with the provided solution, I hacked together another solution.

I wanted to be able to use an array of values and color scale them from lowest red to highest green as well as use a midpoint color as yellow.

Take a look below as well as at the fiddle to see a working solution.

ctrl.getColor = function(value, min_value, max_value) {
    let [highMaxR, highMaxG, highMaxB] = [99, 190, 123];
    let [lowMaxR, lowMaxG, lowMaxB] = [248, 105, 107];
    let [midMaxR, midMaxG, midMaxB] = [255, 235, 132];

    if (Math.round(max_value - min_value) === 0) return `${highMaxR}, ${highMaxG}, ${highMaxB}`;

    let mid_point = (max_value + min_value) / 2;
    if (value > mid_point) {
      [lowMaxR, lowMaxG, lowMaxB] = [midMaxR, midMaxG, midMaxB];
      min_value = mid_point;
    } else {
      [highMaxR, highMaxG, highMaxB] = [midMaxR, midMaxG, midMaxB];
      max_value = mid_point;
    }

    let percentage = Math.abs((value - min_value) / (max_value - min_value));

    let redVal = Math.round(lowMaxR + ((highMaxR - lowMaxR) * percentage));
    let greenVal = Math.round(lowMaxG + ((highMaxG - lowMaxG) * percentage));
    let blueVal = Math.round(lowMaxB + ((highMaxB - lowMaxB) * percentage));

    return `${redVal}, ${greenVal}, ${blueVal}`;
};

Here is the fiddle

Upvotes: 0

brettvd
brettvd

Reputation: 486

Along the same lines of Kirill Slatin's answer, but this one is a lot simpler:

HTML:

<table>
    <tr>
       <td ng-repeat='numericValue in arrayWith5Values' style="background-color: rgb({{getColor($index)}})"
        ng-init="$parent.numValues = arrayWith5Values.length">
          {{numericValue}}
       </td>
    </tr>
 </table>

Controller JS:

$scope.arrayWith5Values = [1,2,3,4,5,6,7,8,9,10];
$scope.getColor = function(index) {
    var greenVal = Math.round(Math.min((255.0*2.0)*(index/($scope.numValues-1)), 255));
    var redVal = Math.round(Math.min((255.0*2.0)*(($scope.numValues-1-index)/($scope.numValues-1))));
    return "" + greenVal + "," + redVal + ",0";
}

Seemed to be working pretty well with the little testing I did. JSFiddle here

Note: this is tailored specifically for green to red. This same math could be applied to other color schemes, but it would have to be somewhat manually done again

Upvotes: 5

Kirill Slatin
Kirill Slatin

Reputation: 6143

Pure Angular and javascript. Javascript code quality is not good, but it is here just for you to get the idea. I was really writing fast...

IDEA: use custom function (getColor()) to define the background color or your elements. Mind that curly braces {{}} in Angular add $watch expressions. So I suggest using once-binding via {{::}} if you have fresh enough Angular (v1.3+). Otherwise use the angular library BindOnce

HTML:

   <tr ng-repeat="arr in data">
        <td ng-repeat="value in arr" ng-attr-style="background: #{{::getColor(value, arr)}};">
            {{value}}
        </td>
    </tr>

Javascript:

$scope.getColor = function(item, array){
    var h = item / array.length ;
    return RGBtoHex(HSVtoRGB(h, 1, 1))
};
function RGBtoHex(color){
    var r = color.r.toString(16);
    if(r.length < 2) r = '0' + r;
    var g = color.g.toString(16);
    if(g.length < 2) g = '0' + g;
    var b = color.b.toString(16);
    if(b.length < 2) b = '0' + b;
    return r + g + b;
}

function HSVtoRGB(h, s, v) {
    var r, g, b, i, f, p, q, t;
    if (h && s === undefined && v === undefined) {
        s = h.s, v = h.v, h = h.h;
    }
    i = Math.floor(h * 6);
    f = h * 6 - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);
    switch (i % 6) {
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }
    return {
        r: Math.floor(r * 255),
        g: Math.floor(g * 255),
        b: Math.floor(b * 255)
    };

PS: getColor() is function you need to redefine according to you color palette. Mind that Hue in HSV color model changes from 0 to 1 ranging the whole spectrum. You should select which range of the spectrum you would like to achieve from first till last element and accordingly limit in function. Although handle marginal cases (like 1 or 2 elements) based on your specification.

Working example in this jsfiddle

Credits for HSVToRGB() goes for Paul S. https://stackoverflow.com/a/17243070/4573999

Upvotes: 3

Related Questions