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 :

http://dive4elements.wald.intevation.org