# HG changeset patch # User Raimund Renkert # Date 1334733288 0 # Node ID 894186b4c1d06a416396225ac192632bb96c0b93 # Parent 7d163c2c6e6d01ea546d261362441afc3b2d6132 Issue 494. Add manual points with text annotations to time charts. flys-artifacts/trunk@4255 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/ChangeLog Wed Apr 18 07:14:48 2012 +0000 @@ -1,3 +1,20 @@ +2012-04-18 Raimund Renkert + + Issue 494. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Create manual points with text annotations in time charts. + + * src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java: + Add manual points to the chart. + + * src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: + Added historical discharge to chart types. + + * doc/conf/artifacts/winfo.xml, + doc/conf/artifacts/manualpoints.xml: + Added manual points facet to output modes. + 2012-04-17 Sascha L. Teichmann * contrib/fixoverview2html.xsl: Render optional check boxes. diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/doc/conf/artifacts/manualpoints.xml --- a/flys-artifacts/doc/conf/artifacts/manualpoints.xml Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/doc/conf/artifacts/manualpoints.xml Wed Apr 18 07:14:48 2012 +0000 @@ -16,6 +16,7 @@ + diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/doc/conf/artifacts/winfo.xml --- a/flys-artifacts/doc/conf/artifacts/winfo.xml Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/doc/conf/artifacts/winfo.xml Wed Apr 18 07:14:48 2012 +0000 @@ -516,6 +516,7 @@ + diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java Wed Apr 18 07:14:48 2012 +0000 @@ -45,7 +45,8 @@ DIC("discharge_curve"), RC("reference_curve"), RCN("reference_curve_normalized"), - WD("wdifferences"); + WD("wdifferences"), + HD("historical_discharge"); private String chartTypeString; diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java Wed Apr 18 07:14:48 2012 +0000 @@ -153,6 +153,11 @@ theme, visible); } + else if (FacetTypes.IS.MANUALPOINTS(name)) { + doPoints (artifactFacet.getData(context), + artifactFacet, + theme, visible, YAXIS.Q.idx); + } // TODO ADD THE CASE FOR DISPLAYING W VALUES else { logger.warn("doOut(): unknown facet name: " + name); diff -r 7d163c2c6e6d -r 894186b4c1d0 flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java Tue Apr 17 13:55:50 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java Wed Apr 18 07:14:48 2012 +0000 @@ -2,28 +2,50 @@ import java.awt.Color; import java.awt.Font; +import java.awt.Paint; +import java.awt.BasicStroke; +import java.awt.Stroke; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Date; + +import org.json.JSONArray; +import org.json.JSONException; import org.apache.log4j.Logger; +import org.w3c.dom.Document; + import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.LegendItemCollection; import org.jfree.data.Range; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.general.Series; import org.jfree.data.xy.XYDataset; +import org.jfree.data.general.SeriesException; +import org.jfree.data.time.Day; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeries; + +import de.intevation.artifactdatabase.state.ArtifactAndFacet; +import de.intevation.artifactdatabase.state.Facet; import de.intevation.flys.jfree.Bounds; import de.intevation.flys.jfree.DoubleBounds; import de.intevation.flys.jfree.TimeBounds; +import de.intevation.flys.jfree.StyledTimeSeries; +import de.intevation.flys.jfree.FLYSAnnotation; +import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; +import de.intevation.flys.utils.ThemeAccess; /** * @author Ingo Weinzierl @@ -122,6 +144,9 @@ } // end of TimeseriesAxisDataset class + /** List of annotations to insert in plot. */ + protected List annotations; + private static final Logger logger = Logger.getLogger(TimeseriesChartGenerator.class); @@ -173,6 +198,8 @@ adaptZoom(plot); + addAnnotationsToRenderer(plot); + return chart; } @@ -450,5 +477,230 @@ xaxis.setLabelFont(labelFont); xaxis.setTickLabelFont(labelFont); } + + + /** + * Do Points out. + */ + protected void doPoints( + Object o, + ArtifactAndFacet aandf, + Document theme, + boolean visible, + int axisIndex + ) { + String seriesName = aandf.getFacetDescription(); + TimeSeries series = new StyledTimeSeries(seriesName, theme); + + // Add text annotations for single points. + List xy = new ArrayList(); + HashMap names = new HashMap(); + + try { + JSONArray points = new JSONArray((String) o); + for (int i = 0; i < points.length(); i++) { + JSONArray array = points.getJSONArray(i); + double x = array.getDouble(0); + double y = array.getDouble(1); + String name = array.getString(2); + boolean act = array.getBoolean(3); + if (!act) { + continue; + } + long l = (new Double(x)).longValue(); + Date date = new Date(l); + Day day = new Day(date); + series.add(day, y, false); + names.put(day, name); + } + } + catch(JSONException e){ + logger.error("Could not decode json."); + } + + TimeSeriesCollection tsc = new TimeSeriesCollection(); + tsc.addSeries(series); + // Add Annotations. + for (int i = 0; i < series.getItemCount(); i++) { + double x = tsc.getXValue(0, i); + double y = tsc.getYValue(0, i); + xy.add(new CollisionFreeXYTextAnnotation( + names.get(series.getTimePeriod(i)), x, y)); + } + FLYSAnnotation annotations = + new FLYSAnnotation(null, null, null, theme); + annotations.setTextAnnotations(xy); + + // Do not generate second legend entry. (null was passed for the aand before). + doAnnotations(annotations, aandf, theme, visible); + + addAxisDataset(tsc, axisIndex, visible); + } + + /** + * Register annotations like MainValues for later plotting + * + * @param o list of annotations (data of facet). + * @param facet The facet. This facet does NOT support any data objects. Use + * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports + * data. + * @param theme Theme document for given annotations. + * @param visible The visibility of the annotations. + */ + protected void doAnnotations( + FLYSAnnotation annotations, + ArtifactAndFacet aandf, + Document theme, + boolean visible + ){ + // Running into trouble here. + logger.debug("doAnnotations"); + + // Add all annotations to our annotation pool. + annotations.setTheme(theme); + if (aandf != null) { + Facet facet = aandf.getFacet(); + annotations.setLabel(aandf.getFacetDescription()); + } + else { + logger.debug( + "Art/Facet for Annotations is null. " + + "This should never happen!"); + } + + addAnnotations(annotations, visible); + } + + + + /** + * Adds annotations to list (if visible is true). + */ + public void addAnnotations(FLYSAnnotation annotation, boolean visible) { + if (!visible) { + return; + } + + if (annotations == null) { + annotations = new ArrayList(); + } + + annotations.add(annotation); + } + + + /** Add annotations (Sticky, Text and hyk zones). */ + public void addAnnotationsToRenderer(XYPlot plot) { + logger.debug("XYChartGenerator.addAnnotationsToRenderer"); + + if (annotations == null) { + logger.debug("XYChartGenerator.addBoxAnnotations: no annotations."); + return; + } + + // Paints for the boxes/lines. + Stroke basicStroke = new BasicStroke(1.0f); + + Paint linePaint = new Color(255, 0,0,60); + Paint fillPaint = new Color(0, 255,0,60); + Paint tranPaint = new Color(0, 0,0, 0); + + // OPTMIMIZE: Pre-calculate positions + Area area = new Area( + plot.getDomainAxis(0).getRange(), + plot.getRangeAxis().getRange()); + + // Walk over all Annotation sets. + for (FLYSAnnotation fa: annotations) { + + // Access text styling, if any. + Document theme = fa.getTheme(); + ThemeAccess.TextStyle textStyle = null; + ThemeAccess.LineStyle lineStyle = null; + + // Get Themeing information and add legend item. + if (theme != null) { + ThemeAccess themeAccess = new ThemeAccess(theme); + textStyle = themeAccess.parseTextStyle(); + lineStyle = themeAccess.parseLineStyle(); + if (fa.getLabel() != null) { + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + lic.add(createLegendItem(theme, fa.getLabel())); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } + else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // Other Text Annotations (e.g. labels of manual points). + for (XYTextAnnotation ta: fa.getTextAnnotations()) { + // Style the text. + if (textStyle != null) { + textStyle.apply(ta); + } + ta.setY(area.above(0.05d, ta.getY())); + plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); + } + } + } + + + /** Two Ranges that span a rectangular area. */ + public static class Area { + protected Range xRange; + protected Range yRange; + + public Area(Range rangeX, Range rangeY) { + this.xRange = rangeX; + this.yRange = rangeY; + } + + public Area(ValueAxis axisX, ValueAxis axisY) { + this.xRange = axisX.getRange(); + this.yRange = axisY.getRange(); + } + + public double ofLeft(double percent) { + return xRange.getLowerBound() + + xRange.getLength() * percent; + } + + public double ofRight(double percent) { + return xRange.getUpperBound() + - xRange.getLength() * percent; + } + + public double ofGround(double percent) { + return yRange.getLowerBound() + + yRange.getLength() * percent; + } + + public double atTop() { + return yRange.getUpperBound(); + } + + public double atGround() { + return yRange.getLowerBound(); + } + + public double atRight() { + return xRange.getUpperBound(); + } + + public double atLeft() { + return xRange.getLowerBound(); + } + + public double above(double percent, double base) { + return base + yRange.getLength() * percent; + } + } + } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :