1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package net.sf.jtreemap.swing.provider;
34
35 import java.awt.Color;
36 import java.awt.Graphics;
37 import java.util.Enumeration;
38
39 import javax.swing.JPanel;
40
41 import lombok.extern.slf4j.Slf4j;
42 import net.sf.jtreemap.swing.DefaultValue;
43 import net.sf.jtreemap.swing.JTreeMap;
44 import net.sf.jtreemap.swing.TreeMapNode;
45 import net.sf.jtreemap.swing.Value;
46
47
48
49
50
51
52
53
54
55 @Slf4j
56 public class HSBTreeMapColorProvider extends ColorProvider {
57 private static final int HSBVAL_SIZE = 3;
58
59
60
61
62 private static final long serialVersionUID = 5009655580804320847L;
63
64
65
66
67 public enum ColorDistributionTypes {
68 LINEAR,
69 LOG,
70 EXP,
71 SQUARE_ROOT,
72 CUBIC_ROOT
73 }
74
75
76
77
78
79 public HSBTreeMapColorProvider(final JTreeMap treeMap, final Color color) {
80 this(treeMap, ColorDistributionTypes.LINEAR, color, color);
81 }
82
83
84
85
86
87
88 public HSBTreeMapColorProvider(final JTreeMap treeMap, final ColorDistributionTypes colorDistribution, final Color color) {
89 this(treeMap, colorDistribution, color, color);
90 }
91
92
93
94
95
96
97 public HSBTreeMapColorProvider(final JTreeMap treeMap, final Color positiveColor, final Color negativeColor) {
98 this(treeMap, ColorDistributionTypes.LINEAR, positiveColor, negativeColor);
99 }
100
101
102
103
104
105
106
107 public HSBTreeMapColorProvider(final JTreeMap treeMap, final ColorDistributionTypes colorDistribution, final Color positiveColor,
108 final Color negativeColor) {
109 super();
110 jTreeMap = treeMap;
111 this.colorDistribution = colorDistribution;
112 adjustColor(positiveColor, negativeColor);
113 }
114
115
116
117
118
119
120 public HSBTreeMapColorProvider(final JTreeMap treeMap, final float hue, final float saturation) {
121 this(treeMap, ColorDistributionTypes.LINEAR, hue, saturation, hue, saturation);
122 }
123
124
125
126
127
128
129
130 public HSBTreeMapColorProvider(final JTreeMap treeMap, final ColorDistributionTypes colorDistribution, final float hue, final float saturation) {
131 this(treeMap, colorDistribution, hue, saturation, hue, saturation);
132 }
133
134
135
136
137
138
139
140
141 public HSBTreeMapColorProvider(final JTreeMap treeMap, final float positiveHue, final float positiveSaturation, final float negativeHue,
142 final float negativeSaturation) {
143 this(treeMap, ColorDistributionTypes.LINEAR, positiveHue, positiveSaturation, negativeHue, negativeSaturation);
144 }
145
146
147
148
149
150
151
152
153
154 public HSBTreeMapColorProvider(final JTreeMap treeMap, final ColorDistributionTypes colorDistribution, final float positiveHue,
155 final float positiveSaturation, final float negativeHue, final float negativeSaturation) {
156 super();
157 jTreeMap = treeMap;
158 this.colorDistribution = colorDistribution;
159 adjustColor(positiveHue, positiveSaturation, negativeHue, negativeSaturation);
160 }
161
162
163
164
165
166
167 @Override
168 public JPanel getLegendPanel() {
169 if (legend == null) {
170 legend = new Legend();
171 }
172
173 return legend;
174 }
175
176
177
178
179 public void adjustColor(final Color color) {
180 adjustColor(color, color);
181 }
182
183
184
185
186
187 public void adjustColor(final Color positiveColor, final Color negativeColor) {
188
189
190
191
192 float[] hsbvals = new float[HSBVAL_SIZE];
193
194 hsbvals = Color.RGBtoHSB(positiveColor.getRed(), positiveColor.getGreen(), positiveColor.getBlue(), hsbvals);
195 positiveHue = hsbvals[0];
196 positiveSaturation = 1f;
197
198 hsbvals = Color.RGBtoHSB(negativeColor.getRed(), negativeColor.getGreen(), negativeColor.getBlue(), hsbvals);
199 negativeHue = hsbvals[0];
200 negativeSaturation = 1f;
201 }
202
203
204
205
206
207 public void adjustColor(final float hue, final float saturation) {
208 adjustColor(hue, saturation, hue, saturation);
209 }
210
211
212
213
214
215
216
217 public void adjustColor(final float posHue, final float posSaturation, final float negHue, final float negSaturation) {
218 this.positiveHue = posHue;
219 this.positiveSaturation = posSaturation;
220 this.negativeHue = negHue;
221 this.negativeSaturation = negSaturation;
222 }
223
224
225
226
227
228
229 @Override
230 public Color getColor(final Value value) {
231
232
233
234 if (maxValue == null || minValue == null) {
235 setValues(jTreeMap.getRoot());
236 }
237 final double max = this.maxValue.getValue();
238 final double min = this.minValue.getValue();
239 double val = value != null ? value.getValue() : 0.00;
240
241 if (val >= 0) {
242
243 double range = max - Math.max(0, min);
244 val -= Math.max(0, min);
245 range = adjustValue(range);
246 return Color.getHSBColor(positiveHue, positiveSaturation, (float) (adjustValue(val) / range));
247 }
248
249
250 double range = Math.abs(min - Math.min(0, max));
251 val += Math.min(0, max);
252 val = Math.abs(val);
253
254
255 range = adjustValue(range);
256 return Color.getHSBColor(negativeHue, negativeSaturation, (float) (adjustValue(val) / range));
257 }
258
259
260
261
262
263
264
265
266
267 private double adjustValue(final double value) {
268 double ret;
269 switch (colorDistribution) {
270 case LOG:
271 ret = Math.log1p(value);
272 break;
273 case EXP:
274 ret = Math.exp(value);
275 break;
276 case SQUARE_ROOT:
277 ret = Math.sqrt(value);
278 break;
279 case CUBIC_ROOT:
280 ret = Math.cbrt(value);
281 break;
282 default:
283
284 ret = value;
285 break;
286 }
287 return ret;
288 }
289
290
291
292
293
294
295
296 private void setValues(final TreeMapNode root) {
297 if (root.isLeaf()) {
298 final Value value = root.getValue();
299
300 if (value == null) {
301 return;
302 }
303
304 setMaxValue(value);
305 setMinValue(value);
306 } else {
307 for (final Enumeration e = root.children(); e.hasMoreElements();) {
308 final TreeMapNode node = (TreeMapNode) e.nextElement();
309 setValues(node);
310 }
311 }
312 }
313
314 private void setMinValue(final Value value) {
315 if (minValue == null || value.getValue() <= minValue.getValue()) {
316 try {
317 final Class c = value.getClass();
318 if (minValue == null) {
319 minValue = (Value) c.newInstance();
320 }
321 minValue.setValue(value.getValue());
322 } catch (final IllegalAccessException iae) {
323
324 } catch (final InstantiationException ie) {
325
326 log.error("Instantiation Issue", ie);
327 }
328 }
329 }
330
331 private void setMaxValue(final Value value) {
332 if (maxValue == null || value.getValue() >= maxValue.getValue()) {
333 try {
334 final Class c = value.getClass();
335 if (maxValue == null) {
336 maxValue = (Value) c.newInstance();
337 }
338 maxValue.setValue(value.getValue());
339 } catch (final IllegalAccessException iae) {
340
341 } catch (final InstantiationException ie) {
342
343 log.error("Instantiation Issue", ie);
344 }
345 }
346 }
347
348 private final JTreeMap jTreeMap;
349 private JPanel legend;
350 private Value maxValue;
351 private Value minValue;
352 private float positiveHue;
353 private float negativeHue;
354 private float positiveSaturation = 1f;
355 private float negativeSaturation = 1f;
356 private ColorDistributionTypes colorDistribution = ColorDistributionTypes.LINEAR;
357
358
359
360
361
362
363 private class Legend extends JPanel {
364 private static final int Y_INSET = 7;
365 private static final int X_INSET = 15;
366 private static final long serialVersionUID = 6371342387871103592L;
367 private static final int HEIGHT = 20;
368 private static final int WIDTH = 150;
369 private static final int X = 20;
370 private static final int Y = 25;
371
372
373
374
375 public Legend() {
376 this.setSize(new java.awt.Dimension(2 * Legend.X + Legend.WIDTH, 2 * Legend.Y + Legend.HEIGHT));
377 this.setPreferredSize(new java.awt.Dimension(2 * Legend.X + Legend.WIDTH, 2 * Legend.Y + Legend.HEIGHT));
378 }
379
380 @Override
381 public void paintComponent(final Graphics g) {
382 super.paintComponent(g);
383 if (HSBTreeMapColorProvider.this.minValue == null || HSBTreeMapColorProvider.this.maxValue == null) {
384 setValues(HSBTreeMapColorProvider.this.jTreeMap.getRoot());
385 }
386 final Value min = HSBTreeMapColorProvider.this.minValue;
387 final Value max = HSBTreeMapColorProvider.this.maxValue;
388
389 g.setColor(Color.black);
390 if (min != null && max != null) {
391 g.drawString(min.getLabel(), Legend.X - X_INSET, Legend.Y - Y_INSET);
392 g.drawString(max.getLabel(), Legend.X + Legend.WIDTH - X_INSET, Legend.Y - Y_INSET);
393
394 final double step = (max.getValue() - min.getValue()) / Legend.WIDTH;
395 final Value value = new DefaultValue(min.getValue());
396 for (int i = 0; i < Legend.WIDTH; i++) {
397 g.setColor(HSBTreeMapColorProvider.this.getColor(value));
398 g.fillRect(Legend.X + i, Legend.Y, 1, Legend.HEIGHT);
399 value.setValue(value.getValue() + step);
400 }
401 }
402 }
403 }
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420