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