Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java @ 2633:894186b4c1d0
Issue 494.
Add manual points with text annotations to time charts.
flys-artifacts/trunk@4255 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Raimund Renkert <raimund.renkert@intevation.de> |
---|---|
date | Wed, 18 Apr 2012 07:14:48 +0000 |
parents | d75b427da50a |
children | fa015cf5c0af |
comparison
equal
deleted
inserted
replaced
2632:7d163c2c6e6d | 2633:894186b4c1d0 |
---|---|
1 package de.intevation.flys.exports; | 1 package de.intevation.flys.exports; |
2 | 2 |
3 import java.awt.Color; | 3 import java.awt.Color; |
4 import java.awt.Font; | 4 import java.awt.Font; |
5 import java.awt.Paint; | |
6 import java.awt.BasicStroke; | |
7 import java.awt.Stroke; | |
5 | 8 |
6 import java.util.ArrayList; | 9 import java.util.ArrayList; |
7 import java.util.HashMap; | 10 import java.util.HashMap; |
8 import java.util.List; | 11 import java.util.List; |
9 import java.util.Map; | 12 import java.util.Map; |
13 import java.util.Date; | |
14 | |
15 import org.json.JSONArray; | |
16 import org.json.JSONException; | |
10 | 17 |
11 import org.apache.log4j.Logger; | 18 import org.apache.log4j.Logger; |
19 | |
20 import org.w3c.dom.Document; | |
12 | 21 |
13 import org.jfree.chart.ChartFactory; | 22 import org.jfree.chart.ChartFactory; |
14 import org.jfree.chart.JFreeChart; | 23 import org.jfree.chart.JFreeChart; |
15 import org.jfree.chart.axis.ValueAxis; | 24 import org.jfree.chart.axis.ValueAxis; |
16 import org.jfree.chart.plot.XYPlot; | 25 import org.jfree.chart.plot.XYPlot; |
26 import org.jfree.chart.annotations.XYTextAnnotation; | |
27 import org.jfree.chart.LegendItemCollection; | |
17 | 28 |
18 import org.jfree.data.Range; | 29 import org.jfree.data.Range; |
19 import org.jfree.data.time.TimeSeriesCollection; | 30 import org.jfree.data.time.TimeSeriesCollection; |
20 import org.jfree.data.general.Series; | 31 import org.jfree.data.general.Series; |
21 import org.jfree.data.xy.XYDataset; | 32 import org.jfree.data.xy.XYDataset; |
33 import org.jfree.data.general.SeriesException; | |
34 import org.jfree.data.time.Day; | |
35 import org.jfree.data.time.RegularTimePeriod; | |
36 import org.jfree.data.time.TimeSeries; | |
37 | |
38 import de.intevation.artifactdatabase.state.ArtifactAndFacet; | |
39 import de.intevation.artifactdatabase.state.Facet; | |
22 | 40 |
23 import de.intevation.flys.jfree.Bounds; | 41 import de.intevation.flys.jfree.Bounds; |
24 import de.intevation.flys.jfree.DoubleBounds; | 42 import de.intevation.flys.jfree.DoubleBounds; |
25 import de.intevation.flys.jfree.TimeBounds; | 43 import de.intevation.flys.jfree.TimeBounds; |
26 | 44 import de.intevation.flys.jfree.StyledTimeSeries; |
45 import de.intevation.flys.jfree.FLYSAnnotation; | |
46 import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; | |
47 | |
48 import de.intevation.flys.utils.ThemeAccess; | |
27 | 49 |
28 /** | 50 /** |
29 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | 51 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> |
30 */ | 52 */ |
31 public abstract class TimeseriesChartGenerator extends ChartGenerator { | 53 public abstract class TimeseriesChartGenerator extends ChartGenerator { |
119 logger.debug("Range after merging: " + range); | 141 logger.debug("Range after merging: " + range); |
120 } | 142 } |
121 | 143 |
122 } // end of TimeseriesAxisDataset class | 144 } // end of TimeseriesAxisDataset class |
123 | 145 |
146 | |
147 /** List of annotations to insert in plot. */ | |
148 protected List<FLYSAnnotation> annotations; | |
124 | 149 |
125 | 150 |
126 private static final Logger logger = | 151 private static final Logger logger = |
127 Logger.getLogger(TimeseriesChartGenerator.class); | 152 Logger.getLogger(TimeseriesChartGenerator.class); |
128 | 153 |
170 adjustPlot(plot); | 195 adjustPlot(plot); |
171 addDatasets(plot); | 196 addDatasets(plot); |
172 adjustAxes(plot); | 197 adjustAxes(plot); |
173 | 198 |
174 adaptZoom(plot); | 199 adaptZoom(plot); |
200 | |
201 addAnnotationsToRenderer(plot); | |
175 | 202 |
176 return chart; | 203 return chart; |
177 } | 204 } |
178 | 205 |
179 | 206 |
448 getXAxisLabelFontSize()); | 475 getXAxisLabelFontSize()); |
449 | 476 |
450 xaxis.setLabelFont(labelFont); | 477 xaxis.setLabelFont(labelFont); |
451 xaxis.setTickLabelFont(labelFont); | 478 xaxis.setTickLabelFont(labelFont); |
452 } | 479 } |
480 | |
481 | |
482 /** | |
483 * Do Points out. | |
484 */ | |
485 protected void doPoints( | |
486 Object o, | |
487 ArtifactAndFacet aandf, | |
488 Document theme, | |
489 boolean visible, | |
490 int axisIndex | |
491 ) { | |
492 String seriesName = aandf.getFacetDescription(); | |
493 TimeSeries series = new StyledTimeSeries(seriesName, theme); | |
494 | |
495 // Add text annotations for single points. | |
496 List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); | |
497 HashMap<Day, String> names = new HashMap<Day, String>(); | |
498 | |
499 try { | |
500 JSONArray points = new JSONArray((String) o); | |
501 for (int i = 0; i < points.length(); i++) { | |
502 JSONArray array = points.getJSONArray(i); | |
503 double x = array.getDouble(0); | |
504 double y = array.getDouble(1); | |
505 String name = array.getString(2); | |
506 boolean act = array.getBoolean(3); | |
507 if (!act) { | |
508 continue; | |
509 } | |
510 long l = (new Double(x)).longValue(); | |
511 Date date = new Date(l); | |
512 Day day = new Day(date); | |
513 series.add(day, y, false); | |
514 names.put(day, name); | |
515 } | |
516 } | |
517 catch(JSONException e){ | |
518 logger.error("Could not decode json."); | |
519 } | |
520 | |
521 TimeSeriesCollection tsc = new TimeSeriesCollection(); | |
522 tsc.addSeries(series); | |
523 // Add Annotations. | |
524 for (int i = 0; i < series.getItemCount(); i++) { | |
525 double x = tsc.getXValue(0, i); | |
526 double y = tsc.getYValue(0, i); | |
527 xy.add(new CollisionFreeXYTextAnnotation( | |
528 names.get(series.getTimePeriod(i)), x, y)); | |
529 } | |
530 FLYSAnnotation annotations = | |
531 new FLYSAnnotation(null, null, null, theme); | |
532 annotations.setTextAnnotations(xy); | |
533 | |
534 // Do not generate second legend entry. (null was passed for the aand before). | |
535 doAnnotations(annotations, aandf, theme, visible); | |
536 | |
537 addAxisDataset(tsc, axisIndex, visible); | |
538 } | |
539 | |
540 /** | |
541 * Register annotations like MainValues for later plotting | |
542 * | |
543 * @param o list of annotations (data of facet). | |
544 * @param facet The facet. This facet does NOT support any data objects. Use | |
545 * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports | |
546 * data. | |
547 * @param theme Theme document for given annotations. | |
548 * @param visible The visibility of the annotations. | |
549 */ | |
550 protected void doAnnotations( | |
551 FLYSAnnotation annotations, | |
552 ArtifactAndFacet aandf, | |
553 Document theme, | |
554 boolean visible | |
555 ){ | |
556 // Running into trouble here. | |
557 logger.debug("doAnnotations"); | |
558 | |
559 // Add all annotations to our annotation pool. | |
560 annotations.setTheme(theme); | |
561 if (aandf != null) { | |
562 Facet facet = aandf.getFacet(); | |
563 annotations.setLabel(aandf.getFacetDescription()); | |
564 } | |
565 else { | |
566 logger.debug( | |
567 "Art/Facet for Annotations is null. " + | |
568 "This should never happen!"); | |
569 } | |
570 | |
571 addAnnotations(annotations, visible); | |
572 } | |
573 | |
574 | |
575 | |
576 /** | |
577 * Adds annotations to list (if visible is true). | |
578 */ | |
579 public void addAnnotations(FLYSAnnotation annotation, boolean visible) { | |
580 if (!visible) { | |
581 return; | |
582 } | |
583 | |
584 if (annotations == null) { | |
585 annotations = new ArrayList<FLYSAnnotation>(); | |
586 } | |
587 | |
588 annotations.add(annotation); | |
589 } | |
590 | |
591 | |
592 /** Add annotations (Sticky, Text and hyk zones). */ | |
593 public void addAnnotationsToRenderer(XYPlot plot) { | |
594 logger.debug("XYChartGenerator.addAnnotationsToRenderer"); | |
595 | |
596 if (annotations == null) { | |
597 logger.debug("XYChartGenerator.addBoxAnnotations: no annotations."); | |
598 return; | |
599 } | |
600 | |
601 // Paints for the boxes/lines. | |
602 Stroke basicStroke = new BasicStroke(1.0f); | |
603 | |
604 Paint linePaint = new Color(255, 0,0,60); | |
605 Paint fillPaint = new Color(0, 255,0,60); | |
606 Paint tranPaint = new Color(0, 0,0, 0); | |
607 | |
608 // OPTMIMIZE: Pre-calculate positions | |
609 Area area = new Area( | |
610 plot.getDomainAxis(0).getRange(), | |
611 plot.getRangeAxis().getRange()); | |
612 | |
613 // Walk over all Annotation sets. | |
614 for (FLYSAnnotation fa: annotations) { | |
615 | |
616 // Access text styling, if any. | |
617 Document theme = fa.getTheme(); | |
618 ThemeAccess.TextStyle textStyle = null; | |
619 ThemeAccess.LineStyle lineStyle = null; | |
620 | |
621 // Get Themeing information and add legend item. | |
622 if (theme != null) { | |
623 ThemeAccess themeAccess = new ThemeAccess(theme); | |
624 textStyle = themeAccess.parseTextStyle(); | |
625 lineStyle = themeAccess.parseLineStyle(); | |
626 if (fa.getLabel() != null) { | |
627 LegendItemCollection lic = new LegendItemCollection(); | |
628 LegendItemCollection old = plot.getFixedLegendItems(); | |
629 lic.add(createLegendItem(theme, fa.getLabel())); | |
630 // (Re-)Add prior legend entries. | |
631 if (old != null) { | |
632 old.addAll(lic); | |
633 } | |
634 else { | |
635 old = lic; | |
636 } | |
637 plot.setFixedLegendItems(old); | |
638 } | |
639 } | |
640 | |
641 // Other Text Annotations (e.g. labels of manual points). | |
642 for (XYTextAnnotation ta: fa.getTextAnnotations()) { | |
643 // Style the text. | |
644 if (textStyle != null) { | |
645 textStyle.apply(ta); | |
646 } | |
647 ta.setY(area.above(0.05d, ta.getY())); | |
648 plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); | |
649 } | |
650 } | |
651 } | |
652 | |
653 | |
654 /** Two Ranges that span a rectangular area. */ | |
655 public static class Area { | |
656 protected Range xRange; | |
657 protected Range yRange; | |
658 | |
659 public Area(Range rangeX, Range rangeY) { | |
660 this.xRange = rangeX; | |
661 this.yRange = rangeY; | |
662 } | |
663 | |
664 public Area(ValueAxis axisX, ValueAxis axisY) { | |
665 this.xRange = axisX.getRange(); | |
666 this.yRange = axisY.getRange(); | |
667 } | |
668 | |
669 public double ofLeft(double percent) { | |
670 return xRange.getLowerBound() | |
671 + xRange.getLength() * percent; | |
672 } | |
673 | |
674 public double ofRight(double percent) { | |
675 return xRange.getUpperBound() | |
676 - xRange.getLength() * percent; | |
677 } | |
678 | |
679 public double ofGround(double percent) { | |
680 return yRange.getLowerBound() | |
681 + yRange.getLength() * percent; | |
682 } | |
683 | |
684 public double atTop() { | |
685 return yRange.getUpperBound(); | |
686 } | |
687 | |
688 public double atGround() { | |
689 return yRange.getLowerBound(); | |
690 } | |
691 | |
692 public double atRight() { | |
693 return xRange.getUpperBound(); | |
694 } | |
695 | |
696 public double atLeft() { | |
697 return xRange.getLowerBound(); | |
698 } | |
699 | |
700 public double above(double percent, double base) { | |
701 return base + yRange.getLength() * percent; | |
702 } | |
703 } | |
704 | |
453 } | 705 } |
454 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : | 706 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |