001package com.hfg.graphics; 002 003import com.hfg.html.attribute.HTMLColor; 004import com.hfg.util.CompareUtil; 005import com.hfg.util.collection.CollectionUtil; 006import com.hfg.xml.XMLName; 007import com.hfg.xml.XMLTag; 008 009import java.awt.Color; 010import java.util.ArrayList; 011import java.util.List; 012 013//------------------------------------------------------------------------------ 014/** 015 <div> 016 Color scale created from two or more colors. 017 </div> 018 <div> 019 Ex: 020 <pre> 021 ColorScale colorScale = new ColorScale(new Color[] {Color.WHITE, Color.BLACK, Color.BLUE, Color.GREEN}); 022 023 Center center = body.addCenter(); 024 center.addSpan("Color Scale Created from White, Black, Blue, & Green"); 025 Table table = center.addTable(); 026 Tr row = table.addRow(); 027 028 for (int i = 0; i <= 20; i++) 029 { 030 float value = i * 0.05f; 031 HTMLColor scaleColor = new HTMLColor(colorScale.getColor(value)); 032 row.addCell(String.format("%.2f", value)).setStyle(CSS.color(scaleColor.getContrastingColor()) + CSS.bgColor(scaleColor)); 033 } 034 </pre> 035 </div> 036 <div style='margin-top:20px'> 037 <span>Color Scale Created from White, Black, Blue, & Green</span> 038 <table summary='Example Color Scale'> 039 <tr> 040 <td style='color:#000000;background-color:#ffffff;'>0.00</td> 041 <td style='color:#000000;background-color:#d9d9d9;'>0.05</td> 042 <td style='color:#000000;background-color:#b3b3b3;'>0.10</td> 043 <td style='color:#000000;background-color:#8c8c8c;'>0.15</td> 044 <td style='color:#ffffff;background-color:#666666;'>0.20</td> 045 <td style='color:#ffffff;background-color:#404040;'>0.25</td> 046 <td style='color:#ffffff;background-color:#191919;'>0.30</td> 047 <td style='color:#ffffff;background-color:#00000d;'>0.35</td> 048 <td style='color:#ffffff;background-color:#000033;'>0.40</td> 049 <td style='color:#ffffff;background-color:#000059;'>0.45</td> 050 <td style='color:#ffffff;background-color:#000080;'>0.50</td> 051 <td style='color:#ffffff;background-color:#0000a6;'>0.55</td> 052 <td style='color:#ffffff;background-color:#0000cc;'>0.60</td> 053 <td style='color:#ffffff;background-color:#0000f2;'>0.65</td> 054 <td style='color:#ffffff;background-color:#0019e6;'>0.70</td> 055 <td style='color:#ffffff;background-color:#0040bf;'>0.75</td> 056 <td style='color:#ffffff;background-color:#006699;'>0.80</td> 057 <td style='color:#ffffff;background-color:#008c73;'>0.85</td> 058 <td style='color:#ffffff;background-color:#00b34c;'>0.90</td> 059 <td style='color:#000000;background-color:#00d926;'>0.95</td> 060 <td style='color:#000000;background-color:#00ff00;'>1.00</td> 061 </tr> 062 </table> 063 </div> 064 <div style='margin-top:20px'> 065 <span>Color Scale Created from Red, Yellow, & Green</span> 066 <table summary='Example Color Scale'> 067 <tr> 068 <td style='color:#ffffff;background-color:#ff0000;'>0.00</td> 069 <td style='color:#ffffff;background-color:#ff1a00;'>0.05</td> 070 <td style='color:#ffffff;background-color:#ff3300;'>0.10</td> 071 <td style='color:#ffffff;background-color:#ff4d00;'>0.15</td> 072 <td style='color:#000000;background-color:#ff6600;'>0.20</td> 073 <td style='color:#000000;background-color:#ff8000;'>0.25</td> 074 <td style='color:#000000;background-color:#ff9900;'>0.30</td> 075 <td style='color:#000000;background-color:#ffb300;'>0.35</td> 076 <td style='color:#000000;background-color:#ffcc00;'>0.40</td> 077 <td style='color:#000000;background-color:#ffe600;'>0.45</td> 078 <td style='color:#000000;background-color:#ffff00;'>0.50</td> 079 <td style='color:#000000;background-color:#e6ff00;'>0.55</td> 080 <td style='color:#000000;background-color:#ccff00;'>0.60</td> 081 <td style='color:#000000;background-color:#b2ff00;'>0.65</td> 082 <td style='color:#000000;background-color:#99ff00;'>0.70</td> 083 <td style='color:#000000;background-color:#80ff00;'>0.75</td> 084 <td style='color:#000000;background-color:#66ff00;'>0.80</td> 085 <td style='color:#000000;background-color:#4cff00;'>0.85</td> 086 <td style='color:#000000;background-color:#33ff00;'>0.90</td> 087 <td style='color:#000000;background-color:#1aff00;'>0.95</td> 088 <td style='color:#000000;background-color:#00ff00;'>1.00</td> 089 </tr> 090 </table> 091 </div> 092 <div style='margin-top:20px'> 093 <span>Color Scale Created from White, Black, Blue, Red, Yellow, & Green</span> 094 <table summary='Example Color Scale'> 095 <tr> 096 <td style='color:#000000;background-color:#ffffff;'>0.00</td> 097 <td style='color:#000000;background-color:#bfbfbf;'>0.05</td> 098 <td style='color:#000000;background-color:#808080;'>0.10</td> 099 <td style='color:#ffffff;background-color:#404040;'>0.15</td> 100 <td style='color:#ffffff;background-color:#000000;'>0.20</td> 101 <td style='color:#ffffff;background-color:#000040;'>0.25</td> 102 <td style='color:#ffffff;background-color:#000080;'>0.30</td> 103 <td style='color:#ffffff;background-color:#0000bf;'>0.35</td> 104 <td style='color:#ffffff;background-color:#0000ff;'>0.40</td> 105 <td style='color:#ffffff;background-color:#4000bf;'>0.45</td> 106 <td style='color:#ffffff;background-color:#800080;'>0.50</td> 107 <td style='color:#ffffff;background-color:#bf0040;'>0.55</td> 108 <td style='color:#ffffff;background-color:#ff0000;'>0.60</td> 109 <td style='color:#ffffff;background-color:#ff4000;'>0.65</td> 110 <td style='color:#000000;background-color:#ff7f00;'>0.70</td> 111 <td style='color:#000000;background-color:#ffbf00;'>0.75</td> 112 <td style='color:#000000;background-color:#ffff00;'>0.80</td> 113 <td style='color:#000000;background-color:#bfff00;'>0.85</td> 114 <td style='color:#000000;background-color:#7fff00;'>0.90</td> 115 <td style='color:#000000;background-color:#40ff00;'>0.95</td> 116 <td style='color:#000000;background-color:#00ff00;'>1.00</td> 117 </tr> 118 </table> 119 </div> 120 121 * @author J. Alex Taylor, hairyfatguy.com 122 */ 123//------------------------------------------------------------------------------ 124// com.hfg Library 125// 126// This library is free software; you can redistribute it and/or 127// modify it under the terms of the GNU Lesser General Public 128// License as published by the Free Software Foundation; either 129// version 2.1 of the License, or (at your option) any later version. 130// 131// This library is distributed in the hope that it will be useful, 132// but WITHOUT ANY WARRANTY; without even the implied warranty of 133// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 134// Lesser General Public License for more details. 135// 136// You should have received a copy of the GNU Lesser General Public 137// License along with this library; if not, write to the Free Software 138// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 139// 140// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 141// jataylor@hairyfatguy.com 142//------------------------------------------------------------------------------ 143 144public class ColorScale implements ColorRule, Comparable 145{ 146 private List<HTMLColor> mColors; 147 148 public static final XMLName XML_COLOR_SCALE = new XMLName("ColorScale"); 149 private static final XMLName XML_COLOR = new XMLName("Color"); 150 151 //########################################################################## 152 // CONSTRUCTORS 153 //########################################################################## 154 155 //-------------------------------------------------------------------------- 156 public ColorScale(List<Color> inColors) 157 { 158 if (null == inColors 159 || inColors.size() < 2) 160 { 161 throw new RuntimeException("At least 2 colors must be specified!"); 162 } 163 164 mColors = new ArrayList<>(inColors.size()); 165 for (Color color : inColors) 166 { 167 mColors.add(new HTMLColor(color)); 168 } 169 } 170 171 //-------------------------------------------------------------------------- 172 public ColorScale(Color... inColors) 173 { 174 if (null == inColors 175 || inColors.length < 2) 176 { 177 throw new RuntimeException("At least 2 colors must be specified!"); 178 } 179 180 mColors = new ArrayList<>(inColors.length); 181 for (Color color : inColors) 182 { 183 mColors.add(new HTMLColor(color)); 184 } 185 } 186 187 //--------------------------------------------------------------------------- 188 public ColorScale(XMLTag inXMLTag) 189 { 190 inXMLTag.verifyTagName(XML_COLOR_SCALE); 191 192 List<XMLTag> subTags = inXMLTag.getSubtagsByName(XML_COLOR); 193 if (CollectionUtil.hasValues(subTags)) 194 { 195 mColors = new ArrayList<>(subTags.size()); 196 197 for (XMLTag subTag : subTags) 198 { 199 mColors.add(HTMLColor.valueOf(subTag.getUnescapedContent())); 200 } 201 } 202 } 203 204 //########################################################################## 205 // PUBLIC METHODS 206 //########################################################################## 207 208 //-------------------------------------------------------------------------- 209 public List<HTMLColor> getColors() 210 { 211 return mColors; 212 } 213 214 //-------------------------------------------------------------------------- 215 /** 216 * Determines the color that should be assigned to the specified value that 217 * has been normalized to the range of 0 to 1. 218 * @param inValue 0 <= float value >= 1.0 219 * @return the assigned color 220 */ 221 public Color assignColorForValue(float inValue) 222 { 223 if (inValue < 0 || inValue > 1.0) 224 { 225 throw new RuntimeException("The value to map to the color scale must be between 0 and 1!"); 226 } 227 228 // Determine which two colors the value falls between. 229 230 float regionSize = 1.0f / (mColors.size() - 1); 231 232 int lowIndex = (int) Math.floor(inValue / regionSize); 233 if (lowIndex == mColors.size() - 1) lowIndex--; 234 235 return ColorUtil.blend(mColors.get(lowIndex), mColors.get(lowIndex + 1), 1 - ((inValue - (lowIndex * regionSize)) / regionSize)); 236 } 237 238 239 //--------------------------------------------------------------------------- 240 public XMLTag toXMLTag() 241 { 242 XMLTag tag = new XMLTag(XML_COLOR_SCALE); 243 244 for(Color color : mColors) 245 { 246 tag.addSubtag(new XMLTag(XML_COLOR).setContent(new HTMLColor(color).toString())); 247 } 248 249 return tag; 250 } 251 252 253 //-------------------------------------------------------------------------- 254 @Override 255 public int compareTo(Object inObj2) 256 { 257 int result = -1; 258 259 if (inObj2 != null 260 && inObj2 instanceof ColorScale) 261 { 262 ColorScale colorScale2 = (ColorScale) inObj2; 263 264 result = CompareUtil.compare(mColors, colorScale2.mColors); 265 } 266 267 return result; 268 } 269}