1:
56:
57: package ;
58:
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65:
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: import ;
79: import ;
80:
81:
84: public class StackedXYAreaRenderer2 extends XYAreaRenderer2
85: implements Cloneable, PublicCloneable, 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: fireChangeEvent();
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: PlotOrientation orientation = plot.getOrientation();
228:
229:
230: double x1 = dataset.getXValue(series, item);
231: double y1 = dataset.getYValue(series, item);
232: if (Double.isNaN(y1)) {
233: y1 = 0.0;
234: }
235: double[] stack1 = getStackValues(tdataset, series, item);
236:
237:
238:
239: double x0 = dataset.getXValue(series, Math.max(item - 1, 0));
240: double y0 = dataset.getYValue(series, Math.max(item - 1, 0));
241: if (Double.isNaN(y0)) {
242: y0 = 0.0;
243: }
244: double[] stack0 = getStackValues(tdataset, series, Math.max(item - 1,
245: 0));
246:
247: int itemCount = dataset.getItemCount(series);
248: double x2 = dataset.getXValue(series, Math.min(item + 1,
249: itemCount - 1));
250: double y2 = dataset.getYValue(series, Math.min(item + 1,
251: itemCount - 1));
252: if (Double.isNaN(y2)) {
253: y2 = 0.0;
254: }
255: double[] stack2 = getStackValues(tdataset, series, Math.min(item + 1,
256: itemCount - 1));
257:
258: double xleft = (x0 + x1) / 2.0;
259: double xright = (x1 + x2) / 2.0;
260: double[] stackLeft = averageStackValues(stack0, stack1);
261: double[] stackRight = averageStackValues(stack1, stack2);
262: double[] adjStackLeft = adjustedStackValues(stack0, stack1);
263: double[] adjStackRight = adjustedStackValues(stack1, stack2);
264:
265: RectangleEdge edge0 = plot.getDomainAxisEdge();
266:
267: float transX1 = (float) domainAxis.valueToJava2D(x1, dataArea, edge0);
268: float transXLeft = (float) domainAxis.valueToJava2D(xleft, dataArea,
269: edge0);
270: float transXRight = (float) domainAxis.valueToJava2D(xright, dataArea,
271: edge0);
272:
273: if (this.roundXCoordinates) {
274: transX1 = Math.round(transX1);
275: transXLeft = Math.round(transXLeft);
276: transXRight = Math.round(transXRight);
277: }
278: float transY1;
279:
280: RectangleEdge edge1 = plot.getRangeAxisEdge();
281:
282: GeneralPath left = new GeneralPath();
283: GeneralPath right = new GeneralPath();
284: if (y1 >= 0.0) {
285: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[1], dataArea,
286: edge1);
287: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[1],
288: dataArea, edge1);
289: float transStackLeft = (float) rangeAxis.valueToJava2D(
290: adjStackLeft[1], dataArea, edge1);
291:
292:
293: if (y0 >= 0.0) {
294: double yleft = (y0 + y1) / 2.0 + stackLeft[1];
295: float transYLeft
296: = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
297: if (orientation == PlotOrientation.VERTICAL) {
298: left.moveTo(transX1, transY1);
299: left.lineTo(transX1, transStack1);
300: left.lineTo(transXLeft, transStackLeft);
301: left.lineTo(transXLeft, transYLeft);
302: }
303: else {
304: left.moveTo(transY1, transX1);
305: left.lineTo(transStack1, transX1);
306: left.lineTo(transStackLeft, transXLeft);
307: left.lineTo(transYLeft, transXLeft);
308: }
309: left.closePath();
310: }
311: else {
312: if (orientation == PlotOrientation.VERTICAL) {
313: left.moveTo(transX1, transStack1);
314: left.lineTo(transX1, transY1);
315: left.lineTo(transXLeft, transStackLeft);
316: }
317: else {
318: left.moveTo(transStack1, transX1);
319: left.lineTo(transY1, transX1);
320: left.lineTo(transStackLeft, transXLeft);
321: }
322: left.closePath();
323: }
324:
325: float transStackRight = (float) rangeAxis.valueToJava2D(
326: adjStackRight[1], dataArea, edge1);
327:
328: if (y2 >= 0.0) {
329: double yright = (y1 + y2) / 2.0 + stackRight[1];
330: float transYRight
331: = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
332: if (orientation == PlotOrientation.VERTICAL) {
333: right.moveTo(transX1, transStack1);
334: right.lineTo(transX1, transY1);
335: right.lineTo(transXRight, transYRight);
336: right.lineTo(transXRight, transStackRight);
337: }
338: else {
339: right.moveTo(transStack1, transX1);
340: right.lineTo(transY1, transX1);
341: right.lineTo(transYRight, transXRight);
342: right.lineTo(transStackRight, transXRight);
343: }
344: right.closePath();
345: }
346: else {
347: if (orientation == PlotOrientation.VERTICAL) {
348: right.moveTo(transX1, transStack1);
349: right.lineTo(transX1, transY1);
350: right.lineTo(transXRight, transStackRight);
351: }
352: else {
353: right.moveTo(transStack1, transX1);
354: right.lineTo(transY1, transX1);
355: right.lineTo(transStackRight, transXRight);
356: }
357: right.closePath();
358: }
359: }
360: else {
361: transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[0], dataArea,
362: edge1);
363: float transStack1 = (float) rangeAxis.valueToJava2D(stack1[0],
364: dataArea, edge1);
365: float transStackLeft = (float) rangeAxis.valueToJava2D(
366: adjStackLeft[0], dataArea, edge1);
367:
368:
369: if (y0 >= 0.0) {
370: if (orientation == PlotOrientation.VERTICAL) {
371: left.moveTo(transX1, transStack1);
372: left.lineTo(transX1, transY1);
373: left.lineTo(transXLeft, transStackLeft);
374: }
375: else {
376: left.moveTo(transStack1, transX1);
377: left.lineTo(transY1, transX1);
378: left.lineTo(transStackLeft, transXLeft);
379: }
380: left.clone();
381: }
382: else {
383: double yleft = (y0 + y1) / 2.0 + stackLeft[0];
384: float transYLeft = (float) rangeAxis.valueToJava2D(yleft,
385: dataArea, edge1);
386: if (orientation == PlotOrientation.VERTICAL) {
387: left.moveTo(transX1, transY1);
388: left.lineTo(transX1, transStack1);
389: left.lineTo(transXLeft, transStackLeft);
390: left.lineTo(transXLeft, transYLeft);
391: }
392: else {
393: left.moveTo(transY1, transX1);
394: left.lineTo(transStack1, transX1);
395: left.lineTo(transStackLeft, transXLeft);
396: left.lineTo(transYLeft, transXLeft);
397: }
398: left.closePath();
399: }
400: float transStackRight = (float) rangeAxis.valueToJava2D(
401: adjStackRight[0], dataArea, edge1);
402:
403:
404: if (y2 >= 0.0) {
405: if (orientation == PlotOrientation.VERTICAL) {
406: right.moveTo(transX1, transStack1);
407: right.lineTo(transX1, transY1);
408: right.lineTo(transXRight, transStackRight);
409: }
410: else {
411: right.moveTo(transStack1, transX1);
412: right.lineTo(transY1, transX1);
413: right.lineTo(transStackRight, transXRight);
414: }
415: right.closePath();
416: }
417: else {
418: double yright = (y1 + y2) / 2.0 + stackRight[0];
419: float transYRight = (float) rangeAxis.valueToJava2D(yright,
420: dataArea, edge1);
421: if (orientation == PlotOrientation.VERTICAL) {
422: right.moveTo(transX1, transStack1);
423: right.lineTo(transX1, transY1);
424: right.lineTo(transXRight, transYRight);
425: right.lineTo(transXRight, transStackRight);
426: }
427: else {
428: right.moveTo(transStack1, transX1);
429: right.lineTo(transY1, transX1);
430: right.lineTo(transYRight, transXRight);
431: right.lineTo(transStackRight, transXRight);
432: }
433: right.closePath();
434: }
435: }
436:
437:
438: Paint itemPaint = getItemPaint(series, item);
439: if (pass == 0) {
440: g2.setPaint(itemPaint);
441: g2.fill(left);
442: g2.fill(right);
443: }
444:
445:
446: if (entities != null) {
447: GeneralPath gp = new GeneralPath(left);
448: gp.append(right, false);
449: entityArea = gp;
450: addEntity(entities, entityArea, dataset, series, item,
451: transX1, transY1);
452: }
453:
454: }
455:
456:
469: private double[] getStackValues(TableXYDataset dataset,
470: int series, int index) {
471: double[] result = new double[2];
472: for (int i = 0; i < series; i++) {
473: double v = dataset.getYValue(i, index);
474: if (!Double.isNaN(v)) {
475: if (v >= 0.0) {
476: result[1] += v;
477: }
478: else {
479: result[0] += v;
480: }
481: }
482: }
483: return result;
484: }
485:
486:
495: private double[] averageStackValues(double[] stack1, double[] stack2) {
496: double[] result = new double[2];
497: result[0] = (stack1[0] + stack2[0]) / 2.0;
498: result[1] = (stack1[1] + stack2[1]) / 2.0;
499: return result;
500: }
501:
502:
512: private double[] adjustedStackValues(double[] stack1, double[] stack2) {
513: double[] result = new double[2];
514: if (stack1[0] == 0.0 || stack2[0] == 0.0) {
515: result[0] = 0.0;
516: }
517: else {
518: result[0] = (stack1[0] + stack2[0]) / 2.0;
519: }
520: if (stack1[1] == 0.0 || stack2[1] == 0.0) {
521: result[1] = 0.0;
522: }
523: else {
524: result[1] = (stack1[1] + stack2[1]) / 2.0;
525: }
526: return result;
527: }
528:
529:
536: public boolean equals(Object obj) {
537: if (obj == this) {
538: return true;
539: }
540: if (!(obj instanceof StackedXYAreaRenderer2)) {
541: return false;
542: }
543: StackedXYAreaRenderer2 that = (StackedXYAreaRenderer2) obj;
544: if (this.roundXCoordinates != that.roundXCoordinates) {
545: return false;
546: }
547: return super.equals(obj);
548: }
549:
550:
557: public Object clone() throws CloneNotSupportedException {
558: return super.clone();
559: }
560:
561: }