View Javadoc

1   /*
2    * ObjectLab, http://www.objectlab.co.uk/open is supporting JTreeMap.
3    * 
4    * Based in London, we are world leaders in the design and development 
5    * of bespoke applications for the securities financing markets.
6    * 
7    * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8    *           ___  _     _           _   _          _
9    *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
10   *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
11   *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
12   *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13   *                   |__/
14   *
15   *                     www.ObjectLab.co.uk
16   *
17   * $Id: HSBTreeMapColorProvider.java 75 2006-10-24 23:00:51Z benoitx $
18   * 
19   * Copyright 2006 the original author or authors.
20   *
21   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22   * use this file except in compliance with the License. You may obtain a copy of
23   * the License at
24   *
25   * http://www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations under
31   * the License.
32   */
33  package net.sf.jtreemap.ktreemap.example;
34  
35  import org.eclipse.swt.SWT;
36  import org.eclipse.swt.events.PaintEvent;
37  import org.eclipse.swt.events.PaintListener;
38  import org.eclipse.swt.graphics.Color;
39  import org.eclipse.swt.graphics.GC;
40  import org.eclipse.swt.graphics.Point;
41  import org.eclipse.swt.widgets.Canvas;
42  import org.eclipse.swt.widgets.Composite;
43  import org.eclipse.swt.widgets.Display;
44  import net.sf.jtreemap.ktreemap.ITreeMapColorProvider;
45  import net.sf.jtreemap.ktreemap.ITreeMapProvider;
46  import net.sf.jtreemap.ktreemap.KTreeMap;
47  import net.sf.jtreemap.ktreemap.TreeMapNode;
48  
49  /**
50   * An HSB color space color provider for KTreeMap. Uses a specified function to
51   * map the values onto the HSB color space. The default is a linear function,
52   * but in my experience one of the logarithmic ones works best for this color
53   * space.
54   *
55   * @author Andy Adamczak
56   */
57  public class HSBTreeMapColorProvider implements ITreeMapColorProvider {
58    protected KTreeMap m_jTreeMap;
59    protected double m_maxValue = Double.MIN_VALUE;
60    protected double m_minValue = Double.MAX_VALUE;
61    private float m_positiveHue;
62    private float m_negativeHue;
63    private float m_positiveSaturation = 1f;
64    private float m_negativeSaturation = 1f;
65  
66    private ColorDistributionTypes m_colorDistribution = ColorDistributionTypes.Linear;
67  
68    /**
69     * @param treeMap
70     * @param color
71     */
72    public HSBTreeMapColorProvider(KTreeMap treeMap, Color color) {
73      this(treeMap, ColorDistributionTypes.Linear, color, color);
74    }
75  
76    /**
77     * @param treeMap
78     * @param positiveColor
79     * @param negativeColor
80     */
81    public HSBTreeMapColorProvider(KTreeMap treeMap, Color positiveColor,
82        Color negativeColor) {
83      this(treeMap, ColorDistributionTypes.Linear, positiveColor, negativeColor);
84    }
85  
86    /**
87     * @param treeMap
88     * @param colorDistribution
89     * @param color
90     */
91    public HSBTreeMapColorProvider(KTreeMap treeMap,
92        ColorDistributionTypes colorDistribution, Color color) {
93      this(treeMap, colorDistribution, color, color);
94    }
95  
96    /**
97     * @param treeMap
98     * @param colorDistribution
99     * @param positiveColor
100    * @param negativeColor
101    */
102   public HSBTreeMapColorProvider(KTreeMap treeMap,
103       ColorDistributionTypes colorDistribution, Color positiveColor,
104       Color negativeColor) {
105     super();
106     m_jTreeMap = treeMap;
107     m_colorDistribution = colorDistribution;
108     adjustColor(positiveColor, negativeColor);
109   }
110 
111   /**
112    * @param treeMap
113    * @param colorDistribution
114    * @param hue
115    * @param saturation
116    */
117   public HSBTreeMapColorProvider(KTreeMap treeMap,
118       ColorDistributionTypes colorDistribution, float hue, float saturation) {
119     this(treeMap, colorDistribution, hue, saturation, hue, saturation);
120   }
121 
122   /**
123    * @param treeMap
124    * @param colorDistribution
125    * @param positiveHue
126    * @param positiveSaturation
127    * @param negativeHue
128    * @param negativeSaturation
129    */
130   public HSBTreeMapColorProvider(KTreeMap treeMap,
131       ColorDistributionTypes colorDistribution, float positiveHue,
132       float positiveSaturation, float negativeHue, float negativeSaturation) {
133     super();
134     m_jTreeMap = treeMap;
135     m_colorDistribution = colorDistribution;
136     adjustColor(positiveHue, positiveSaturation, negativeHue,
137         negativeSaturation);
138   }
139 
140   /**
141    * @param treeMap
142    * @param hue
143    * @param saturation
144    */
145   public HSBTreeMapColorProvider(KTreeMap treeMap, float hue, float saturation) {
146     this(treeMap, ColorDistributionTypes.Linear, hue, saturation, hue,
147         saturation);
148   }
149 
150   /**
151    * @param treeMap
152    * @param positiveHue
153    * @param positiveSaturation
154    * @param negativeHue
155    * @param negativeSaturation
156    */
157   public HSBTreeMapColorProvider(KTreeMap treeMap, float positiveHue,
158       float positiveSaturation, float negativeHue, float negativeSaturation) {
159     this(treeMap, ColorDistributionTypes.Linear, positiveHue,
160         positiveSaturation, negativeHue, negativeSaturation);
161   }
162 
163   /**
164    * @param color
165    */
166   public void adjustColor(Color color) {
167     adjustColor(color, color);
168   }
169 
170   /**
171    * @param positiveColor
172    * @param negativeColor
173    */
174   public void adjustColor(Color positiveColor, Color negativeColor) {
175     // Figure out the hue of the passed in colors. Note, greys will map to reds
176     // in this color space, so use the
177     // hue/saturation
178     // constructions for grey scales.
179     float[] hsbvals = new float[3];
180 
181     hsbvals = java.awt.Color.RGBtoHSB(positiveColor.getRed(), positiveColor
182         .getGreen(), positiveColor.getBlue(), hsbvals);
183     m_positiveHue = hsbvals[0];
184     m_positiveSaturation = 1f;
185 
186     hsbvals = java.awt.Color.RGBtoHSB(negativeColor.getRed(), negativeColor
187         .getGreen(), negativeColor.getBlue(), hsbvals);
188     m_negativeHue = hsbvals[0];
189     m_negativeSaturation = 1f;
190   }
191 
192   /**
193    * @param hue
194    * @param saturation
195    */
196   public void adjustColor(float hue, float saturation) {
197     adjustColor(hue, saturation, hue, saturation);
198   }
199 
200   /**
201    * @param positiveHue
202    * @param positiveSaturation
203    * @param negativeHue
204    * @param negativeSaturation
205    */
206   public void adjustColor(float positiveHue, float positiveSaturation,
207       float negativeHue, float negativeSaturation) {
208     m_positiveHue = positiveHue;
209     m_positiveSaturation = positiveSaturation;
210     m_negativeHue = negativeHue;
211     m_negativeSaturation = negativeSaturation;
212   }
213 
214   public Color getBackground(Object value) {
215     // Figure out the current range of colors, map that range into a scale from
216     // 0 to 1,
217     // using the specified distribution type
218     if (m_maxValue == Double.MIN_VALUE || m_minValue == Double.MAX_VALUE) {
219       setValues(m_jTreeMap.getRoot());
220     }
221     ITreeMapProvider provider = m_jTreeMap.getTreeMapProvider();
222     double val = provider.getDoubleValue(value);
223 
224     return getBackground(val);
225   }
226 
227   public Color getForeground(Object value) {
228     return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
229   }
230 
231   public Composite getLegend(Composite parent, int style) {
232     return new Legend(parent, style);
233   }
234 
235   /**
236    * Set the max and the min values in the tree map
237    *
238    * @param root root of the JTreeMap
239    */
240   void setValues(TreeMapNode root) {
241     if (root.isLeaf()) {
242       Object value = root.getValue();
243       ITreeMapProvider provider = m_jTreeMap.getTreeMapProvider();
244       double rootValue = provider.getDoubleValue(value);
245       if (rootValue >= m_maxValue) {
246         m_maxValue = rootValue;
247       }
248 
249       if (rootValue <= m_minValue) {
250         m_minValue = rootValue;
251       }
252     } else {
253       for (TreeMapNode node : root.getChildren()) {
254         setValues(node);
255       }
256     }
257   }
258 
259   /**
260    * Given a value, maps that value to a new value using the specified math
261    * function
262    *
263    * @param value the value to convert
264    * @return the converted value
265    */
266   private double adjustValue(double value) {
267     switch (m_colorDistribution) {
268     case Log:
269       return Math.log1p(value);
270     case Exp:
271       return Math.exp(value);
272     case SquareRoot:
273       return Math.sqrt(value);
274     case CubicRoot:
275       return Math.cbrt(value);
276     default:
277       // Linear
278       return value;
279     }
280   }
281 
282   private Color getBackground(double val) {
283     double maxValue = m_maxValue;
284     double minValue = m_minValue;
285     if (val >= 0) {
286       // Value is greater than 0, use the positive colors
287       double range = maxValue - Math.max(0, minValue);
288       val -= Math.max(0, minValue);
289       range = adjustValue(range);
290       java.awt.Color cc = new java.awt.Color(java.awt.Color.HSBtoRGB(
291           m_positiveHue, m_positiveSaturation,
292           (float)(adjustValue(val) / range)));
293       return ResourceManager.getColor(cc.getRed(), cc.getGreen(), cc.getBlue());
294     }
295 
296     // Value is less than 0, use the negative colors
297     double range = Math.abs(minValue - Math.min(0, maxValue));
298     val += Math.min(0, maxValue);
299     val = Math.abs(val);
300     // Value and range are not positive values, we need them to be for the math
301     // functions
302     range = adjustValue(range);
303     java.awt.Color cc = new java.awt.Color(java.awt.Color.HSBtoRGB(
304         m_negativeHue, m_negativeSaturation, (float)(adjustValue(val) / range)));
305     return ResourceManager.getColor(cc.getRed(), cc.getGreen(), cc.getBlue());
306   }
307 
308   /**
309    * @author Andy Adamczak
310    */
311   public enum ColorDistributionTypes {
312     /**
313      *
314      */
315     Linear,
316     /**
317      *
318      */
319     Log,
320     /**
321      *
322      */
323     Exp,
324     /**
325      *
326      */
327     SquareRoot,
328     /**
329      *
330      */
331     CubicRoot
332   }
333 
334   private class Legend extends Canvas {
335 
336     /**
337      * Constructor
338      * @param parent parent Composite
339      * @param style style
340      */
341     public Legend(Composite parent, int style) {
342       super(parent, style);
343 
344       addPaintListener(new PaintListener() {
345         public void paintControl(PaintEvent e) {
346           Legend.this.paintControl(e);
347         }
348       });
349     }
350 
351     @Override
352     public Point computeSize(int wHint, int hHint, boolean changed) {
353       int height = 20;
354       if (hHint != SWT.DEFAULT)
355         height = hHint;
356       return new Point(wHint, height);
357     }
358 
359     protected void paintControl(PaintEvent e) {
360       GC gc = e.gc;
361       int width = this.getBounds().width;
362       double step = (m_maxValue - m_minValue) / width;
363       double value = m_minValue;
364       for (int i = 0; i < width; i++) {
365         gc.setBackground(HSBTreeMapColorProvider.this.getBackground(value));
366         gc.fillRectangle(i, 0, 1, this.getBounds().height);
367         value += step;
368       }
369     }
370   }
371 }
372 /*
373  *                 ObjectLab is supporing JTreeMap
374  * 
375  * Based in London, we are world leaders in the design and development 
376  * of bespoke applications for the securities financing markets.
377  * 
378  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
379  *           ___  _     _           _   _          _
380  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
381  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
382  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
383  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
384  *                   |__/
385  *
386  *                     www.ObjectLab.co.uk
387  */