1:
54:
55: package ;
56:
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66:
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82:
83:
95: public class WaterfallBarRenderer extends BarRenderer {
96:
97:
98: private static final long serialVersionUID = -2482910643727230911L;
99:
100:
101: private transient Paint firstBarPaint;
102:
103:
104: private transient Paint lastBarPaint;
105:
106:
107: private transient Paint positiveBarPaint;
108:
109:
110: private transient Paint negativeBarPaint;
111:
112:
115: public WaterfallBarRenderer() {
116: this(new GradientPaint(0.0f, 0.0f, new Color(0x22, 0x22, 0xFF),
117: 0.0f, 0.0f, new Color(0x66, 0x66, 0xFF)),
118: new GradientPaint(0.0f, 0.0f, new Color(0x22, 0xFF, 0x22),
119: 0.0f, 0.0f, new Color(0x66, 0xFF, 0x66)),
120: new GradientPaint(0.0f, 0.0f, new Color(0xFF, 0x22, 0x22),
121: 0.0f, 0.0f, new Color(0xFF, 0x66, 0x66)),
122: new GradientPaint(0.0f, 0.0f, new Color(0xFF, 0xFF, 0x22),
123: 0.0f, 0.0f, new Color(0xFF, 0xFF, 0x66)));
124: }
125:
126:
138: public WaterfallBarRenderer(Paint firstBarPaint,
139: Paint positiveBarPaint,
140: Paint negativeBarPaint,
141: Paint lastBarPaint) {
142: super();
143: if (firstBarPaint == null) {
144: throw new IllegalArgumentException("Null 'firstBarPaint' argument");
145: }
146: if (positiveBarPaint == null) {
147: throw new IllegalArgumentException(
148: "Null 'positiveBarPaint' argument");
149: }
150: if (negativeBarPaint == null) {
151: throw new IllegalArgumentException(
152: "Null 'negativeBarPaint' argument");
153: }
154: if (lastBarPaint == null) {
155: throw new IllegalArgumentException("Null 'lastBarPaint' argument");
156: }
157: this.firstBarPaint = firstBarPaint;
158: this.lastBarPaint = lastBarPaint;
159: this.positiveBarPaint = positiveBarPaint;
160: this.negativeBarPaint = negativeBarPaint;
161: setGradientPaintTransformer(new StandardGradientPaintTransformer(
162: GradientPaintTransformType.CENTER_VERTICAL));
163: setMinimumBarLength(1.0);
164: }
165:
166:
171: public Paint getFirstBarPaint() {
172: return this.firstBarPaint;
173: }
174:
175:
181: public void setFirstBarPaint(Paint paint) {
182: if (paint == null) {
183: throw new IllegalArgumentException("Null 'paint' argument");
184: }
185: this.firstBarPaint = paint;
186: fireChangeEvent();
187: }
188:
189:
194: public Paint getLastBarPaint() {
195: return this.lastBarPaint;
196: }
197:
198:
204: public void setLastBarPaint(Paint paint) {
205: if (paint == null) {
206: throw new IllegalArgumentException("Null 'paint' argument");
207: }
208: this.lastBarPaint = paint;
209: fireChangeEvent();
210: }
211:
212:
217: public Paint getPositiveBarPaint() {
218: return this.positiveBarPaint;
219: }
220:
221:
226: public void setPositiveBarPaint(Paint paint) {
227: if (paint == null) {
228: throw new IllegalArgumentException("Null 'paint' argument");
229: }
230: this.positiveBarPaint = paint;
231: fireChangeEvent();
232: }
233:
234:
239: public Paint getNegativeBarPaint() {
240: return this.negativeBarPaint;
241: }
242:
243:
249: public void setNegativeBarPaint(Paint paint) {
250: if (paint == null) {
251: throw new IllegalArgumentException("Null 'paint' argument");
252: }
253: this.negativeBarPaint = paint;
254: fireChangeEvent();
255: }
256:
257:
265: public Range findRangeBounds(CategoryDataset dataset) {
266:
267: if (dataset == null) {
268: throw new IllegalArgumentException("Null 'dataset' argument.");
269: }
270:
271: boolean allItemsNull = true;
272:
273: double minimum = 0.0;
274: double maximum = 0.0;
275: int columnCount = dataset.getColumnCount();
276: for (int row = 0; row < dataset.getRowCount(); row++) {
277: double runningTotal = 0.0;
278: for (int column = 0; column <= columnCount - 1; column++) {
279: Number n = dataset.getValue(row, column);
280: if (n != null) {
281: allItemsNull = false;
282: double value = n.doubleValue();
283: if (column == columnCount - 1) {
284:
285: runningTotal = value;
286: }
287: else {
288: runningTotal = runningTotal + value;
289: }
290: minimum = Math.min(minimum, runningTotal);
291: maximum = Math.max(maximum, runningTotal);
292: }
293: }
294:
295: }
296: if (!allItemsNull) {
297: return new Range(minimum, maximum);
298: }
299: else {
300: return null;
301: }
302:
303: }
304:
305:
319: public void drawItem(Graphics2D g2,
320: CategoryItemRendererState state,
321: Rectangle2D dataArea,
322: CategoryPlot plot,
323: CategoryAxis domainAxis,
324: ValueAxis rangeAxis,
325: CategoryDataset dataset,
326: int row,
327: int column,
328: int pass) {
329:
330: double previous = state.getSeriesRunningTotal();
331: if (column == dataset.getColumnCount() - 1) {
332: previous = 0.0;
333: }
334: double current = 0.0;
335: Number n = dataset.getValue(row, column);
336: if (n != null) {
337: current = previous + n.doubleValue();
338: }
339: state.setSeriesRunningTotal(current);
340:
341: int seriesCount = getRowCount();
342: int categoryCount = getColumnCount();
343: PlotOrientation orientation = plot.getOrientation();
344:
345: double rectX = 0.0;
346: double rectY = 0.0;
347:
348: RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
349: RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
350:
351:
352: double j2dy0 = rangeAxis.valueToJava2D(previous, dataArea,
353: rangeAxisLocation);
354:
355:
356: double j2dy1 = rangeAxis.valueToJava2D(current, dataArea,
357: rangeAxisLocation);
358:
359: double valDiff = current - previous;
360: if (j2dy1 < j2dy0) {
361: double temp = j2dy1;
362: j2dy1 = j2dy0;
363: j2dy0 = temp;
364: }
365:
366:
367: double rectWidth = state.getBarWidth();
368:
369:
370: double rectHeight = Math.max(getMinimumBarLength(),
371: Math.abs(j2dy1 - j2dy0));
372:
373: if (orientation == PlotOrientation.HORIZONTAL) {
374:
375: rectY = domainAxis.getCategoryStart(column, getColumnCount(),
376: dataArea, domainAxisLocation);
377: if (seriesCount > 1) {
378: double seriesGap = dataArea.getHeight() * getItemMargin()
379: / (categoryCount * (seriesCount - 1));
380: rectY = rectY + row * (state.getBarWidth() + seriesGap);
381: }
382: else {
383: rectY = rectY + row * state.getBarWidth();
384: }
385:
386: rectX = j2dy0;
387: rectHeight = state.getBarWidth();
388: rectWidth = Math.max(getMinimumBarLength(),
389: Math.abs(j2dy1 - j2dy0));
390:
391: }
392: else if (orientation == PlotOrientation.VERTICAL) {
393:
394: rectX = domainAxis.getCategoryStart(column, getColumnCount(),
395: dataArea, domainAxisLocation);
396:
397: if (seriesCount > 1) {
398: double seriesGap = dataArea.getWidth() * getItemMargin()
399: / (categoryCount * (seriesCount - 1));
400: rectX = rectX + row * (state.getBarWidth() + seriesGap);
401: }
402: else {
403: rectX = rectX + row * state.getBarWidth();
404: }
405:
406: rectY = j2dy0;
407: }
408: Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
409: rectHeight);
410: Paint seriesPaint = getFirstBarPaint();
411: if (column == 0) {
412: seriesPaint = getFirstBarPaint();
413: }
414: else if (column == categoryCount - 1) {
415: seriesPaint = getLastBarPaint();
416: }
417: else {
418: if (valDiff < 0.0) {
419: seriesPaint = getNegativeBarPaint();
420: }
421: else if (valDiff > 0.0) {
422: seriesPaint = getPositiveBarPaint();
423: }
424: else {
425: seriesPaint = getLastBarPaint();
426: }
427: }
428: if (getGradientPaintTransformer() != null
429: && seriesPaint instanceof GradientPaint) {
430: GradientPaint gp = (GradientPaint) seriesPaint;
431: seriesPaint = getGradientPaintTransformer().transform(gp, bar);
432: }
433: g2.setPaint(seriesPaint);
434: g2.fill(bar);
435:
436:
437: if (isDrawBarOutline()
438: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
439: Stroke stroke = getItemOutlineStroke(row, column);
440: Paint paint = getItemOutlinePaint(row, column);
441: if (stroke != null && paint != null) {
442: g2.setStroke(stroke);
443: g2.setPaint(paint);
444: g2.draw(bar);
445: }
446: }
447:
448: CategoryItemLabelGenerator generator
449: = getItemLabelGenerator(row, column);
450: if (generator != null && isItemLabelVisible(row, column)) {
451: drawItemLabel(g2, dataset, row, column, plot, generator, bar,
452: (valDiff < 0.0));
453: }
454:
455:
456: EntityCollection entities = state.getEntityCollection();
457: if (entities != null) {
458: addItemEntity(entities, dataset, row, column, bar);
459: }
460:
461: }
462:
463:
470: public boolean equals(Object obj) {
471:
472: if (obj == this) {
473: return true;
474: }
475: if (!super.equals(obj)) {
476: return false;
477: }
478: if (!(obj instanceof WaterfallBarRenderer)) {
479: return false;
480: }
481: WaterfallBarRenderer that = (WaterfallBarRenderer) obj;
482: if (!PaintUtilities.equal(this.firstBarPaint, that.firstBarPaint)) {
483: return false;
484: }
485: if (!PaintUtilities.equal(this.lastBarPaint, that.lastBarPaint)) {
486: return false;
487: }
488: if (!PaintUtilities.equal(this.positiveBarPaint,
489: that.positiveBarPaint)) {
490: return false;
491: }
492: if (!PaintUtilities.equal(this.negativeBarPaint,
493: that.negativeBarPaint)) {
494: return false;
495: }
496: return true;
497:
498: }
499:
500:
507: private void writeObject(ObjectOutputStream stream) throws IOException {
508: stream.defaultWriteObject();
509: SerialUtilities.writePaint(this.firstBarPaint, stream);
510: SerialUtilities.writePaint(this.lastBarPaint, stream);
511: SerialUtilities.writePaint(this.positiveBarPaint, stream);
512: SerialUtilities.writePaint(this.negativeBarPaint, stream);
513: }
514:
515:
523: private void readObject(ObjectInputStream stream)
524: throws IOException, ClassNotFoundException {
525: stream.defaultReadObject();
526: this.firstBarPaint = SerialUtilities.readPaint(stream);
527: this.lastBarPaint = SerialUtilities.readPaint(stream);
528: this.positiveBarPaint = SerialUtilities.readPaint(stream);
529: this.negativeBarPaint = SerialUtilities.readPaint(stream);
530: }
531:
532: }