1:
84:
85: package ;
86:
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94:
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108:
109:
113: public class CombinedDomainXYPlot extends XYPlot
114: implements Cloneable, PublicCloneable,
115: Serializable,
116: PlotChangeListener {
117:
118:
119: private static final long serialVersionUID = -7765545541261907383L;
120:
121:
122: private List subplots;
123:
124:
125: private int totalWeight = 0;
126:
127:
128: private double gap = 5.0;
129:
130:
131: private transient Rectangle2D[] subplotAreas;
132:
133:
134:
135:
138: public CombinedDomainXYPlot() {
139: this(new NumberAxis());
140: }
141:
142:
148: public CombinedDomainXYPlot(ValueAxis domainAxis) {
149:
150: super(
151: null,
152: domainAxis,
153: null,
154: null
155: );
156:
157: this.subplots = new java.util.ArrayList();
158:
159: }
160:
161:
166: public String getPlotType() {
167: return "Combined_Domain_XYPlot";
168: }
169:
170:
176: public void setOrientation(PlotOrientation orientation) {
177:
178: super.setOrientation(orientation);
179: Iterator iterator = this.subplots.iterator();
180: while (iterator.hasNext()) {
181: XYPlot plot = (XYPlot) iterator.next();
182: plot.setOrientation(orientation);
183: }
184:
185: }
186:
187:
195: public Range getDataRange(ValueAxis axis) {
196:
197: Range result = null;
198: if (this.subplots != null) {
199: Iterator iterator = this.subplots.iterator();
200: while (iterator.hasNext()) {
201: XYPlot subplot = (XYPlot) iterator.next();
202: result = Range.combine(result, subplot.getDataRange(axis));
203: }
204: }
205: return result;
206:
207: }
208:
209:
214: public double getGap() {
215: return this.gap;
216: }
217:
218:
224: public void setGap(double gap) {
225: this.gap = gap;
226: notifyListeners(new PlotChangeEvent(this));
227: }
228:
229:
237: public void add(XYPlot subplot) {
238:
239: add(subplot, 1);
240: }
241:
242:
253: public void add(XYPlot subplot, int weight) {
254:
255: if (subplot == null) {
256: throw new IllegalArgumentException("Null 'subplot' argument.");
257: }
258: if (weight <= 0) {
259: throw new IllegalArgumentException("Require weight >= 1.");
260: }
261:
262:
263: subplot.setParent(this);
264: subplot.setWeight(weight);
265: subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0), false);
266: subplot.setDomainAxis(null);
267: subplot.addChangeListener(this);
268: this.subplots.add(subplot);
269:
270:
271: this.totalWeight += weight;
272:
273: ValueAxis axis = getDomainAxis();
274: if (axis != null) {
275: axis.configure();
276: }
277:
278: notifyListeners(new PlotChangeEvent(this));
279:
280: }
281:
282:
288: public void remove(XYPlot subplot) {
289: if (subplot == null) {
290: throw new IllegalArgumentException(" Null 'subplot' argument.");
291: }
292: int position = -1;
293: int size = this.subplots.size();
294: int i = 0;
295: while (position == -1 && i < size) {
296: if (this.subplots.get(i) == subplot) {
297: position = i;
298: }
299: i++;
300: }
301: if (position != -1) {
302: this.subplots.remove(position);
303: subplot.setParent(null);
304: subplot.removeChangeListener(this);
305: this.totalWeight -= subplot.getWeight();
306:
307: ValueAxis domain = getDomainAxis();
308: if (domain != null) {
309: domain.configure();
310: }
311: notifyListeners(new PlotChangeEvent(this));
312: }
313: }
314:
315:
320: public List getSubplots() {
321: return Collections.unmodifiableList(this.subplots);
322: }
323:
324:
332: protected AxisSpace calculateAxisSpace(Graphics2D g2,
333: Rectangle2D plotArea) {
334:
335: AxisSpace space = new AxisSpace();
336: PlotOrientation orientation = getOrientation();
337:
338:
339: AxisSpace fixed = getFixedDomainAxisSpace();
340: if (fixed != null) {
341: if (orientation == PlotOrientation.HORIZONTAL) {
342: space.setLeft(fixed.getLeft());
343: space.setRight(fixed.getRight());
344: }
345: else if (orientation == PlotOrientation.VERTICAL) {
346: space.setTop(fixed.getTop());
347: space.setBottom(fixed.getBottom());
348: }
349: }
350: else {
351: ValueAxis xAxis = getDomainAxis();
352: RectangleEdge xEdge = Plot.resolveDomainAxisLocation(
353: getDomainAxisLocation(), orientation
354: );
355: if (xAxis != null) {
356: space = xAxis.reserveSpace(g2, this, plotArea, xEdge, space);
357: }
358: }
359:
360: Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
361:
362:
363: int n = this.subplots.size();
364: this.subplotAreas = new Rectangle2D[n];
365: double x = adjustedPlotArea.getX();
366: double y = adjustedPlotArea.getY();
367: double usableSize = 0.0;
368: if (orientation == PlotOrientation.HORIZONTAL) {
369: usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
370: }
371: else if (orientation == PlotOrientation.VERTICAL) {
372: usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
373: }
374:
375: for (int i = 0; i < n; i++) {
376: XYPlot plot = (XYPlot) this.subplots.get(i);
377:
378:
379: if (orientation == PlotOrientation.HORIZONTAL) {
380: double w = usableSize * plot.getWeight() / this.totalWeight;
381: this.subplotAreas[i] = new Rectangle2D.Double(
382: x, y, w, adjustedPlotArea.getHeight()
383: );
384: x = x + w + this.gap;
385: }
386: else if (orientation == PlotOrientation.VERTICAL) {
387: double h = usableSize * plot.getWeight() / this.totalWeight;
388: this.subplotAreas[i] = new Rectangle2D.Double(
389: x, y, adjustedPlotArea.getWidth(), h
390: );
391: y = y + h + this.gap;
392: }
393:
394: AxisSpace subSpace = plot.calculateRangeAxisSpace(
395: g2, this.subplotAreas[i], null
396: );
397: space.ensureAtLeast(subSpace);
398:
399: }
400:
401: return space;
402: }
403:
404:
416: public void draw(Graphics2D g2,
417: Rectangle2D area,
418: Point2D anchor,
419: PlotState parentState,
420: PlotRenderingInfo info) {
421:
422:
423: if (info != null) {
424: info.setPlotArea(area);
425: }
426:
427:
428: RectangleInsets insets = getInsets();
429: insets.trim(area);
430:
431: AxisSpace space = calculateAxisSpace(g2, area);
432: Rectangle2D dataArea = space.shrink(area, null);
433:
434:
435: setFixedRangeAxisSpaceForSubplots(space);
436:
437:
438: ValueAxis axis = getDomainAxis();
439: RectangleEdge edge = getDomainAxisEdge();
440: double cursor = RectangleEdge.coordinate(dataArea, edge);
441: AxisState axisState = axis.draw(g2, cursor, area, dataArea, edge, info);
442: if (parentState == null) {
443: parentState = new PlotState();
444: }
445: parentState.getSharedAxisStates().put(axis, axisState);
446:
447:
448: for (int i = 0; i < this.subplots.size(); i++) {
449: XYPlot plot = (XYPlot) this.subplots.get(i);
450: PlotRenderingInfo subplotInfo = null;
451: if (info != null) {
452: subplotInfo = new PlotRenderingInfo(info.getOwner());
453: info.addSubplotInfo(subplotInfo);
454: }
455: plot.draw(
456: g2, this.subplotAreas[i], anchor, parentState, subplotInfo
457: );
458: }
459:
460: if (info != null) {
461: info.setDataArea(dataArea);
462: }
463:
464: }
465:
466:
471: public LegendItemCollection getLegendItems() {
472: LegendItemCollection result = getFixedLegendItems();
473: if (result == null) {
474: result = new LegendItemCollection();
475: if (this.subplots != null) {
476: Iterator iterator = this.subplots.iterator();
477: while (iterator.hasNext()) {
478: XYPlot plot = (XYPlot) iterator.next();
479: LegendItemCollection more = plot.getLegendItems();
480: result.addAll(more);
481: }
482: }
483: }
484: return result;
485: }
486:
487:
494: public void zoomRangeAxes(double factor, PlotRenderingInfo info,
495: Point2D source) {
496: XYPlot subplot = findSubplot(info, source);
497: if (subplot != null) {
498: subplot.zoomRangeAxes(factor, info, source);
499: }
500: }
501:
502:
510: public void zoomRangeAxes(double lowerPercent, double upperPercent,
511: PlotRenderingInfo info, Point2D source) {
512: XYPlot subplot = findSubplot(info, source);
513: if (subplot != null) {
514: subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
515: }
516: }
517:
518:
527: public XYPlot findSubplot(PlotRenderingInfo info, Point2D source) {
528: XYPlot result = null;
529: int subplotIndex = info.getSubplotIndex(source);
530: if (subplotIndex >= 0) {
531: result = (XYPlot) this.subplots.get(subplotIndex);
532: }
533: return result;
534: }
535:
536:
545: public void setRenderer(XYItemRenderer renderer) {
546:
547: super.setRenderer(renderer);
548:
549:
550:
551: Iterator iterator = this.subplots.iterator();
552: while (iterator.hasNext()) {
553: XYPlot plot = (XYPlot) iterator.next();
554: plot.setRenderer(renderer);
555: }
556:
557: }
558:
559:
564: public void setFixedRangeAxisSpace(AxisSpace space) {
565: super.setFixedRangeAxisSpace(space);
566: setFixedRangeAxisSpaceForSubplots(space);
567: this.notifyListeners(new PlotChangeEvent(this));
568: }
569:
570:
576: protected void setFixedRangeAxisSpaceForSubplots(AxisSpace space) {
577:
578: Iterator iterator = this.subplots.iterator();
579: while (iterator.hasNext()) {
580: XYPlot plot = (XYPlot) iterator.next();
581: plot.setFixedRangeAxisSpace(space);
582: }
583:
584: }
585:
586:
593: public void handleClick(int x, int y, PlotRenderingInfo info) {
594: Rectangle2D dataArea = info.getDataArea();
595: if (dataArea.contains(x, y)) {
596: for (int i = 0; i < this.subplots.size(); i++) {
597: XYPlot subplot = (XYPlot) this.subplots.get(i);
598: PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
599: subplot.handleClick(x, y, subplotInfo);
600: }
601: }
602: }
603:
604:
610: public void plotChanged(PlotChangeEvent event) {
611: notifyListeners(event);
612: }
613:
614:
621: public boolean equals(Object obj) {
622:
623: if (obj == null) {
624: return false;
625: }
626:
627: if (obj == this) {
628: return true;
629: }
630:
631: if (!(obj instanceof CombinedDomainXYPlot)) {
632: return false;
633: }
634: if (!super.equals(obj)) {
635: return false;
636: }
637:
638: CombinedDomainXYPlot p = (CombinedDomainXYPlot) obj;
639: if (this.totalWeight != p.totalWeight) {
640: return false;
641: }
642: if (this.gap != p.gap) {
643: return false;
644: }
645: if (!ObjectUtilities.equal(this.subplots, p.subplots)) {
646: return false;
647: }
648:
649: return true;
650: }
651:
652:
660: public Object clone() throws CloneNotSupportedException {
661:
662: CombinedDomainXYPlot result = (CombinedDomainXYPlot) super.clone();
663: result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
664: for (Iterator it = result.subplots.iterator(); it.hasNext();) {
665: Plot child = (Plot) it.next();
666: child.setParent(result);
667: }
668:
669:
670:
671: ValueAxis domainAxis = result.getDomainAxis();
672: if (domainAxis != null) {
673: domainAxis.configure();
674: }
675:
676: return result;
677:
678: }
679:
680: }