1:
55:
56: package ;
57:
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64:
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78:
79:
82: public class StackedXYAreaRenderer2 extends XYAreaRenderer2
83: implements Cloneable,
84: PublicCloneable,
85: Serializable {
86:
87:
88: private static final long serialVersionUID = 7752676509764539182L;
89:
90:
99: private boolean roundXCoordinates;
100:
101:
104: public StackedXYAreaRenderer2() {
105: this(null, null);
106: }
107:
108:
115: public StackedXYAreaRenderer2(XYToolTipGenerator labelGenerator,
116: XYURLGenerator urlGenerator) {
117: super(labelGenerator, urlGenerator);
118: this.roundXCoordinates = true;
119: }
120:
121:
131: public boolean getRoundXCoordinates() {
132: return this.roundXCoordinates;
133: }
134:
135:
146: public void setRoundXCoordinates(boolean round) {
147: this.roundXCoordinates = round;
148: notifyListeners(new RendererChangeEvent(this));
149: }
150:
151:
160: public Range findRangeBounds(XYDataset dataset) {
161: if (dataset == null) {
162: return null;
163: }
164: double min = Double.POSITIVE_INFINITY;
165: double max = Double.NEGATIVE_INFINITY;
166: TableXYDataset d = (TableXYDataset) dataset;
167: int itemCount = d.getItemCount();
168: for (int i = 0; i < itemCount; i++) {
169: double[] stackValues = getStackValues((TableXYDataset) dataset,
170: d.getSeriesCount(), i);
171: min = Math.min(min, stackValues[0]);
172: max = Math.max(max, stackValues[1]);
173: }
174: if (min == Double.POSITIVE_INFINITY) {
175: return null;
176: }
177: return new Range(min, max);
178: }
179:
180:
185: public int getPassCount() {
186: return 1;
187: }
188:
189:
206: public void drawItem(Graphics2D g2,
207: XYItemRendererState state,
208: Rectangle2D dataArea,
209: PlotRenderingInfo info,
210: XYPlot plot,
211: ValueAxis domainAxis,
212: ValueAxis rangeAxis,
213: XYDataset dataset,
214: int series,
215: int item,
216: CrosshairState crosshairState,
217: int pass) {
218:
219:
220: Shape entityArea = null;
221: EntityCollection entities = null;
222: if (info != null) {
223: entities = info.getOwner().getEntityCollection();
224: }
225:
226: TableXYDataset tdataset = (TableXYDataset) dataset;
227:
228:
229: double x1 = dataset.getXValue(series, item);
230: double y1 = dataset.getYValue(series, item);
231: if (Double.isNaN(y1)) {
232: y1 = 0.0;
233: }
234: double[] stack1 = getStackValues(tdataset, series, item);
235:
236:
237:
238: double x0 = dataset.getXValue(series, Math.max(item - 1, 0));
239: double y0 = dataset.getYValue(series, Math.max(item - 1, 0));
240: if (Double.isNaN(y0)) {
241: y0 = 0.0;
242: }
243: double[] stack0 = getStackValues(tdataset, series, Math.max(item - 1,
244: 0));
245:
246: int itemCount = dataset.getItemCount(series);
247: double x2 = dataset.getXValue(series, Math.min(item + 1,
248: itemCount - 1));
249: double y2 = dataset.getYValue(series, Math.min(item + 1,
250: itemCount - 1));
251: if (Double.isNaN(y2)) {
252: y2 = 0.0;
253: }
254: double[] stack2 = getStackValues(tdataset, series, Math.min(item + 1,
255: itemCount - 1));
256:
257: double xleft = (x0 + x1) / 2.0;
258: double xright = (x1 + x2) / 2.0;
259: double[] stackLeft = averageStackValues(stack0, stack1);
260: double[] stackRight = averageStackValues(stack1, stack2);
261: double[] adjStackLeft = adjustedStackValues(stack0, stack1);
262: double[] adjStackRight = adjustedStackValues(stack1, stack2);
263:
264: RectangleEdge edge0 = plot.getDomainAxisEdge();
265:
266: float transX1 = (float) domainAxis.valueToJava2D(x1, dataArea, edge0);
267: float transXLeft = (float) domainAxis.valueToJava2D(xleft, dataArea,
268: edge0);
269: float transXRight = (float) domainAxis.valueToJava2D(xright, dataArea,
270: edge0);
271:
272: if (this.roundXCoordinates) {
273: transX1 = Math.round(transX1);
274: transXLeft = Math.round(transXLeft);
275: transXRight = Math.round(transXRight);
276: }
277: float transY1;
278:
279: RectangleEdge edge1 = plot.getRangeAxisEdge();
280:
281: GeneralPath left = new GeneralPath();
282: GeneralPath right = new GeneralPath();
283: if (y1 >= 0.0) {
284: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[1], dataArea,
285: edge1);
286: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[1],
287: dataArea, edge1);
288: float transStackLeft = (float) rangeAxis.valueToJava2D(
289: adjStackLeft[1], dataArea, edge1);
290:
291:
292: if (y0 >= 0.0) {
293: double yleft = (y0 + y1) / 2.0 + stackLeft[1];
294: float transYLeft
295: = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
296: left.moveTo(transX1, transY1);
297: left.lineTo(transX1, transStack1);
298: left.lineTo(transXLeft, transStackLeft);
299: left.lineTo(transXLeft, transYLeft);
300: left.closePath();
301: }
302: else {
303: left.moveTo(transX1, transStack1);
304: left.lineTo(transX1, transY1);
305: left.lineTo(transXLeft, transStackLeft);
306: left.closePath();
307: }
308:
309: float transStackRight = (float) rangeAxis.valueToJava2D(
310: adjStackRight[1], dataArea, edge1);
311:
312: if (y2 >= 0.0) {
313: double yright = (y1 + y2) / 2.0 + stackRight[1];
314: float transYRight
315: = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
316: right.moveTo(transX1, transStack1);
317: right.lineTo(transX1, transY1);
318: right.lineTo(transXRight, transYRight);
319: right.lineTo(transXRight, transStackRight);
320: right.closePath();
321: }
322: else {
323: right.moveTo(transX1, transStack1);
324: right.lineTo(transX1, transY1);
325: right.lineTo(transXRight, transStackRight);
326: right.closePath();
327: }
328: }
329: else {
330: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[0], dataArea,
331: edge1);
332: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[0],
333: dataArea, edge1);
334: float transStackLeft = (float) rangeAxis.valueToJava2D(
335: adjStackLeft[0], dataArea, edge1);
336:
337:
338: if (y0 >= 0.0) {
339: left.moveTo(transX1, transStack1);
340: left.lineTo(transX1, transY1);
341: left.lineTo(transXLeft, transStackLeft);
342: left.clone();
343: }
344: else {
345: double yleft = (y0 + y1) / 2.0 + stackLeft[0];
346: float transYLeft = (float) rangeAxis.valueToJava2D(yleft,
347: dataArea, edge1);
348: left.moveTo(transX1, transY1);
349: left.lineTo(transX1, transStack1);
350: left.lineTo(transXLeft, transStackLeft);
351: left.lineTo(transXLeft, transYLeft);
352: left.closePath();
353: }
354: float transStackRight = (float) rangeAxis.valueToJava2D(
355: adjStackRight[0], dataArea, edge1);
356:
357:
358: if (y2 >= 0.0) {
359: right.moveTo(transX1, transStack1);
360: right.lineTo(transX1, transY1);
361: right.lineTo(transXRight, transStackRight);
362: right.closePath();
363: }
364: else {
365: double yright = (y1 + y2) / 2.0 + stackRight[0];
366: float transYRight = (float) rangeAxis.valueToJava2D(yright,
367: dataArea, edge1);
368: right.moveTo(transX1, transStack1);
369: right.lineTo(transX1, transY1);
370: right.lineTo(transXRight, transYRight);
371: right.lineTo(transXRight, transStackRight);
372: right.closePath();
373: }
374: }
375:
376:
377: Paint itemPaint = getItemPaint(series, item);
378: if (pass == 0) {
379: g2.setPaint(itemPaint);
380: g2.fill(left);
381: g2.fill(right);
382: }
383:
384:
385: if (entities != null) {
386: GeneralPath gp = new GeneralPath(left);
387: gp.append(right, false);
388: entityArea = gp;
389: addEntity(entities, entityArea, dataset, series, item,
390: transX1, transY1);
391: }
392:
393: }
394:
395:
408: private double[] getStackValues(TableXYDataset dataset,
409: int series, int index) {
410: double[] result = new double[2];
411: for (int i = 0; i < series; i++) {
412: double v = dataset.getYValue(i, index);
413: if (!Double.isNaN(v)) {
414: if (v >= 0.0) {
415: result[1] += v;
416: }
417: else {
418: result[0] += v;
419: }
420: }
421: }
422: return result;
423: }
424:
425:
434: private double[] averageStackValues(double[] stack1, double[] stack2) {
435: double[] result = new double[2];
436: result[0] = (stack1[0] + stack2[0]) / 2.0;
437: result[1] = (stack1[1] + stack2[1]) / 2.0;
438: return result;
439: }
440:
441:
451: private double[] adjustedStackValues(double[] stack1, double[] stack2) {
452: double[] result = new double[2];
453: if (stack1[0] == 0.0 || stack2[0] == 0.0) {
454: result[0] = 0.0;
455: }
456: else {
457: result[0] = (stack1[0] + stack2[0]) / 2.0;
458: }
459: if (stack1[1] == 0.0 || stack2[1] == 0.0) {
460: result[1] = 0.0;
461: }
462: else {
463: result[1] = (stack1[1] + stack2[1]) / 2.0;
464: }
465: return result;
466: }
467:
468:
475: public boolean equals(Object obj) {
476: if (obj == this) {
477: return true;
478: }
479: if (!(obj instanceof StackedXYAreaRenderer2)) {
480: return false;
481: }
482: StackedXYAreaRenderer2 that = (StackedXYAreaRenderer2) obj;
483: if (this.roundXCoordinates != that.roundXCoordinates) {
484: return false;
485: }
486: return super.equals(obj);
487: }
488:
489:
496: public Object clone() throws CloneNotSupportedException {
497: return super.clone();
498: }
499:
500: }