package org.iplantc.phyloviewer.shared.render.style; public class ContinuousColorPalette implements IColorPalette { private double min; private int[] minColor = new int[4]; //simplify getColor calculation by storing ranges instead of maxima private double valueRange; private int[] colorRange = new int[4]; public ContinuousColorPalette(double minValue, double maxValue, int[] minColor, int[] maxColor) { //TODO validate inputs (min strictly < max, color arrays are right length and value ranges, etc.) this.min = minValue; this.valueRange = maxValue - minValue; this.minColor = minColor; for (int i = 0; i < 4; i++) { this.colorRange[i] = maxColor[i] - minColor[i]; } } @Override public String getColor(Object value) { if (value instanceof Number) { return getColor(((Number) value).doubleValue()); } else { throw new IllegalArgumentException("ContinuousColorPalette only accepts numerical values"); } } public String getColor(double d) { //TODO Explore other color options. Not sure if interpolating a straight line through rgba space is best visually, but it's the obvious thing to try first. if (d <= min) { return rgbaString(minColor); } else if (d > min + valueRange) { return getColor(min + valueRange); } else { int[] color = new int[4]; for (int i = 0; i < 4; i++) { color[i] = minColor[0] + (int)Math.round(((d - min)/valueRange) * colorRange[i]); } return rgbaString(color); } } private String rgbaString(int[] color) { double a = color[3]/255.0; return "rgba(" + color[0] + ", " + color[1] + ", " + color[2] + ", " + a + ")"; } }