1:
62:
63: package ;
64:
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71:
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83:
84:
88: public class StackedAreaRenderer extends AreaRenderer
89: implements Cloneable, PublicCloneable, Serializable {
90:
91:
92: private static final long serialVersionUID = -3595635038460823663L;
93:
94:
95: private boolean renderAsPercentages;
96:
97:
100: public StackedAreaRenderer() {
101: this(false);
102: }
103:
104:
110: public StackedAreaRenderer(boolean renderAsPercentages) {
111: super();
112: this.renderAsPercentages = renderAsPercentages;
113: }
114:
115:
124: public boolean getRenderAsPercentages() {
125: return this.renderAsPercentages;
126: }
127:
128:
137: public void setRenderAsPercentages(boolean asPercentages) {
138: this.renderAsPercentages = asPercentages;
139: fireChangeEvent();
140: }
141:
142:
149: public int getPassCount() {
150: return 2;
151: }
152:
153:
161: public Range findRangeBounds(CategoryDataset dataset) {
162: if (this.renderAsPercentages) {
163: return new Range(0.0, 1.0);
164: }
165: else {
166: return DatasetUtilities.findStackedRangeBounds(dataset);
167: }
168: }
169:
170:
184: public void drawItem(Graphics2D g2,
185: CategoryItemRendererState state,
186: Rectangle2D dataArea,
187: CategoryPlot plot,
188: CategoryAxis domainAxis,
189: ValueAxis rangeAxis,
190: CategoryDataset dataset,
191: int row,
192: int column,
193: int pass) {
194:
195:
196: Shape entityArea = null;
197: EntityCollection entities = state.getEntityCollection();
198:
199: double y1 = 0.0;
200: Number n = dataset.getValue(row, column);
201: if (n != null) {
202: y1 = n.doubleValue();
203: }
204: double[] stack1 = getStackValues(dataset, row, column);
205:
206:
207:
208:
209:
210: double xx1 = domainAxis.getCategoryMiddle(column, getColumnCount(),
211: dataArea, plot.getDomainAxisEdge());
212:
213:
214:
215:
216: double y0 = 0.0;
217: n = dataset.getValue(row, Math.max(column - 1, 0));
218: if (n != null) {
219: y0 = n.doubleValue();
220: }
221: double[] stack0 = getStackValues(dataset, row, Math.max(column - 1, 0));
222:
223:
224: double xx0 = domainAxis.getCategoryStart(column, getColumnCount(),
225: dataArea, plot.getDomainAxisEdge());
226:
227: int itemCount = dataset.getColumnCount();
228: double y2 = 0.0;
229: n = dataset.getValue(row, Math.min(column + 1, itemCount - 1));
230: if (n != null) {
231: y2 = n.doubleValue();
232: }
233: double[] stack2 = getStackValues(dataset, row, Math.min(column + 1,
234: itemCount - 1));
235:
236: double xx2 = domainAxis.getCategoryEnd(column, getColumnCount(),
237: dataArea, plot.getDomainAxisEdge());
238:
239:
240: double xxLeft = xx0;
241: double xxRight = xx2;
242:
243: double[] stackLeft = averageStackValues(stack0, stack1);
244: double[] stackRight = averageStackValues(stack1, stack2);
245: double[] adjStackLeft = adjustedStackValues(stack0, stack1);
246: double[] adjStackRight = adjustedStackValues(stack1, stack2);
247:
248: float transY1;
249:
250: RectangleEdge edge1 = plot.getRangeAxisEdge();
251:
252: GeneralPath left = new GeneralPath();
253: GeneralPath right = new GeneralPath();
254: if (y1 >= 0.0) {
255: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[1], dataArea,
256: edge1);
257: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[1],
258: dataArea, edge1);
259: float transStackLeft = (float) rangeAxis.valueToJava2D(
260: adjStackLeft[1], dataArea, edge1);
261:
262:
263: if (y0 >= 0.0) {
264: double yleft = (y0 + y1) / 2.0 + stackLeft[1];
265: float transYLeft
266: = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
267: left.moveTo((float) xx1, transY1);
268: left.lineTo((float) xx1, transStack1);
269: left.lineTo((float) xxLeft, transStackLeft);
270: left.lineTo((float) xxLeft, transYLeft);
271: left.closePath();
272: }
273: else {
274: left.moveTo((float) xx1, transStack1);
275: left.lineTo((float) xx1, transY1);
276: left.lineTo((float) xxLeft, transStackLeft);
277: left.closePath();
278: }
279:
280: float transStackRight = (float) rangeAxis.valueToJava2D(
281: adjStackRight[1], dataArea, edge1);
282:
283: if (y2 >= 0.0) {
284: double yright = (y1 + y2) / 2.0 + stackRight[1];
285: float transYRight
286: = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
287: right.moveTo((float) xx1, transStack1);
288: right.lineTo((float) xx1, transY1);
289: right.lineTo((float) xxRight, transYRight);
290: right.lineTo((float) xxRight, transStackRight);
291: right.closePath();
292: }
293: else {
294: right.moveTo((float) xx1, transStack1);
295: right.lineTo((float) xx1, transY1);
296: right.lineTo((float) xxRight, transStackRight);
297: right.closePath();
298: }
299: }
300: else {
301: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[0], dataArea,
302: edge1);
303: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[0],
304: dataArea, edge1);
305: float transStackLeft = (float) rangeAxis.valueToJava2D(
306: adjStackLeft[0], dataArea, edge1);
307:
308:
309: if (y0 >= 0.0) {
310: left.moveTo((float) xx1, transStack1);
311: left.lineTo((float) xx1, transY1);
312: left.lineTo((float) xxLeft, transStackLeft);
313: left.clone();
314: }
315: else {
316: double yleft = (y0 + y1) / 2.0 + stackLeft[0];
317: float transYLeft = (float) rangeAxis.valueToJava2D(yleft,
318: dataArea, edge1);
319: left.moveTo((float) xx1, transY1);
320: left.lineTo((float) xx1, transStack1);
321: left.lineTo((float) xxLeft, transStackLeft);
322: left.lineTo((float) xxLeft, transYLeft);
323: left.closePath();
324: }
325: float transStackRight = (float) rangeAxis.valueToJava2D(
326: adjStackRight[0], dataArea, edge1);
327:
328:
329: if (y2 >= 0.0) {
330: right.moveTo((float) xx1, transStack1);
331: right.lineTo((float) xx1, transY1);
332: right.lineTo((float) xxRight, transStackRight);
333: right.closePath();
334: }
335: else {
336: double yright = (y1 + y2) / 2.0 + stackRight[0];
337: float transYRight = (float) rangeAxis.valueToJava2D(yright,
338: dataArea, edge1);
339: right.moveTo((float) xx1, transStack1);
340: right.lineTo((float) xx1, transY1);
341: right.lineTo((float) xxRight, transYRight);
342: right.lineTo((float) xxRight, transStackRight);
343: right.closePath();
344: }
345: }
346:
347: g2.setPaint(getItemPaint(row, column));
348: g2.setStroke(getItemStroke(row, column));
349:
350:
351: Paint itemPaint = getItemPaint(row, column);
352: if (pass == 0) {
353: g2.setPaint(itemPaint);
354: g2.fill(left);
355: g2.fill(right);
356: }
357:
358:
359: if (entities != null) {
360: GeneralPath gp = new GeneralPath(left);
361: gp.append(right, false);
362: entityArea = gp;
363: addItemEntity(entities, dataset, row, column, entityArea);
364: }
365:
366: }
367:
368:
381: protected double getPreviousHeight(CategoryDataset dataset,
382: int series, int category) {
383:
384: double result = 0.0;
385: Number n;
386: double total = 0.0;
387: if (this.renderAsPercentages) {
388: total = DataUtilities.calculateColumnTotal(dataset, category);
389: }
390: for (int i = 0; i < series; i++) {
391: n = dataset.getValue(i, category);
392: if (n != null) {
393: double v = n.doubleValue();
394: if (this.renderAsPercentages) {
395: v = v / total;
396: }
397: result += v;
398: }
399: }
400: return result;
401:
402: }
403:
404:
417: protected double[] getStackValues(CategoryDataset dataset,
418: int series, int index) {
419: double[] result = new double[2];
420: for (int i = 0; i < series; i++) {
421: if (isSeriesVisible(i)) {
422: double v = 0.0;
423: Number n = dataset.getValue(i, index);
424: if (n != null) {
425: v = n.doubleValue();
426: }
427: if (!Double.isNaN(v)) {
428: if (v >= 0.0) {
429: result[1] += v;
430: }
431: else {
432: result[0] += v;
433: }
434: }
435: }
436: }
437: return result;
438: }
439:
440:
449: private double[] averageStackValues(double[] stack1, double[] stack2) {
450: double[] result = new double[2];
451: result[0] = (stack1[0] + stack2[0]) / 2.0;
452: result[1] = (stack1[1] + stack2[1]) / 2.0;
453: return result;
454: }
455:
456:
466: private double[] adjustedStackValues(double[] stack1, double[] stack2) {
467: double[] result = new double[2];
468: if (stack1[0] == 0.0 || stack2[0] == 0.0) {
469: result[0] = 0.0;
470: }
471: else {
472: result[0] = (stack1[0] + stack2[0]) / 2.0;
473: }
474: if (stack1[1] == 0.0 || stack2[1] == 0.0) {
475: result[1] = 0.0;
476: }
477: else {
478: result[1] = (stack1[1] + stack2[1]) / 2.0;
479: }
480: return result;
481: }
482:
483:
490: public boolean equals(Object obj) {
491: if (obj == this) {
492: return true;
493: }
494: if (!(obj instanceof StackedAreaRenderer)) {
495: return false;
496: }
497: StackedAreaRenderer that = (StackedAreaRenderer) obj;
498: if (this.renderAsPercentages != that.renderAsPercentages) {
499: return false;
500: }
501: return super.equals(obj);
502: }
503: }