ingo@2233: package de.intevation.flys.exports; ingo@2233: raimund@2633: import de.intevation.artifactdatabase.state.ArtifactAndFacet; raimund@2633: import de.intevation.artifactdatabase.state.Facet; ingo@2233: ingo@2400: import de.intevation.flys.jfree.Bounds; sascha@3139: import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; ingo@2400: import de.intevation.flys.jfree.DoubleBounds; sascha@3139: import de.intevation.flys.jfree.FLYSAnnotation; raimund@2633: import de.intevation.flys.jfree.StyledTimeSeries; sascha@3139: import de.intevation.flys.jfree.TimeBounds; ingo@2400: ingo@3227: import de.intevation.flys.themes.ThemeAccess; ingo@2233: christian@3212: import de.intevation.flys.artifacts.model.HYKFactory; christian@3212: sascha@3139: import java.awt.BasicStroke; sascha@3139: import java.awt.Color; sascha@3139: import java.awt.Font; sascha@3139: import java.awt.Paint; sascha@3139: import java.awt.Stroke; sascha@3139: sascha@3139: import java.util.ArrayList; sascha@3139: import java.util.Date; sascha@3139: import java.util.HashMap; sascha@3139: import java.util.List; sascha@3139: import java.util.Map; sascha@3139: sascha@3139: import org.apache.log4j.Logger; sascha@3139: sascha@3139: import org.jfree.chart.ChartFactory; sascha@3139: import org.jfree.chart.JFreeChart; sascha@3139: import org.jfree.chart.LegendItemCollection; sascha@3139: christian@3212: import org.jfree.chart.annotations.XYBoxAnnotation; sascha@3139: import org.jfree.chart.annotations.XYTextAnnotation; sascha@3139: sascha@3139: import org.jfree.chart.axis.ValueAxis; sascha@3139: sascha@3139: import org.jfree.chart.plot.Marker; sascha@3139: import org.jfree.chart.plot.XYPlot; sascha@3139: sascha@3139: import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; sascha@3139: sascha@3139: import org.jfree.data.Range; sascha@3139: sascha@3139: import org.jfree.data.general.Series; sascha@3139: sascha@3139: import org.jfree.data.time.Day; sascha@3139: import org.jfree.data.time.TimeSeries; sascha@3139: import org.jfree.data.time.TimeSeriesCollection; sascha@3139: sascha@3139: import org.jfree.data.xy.XYDataset; sascha@3139: sascha@3139: import org.jfree.ui.Layer; sascha@3139: sascha@3139: import org.json.JSONArray; sascha@3139: import org.json.JSONException; sascha@3139: sascha@3139: import org.w3c.dom.Document; sascha@3139: ingo@2233: /** ingo@2233: * @author Ingo Weinzierl ingo@2233: */ ingo@2233: public abstract class TimeseriesChartGenerator extends ChartGenerator { ingo@2233: ingo@2238: ingo@2238: /** ingo@2238: * Inner class TimeseriesAxisDataset stores TimeSeriesCollection. ingo@2238: */ ingo@2238: public class TimeseriesAxisDataset implements AxisDataset { ingo@2238: ingo@2238: protected int axisSymbol; ingo@2238: ingo@2238: protected List datasets; ingo@2238: ingo@2238: protected Range range; ingo@2238: ingo@2238: protected int plotAxisIndex; ingo@2238: ingo@2238: public TimeseriesAxisDataset(int axisSymbol) { ingo@2238: this.axisSymbol = axisSymbol; ingo@2238: this.datasets = new ArrayList(); ingo@2238: } ingo@2238: ingo@2238: ingo@2238: @Override ingo@2238: public void addDataset(XYDataset dataset) { ingo@2238: if (!(dataset instanceof TimeSeriesCollection)) { ingo@2238: logger.warn("Skip non TimeSeriesCollection dataset."); ingo@2238: return; ingo@2238: } ingo@2238: ingo@2238: TimeSeriesCollection tsc = (TimeSeriesCollection) dataset; ingo@2238: ingo@2238: datasets.add(tsc); ingo@2238: mergeRanges(tsc); ingo@2238: } ingo@2238: ingo@2238: ingo@2238: @Override ingo@2242: public XYDataset[] getDatasets() { ingo@2242: return (XYDataset[]) ingo@2242: datasets.toArray(new XYDataset[datasets.size()]); ingo@2242: } ingo@2242: ingo@2242: ingo@2242: @Override ingo@2238: public boolean isEmpty() { ingo@2238: return datasets.isEmpty(); ingo@2238: } ingo@2238: ingo@2238: ingo@2242: @Override ingo@2242: public void setRange(Range range) { ingo@2242: this.range = range; ingo@2242: } ingo@2242: ingo@2242: ingo@2242: @Override ingo@2242: public Range getRange() { ingo@2242: return range; ingo@2242: } ingo@2242: ingo@2242: ingo@2242: @Override ingo@2242: public void setPlotAxisIndex(int plotAxisIndex) { ingo@2242: this.plotAxisIndex = plotAxisIndex; ingo@2242: } ingo@2242: ingo@2242: ingo@2242: @Override ingo@2242: public int getPlotAxisIndex() { ingo@2242: return plotAxisIndex; ingo@2242: } ingo@2242: ingo@2242: ingo@2242: @Override ingo@2242: public boolean isArea(XYDataset dataset) { ingo@2242: logger.warn("This AxisDataset doesn't support Areas yet!"); ingo@2242: return false; ingo@2242: } ingo@2242: ingo@2242: ingo@2238: protected void mergeRanges(TimeSeriesCollection dataset) { ingo@2238: logger.debug("Range after merging: " + range); ingo@2238: ingo@2400: Bounds[] xyRanges = ChartHelper.getBounds(dataset); ingo@2400: ingo@2400: // TODO COMBINE BOUNDS! ingo@2238: ingo@2238: logger.debug("Range after merging: " + range); ingo@2238: } ingo@2238: ingo@2238: } // end of TimeseriesAxisDataset class ingo@2238: ingo@2238: raimund@2633: /** List of annotations to insert in plot. */ raimund@2633: protected List annotations; raimund@2633: raimund@3130: protected List domainMarker; raimund@3130: raimund@3130: protected List valueMarker; raimund@3130: raimund@3134: protected Map attributes; raimund@3134: raimund@3130: protected boolean domainZeroLineVisible; ingo@2238: ingo@2233: private static final Logger logger = ingo@2233: Logger.getLogger(TimeseriesChartGenerator.class); ingo@2233: ingo@2233: ingo@2400: public static final int AXIS_SPACE = 5; ingo@2238: ingo@2400: ingo@2587: protected Map xBounds; ingo@2400: ingo@2587: protected Map yBounds; ingo@2242: ingo@2238: ingo@2238: ingo@2238: /** ingo@2238: * The default constructor that initializes internal datastructures. ingo@2238: */ ingo@2238: public TimeseriesChartGenerator() { ingo@2238: super(); ingo@2238: ingo@2587: xBounds = new HashMap(); ingo@2587: yBounds = new HashMap(); raimund@3130: domainMarker = new ArrayList(); raimund@3130: valueMarker = new ArrayList(); raimund@3134: attributes = new HashMap(); ingo@2238: } ingo@2238: ingo@2233: ingo@2233: ingo@2233: @Override ingo@2234: public JFreeChart generateChart() { ingo@2233: logger.info("Generate Timeseries Chart."); ingo@2233: ingo@2238: JFreeChart chart = ChartFactory.createTimeSeriesChart( ingo@2238: getChartTitle(), ingo@2238: getXAxisLabel(), ingo@2238: getYAxisLabel(0), ingo@2238: null, ingo@2554: isLegendVisible(), ingo@2238: false, ingo@2238: false); ingo@2238: ingo@2238: XYPlot plot = (XYPlot) chart.getPlot(); ingo@2238: ingo@2238: chart.setBackgroundPaint(Color.WHITE); ingo@2238: plot.setBackgroundPaint(Color.WHITE); ingo@2238: ingo@2238: addSubtitles(chart); ingo@2553: adjustPlot(plot); ingo@2238: addDatasets(plot); ingo@2586: adjustAxes(plot); raimund@3130: addDomainAxisMarker(plot); raimund@3130: addValueAxisMarker(plot); ingo@2400: adaptZoom(plot); ingo@2400: raimund@3134: applySeriesAttributes(plot); raimund@2633: addAnnotationsToRenderer(plot); felix@3185: aggregateLegendEntries(plot); ingo@2238: return chart; ingo@2238: } ingo@2238: ingo@2238: ingo@2242: @Override ingo@2242: protected Series getSeriesOf(XYDataset dataset, int idx) { ingo@2242: return ((TimeSeriesCollection) dataset).getSeries(idx); ingo@2242: } ingo@2242: ingo@2242: ingo@2238: /** ingo@2238: * This method creates new instances of TimeseriesAxisDataset. ingo@2238: * ingo@2238: * @param idx The symbol for the new TimeseriesAxisDataset. ingo@2238: */ ingo@2238: @Override ingo@2238: protected AxisDataset createAxisDataset(int idx) { ingo@2238: logger.debug("Create a new AxisDataset for index: " + idx); ingo@2238: return new TimeseriesAxisDataset(idx); ingo@2238: } ingo@2238: ingo@2238: ingo@2400: @Override ingo@2587: protected void combineXBounds(Bounds bounds, int index) { ingo@2400: if (bounds != null) { ingo@2587: Bounds old = getXBounds(index); ingo@2238: ingo@2238: if (old != null) { ingo@2400: bounds = bounds.combine(old); ingo@2238: } ingo@2238: ingo@2400: setXBounds(index, bounds); ingo@2238: } ingo@2238: } ingo@2261: ingo@2261: ingo@2587: @Override ingo@2587: protected void combineYBounds(Bounds bounds, int index) { ingo@2400: if (bounds != null) { ingo@2400: Bounds old = getYBounds(index); ingo@2400: ingo@2400: if (old != null) { ingo@2400: bounds = bounds.combine(old); ingo@2400: } ingo@2400: ingo@2400: setYBounds(index, bounds); ingo@2400: } ingo@2400: } ingo@2400: ingo@2400: ingo@2400: // TODO REPLACE THIS METHOD WITH getBoundsForAxis(index) ingo@2400: @Override ingo@2400: public Range[] getRangesForAxis(int index) { ingo@2400: // TODO ingo@2400: Bounds[] bounds = getBoundsForAxis(index); ingo@2400: ingo@2400: return new Range[] { ingo@2400: new Range( ingo@2400: bounds[0].getLower().doubleValue(), ingo@2400: bounds[0].getUpper().doubleValue()), ingo@2400: new Range( ingo@2400: bounds[1].getLower().doubleValue(), ingo@2400: bounds[1].getUpper().doubleValue()) ingo@2400: }; ingo@2400: } ingo@2400: ingo@2400: ingo@2261: @Override ingo@2400: public Bounds getXBounds(int axis) { ingo@2587: return xBounds.get(axis); ingo@2400: } ingo@2261: ingo@2400: ingo@2400: @Override ingo@2400: protected void setXBounds(int axis, Bounds bounds) { ingo@2587: xBounds.put(axis, bounds); ingo@2400: } ingo@2400: ingo@2400: ingo@2400: @Override ingo@2400: public Bounds getYBounds(int axis) { ingo@2587: return yBounds.get(axis); ingo@2400: } ingo@2400: ingo@2400: ingo@2400: @Override ingo@2400: protected void setYBounds(int axis, Bounds bounds) { ingo@2587: if (bounds != null) { ingo@2587: yBounds.put(axis, bounds); ingo@2587: } ingo@2400: } ingo@2400: ingo@2400: ingo@2400: public Bounds[] getBoundsForAxis(int index) { ingo@2400: logger.debug("Return x and y bounds for axis at: " + index); ingo@2400: ingo@2400: Bounds rx = getXBounds(Integer.valueOf(index)); ingo@2400: Bounds ry = getYBounds(Integer.valueOf(index)); ingo@2261: ingo@2261: if (rx == null) { ingo@2261: logger.warn("Range for x axis not set." + ingo@2261: " Using default values: 0 - 1."); ingo@2400: rx = new TimeBounds(0l, 1l); ingo@2261: } ingo@2261: ingo@2400: if (ry == null) { ingo@2400: logger.warn("Range for y axis not set." + ingo@2400: " Using default values: 0 - 1."); ingo@2400: ry = new DoubleBounds(0l, 1l); ingo@2400: } ingo@2261: ingo@2400: logger.debug("X Bounds at index " + index + " is: " + rx); ingo@2400: logger.debug("Y Bounds at index " + index + " is: " + ry); ingo@2400: ingo@2400: return new Bounds[] {rx, ry}; ingo@2400: } ingo@2400: ingo@2400: ingo@2400: public Bounds getDomainAxisRange() { ingo@2400: String[] ranges = getDomainAxisRangeFromRequest(); ingo@2400: ingo@2400: if (ranges == null || ranges.length < 2) { ingo@2400: logger.debug("No zoom range for domain axis specified."); ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: if (ranges[0] == null || ranges[1] == null) { ingo@2400: logger.warn("Invalid ranges for domain axis specified!"); ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: try { ingo@2400: double lower = Double.parseDouble(ranges[0]); ingo@2400: double upper = Double.parseDouble(ranges[1]); ingo@2400: ingo@2400: return new DoubleBounds(lower, upper); ingo@2400: } ingo@2400: catch (NumberFormatException nfe) { ingo@2400: logger.warn("Invalid ranges for domain axis specified: " + nfe); ingo@2400: } ingo@2400: ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: ingo@2400: public Bounds getValueAxisRange() { ingo@2400: String[] ranges = getValueAxisRangeFromRequest(); ingo@2400: ingo@2400: if (ranges == null || ranges.length < 2) { ingo@2400: logger.debug("No zoom range for domain axis specified."); ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: if (ranges[0] == null || ranges[1] == null) { ingo@2400: logger.warn("Invalid ranges for domain axis specified!"); ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: try { ingo@2400: double lower = Double.parseDouble(ranges[0]); ingo@2400: double upper = Double.parseDouble(ranges[1]); ingo@2400: ingo@2400: return new DoubleBounds(lower, upper); ingo@2400: } ingo@2400: catch (NumberFormatException nfe) { ingo@2400: logger.warn("Invalid ranges for domain axis specified: " + nfe); ingo@2400: } ingo@2400: ingo@2400: return null; ingo@2400: } ingo@2400: ingo@2400: ingo@2400: protected void adaptZoom(XYPlot plot) { ingo@2400: logger.debug("Adapt zoom of Timeseries chart."); ingo@2400: ingo@2587: zoomX(plot, plot.getDomainAxis(), getXBounds(0), getDomainAxisRange()); ingo@2400: ingo@2400: Bounds valueAxisBounds = getValueAxisRange(); ingo@2400: ingo@2400: for (int j = 0, n = plot.getRangeAxisCount(); j < n; j++) { ingo@2400: zoomY( ingo@2400: plot, ingo@2400: plot.getRangeAxis(j), ingo@2400: getYBounds(j), ingo@2400: valueAxisBounds); ingo@2400: } ingo@2400: } ingo@2400: ingo@2400: ingo@2400: protected void zoomX( ingo@2400: XYPlot plot, ingo@2400: ValueAxis axis, ingo@2400: Bounds total, ingo@2400: Bounds user ingo@2400: ) { ingo@2400: if (logger.isDebugEnabled()) { ingo@2400: logger.debug("== Zoom X axis =="); ingo@2400: logger.debug(" Total axis range : " + total); ingo@2400: logger.debug(" User defined range: " + user); ingo@2400: } ingo@2400: ingo@2400: if (user != null) { ingo@2400: long min = total.getLower().longValue(); ingo@2400: long max = total.getUpper().longValue(); ingo@2400: long diff = max > min ? max - min : min - max; ingo@2400: ingo@2400: long newMin = (long) Math.round(min + user.getLower().doubleValue() * diff); ingo@2400: long newMax = (long) Math.round(min + user.getUpper().doubleValue() * diff); ingo@2400: ingo@2400: TimeBounds newBounds = new TimeBounds(newMin, newMax); ingo@2400: ingo@2400: logger.debug(" Zoom axis to: " + newBounds); ingo@2400: ingo@2400: newBounds.applyBounds(axis, AXIS_SPACE); ingo@2400: } ingo@2400: else { ingo@2400: logger.debug("No user specified zoom values found!"); sascha@3140: if (total != null && axis != null) { sascha@3140: total.applyBounds(axis, AXIS_SPACE); sascha@3140: } ingo@2400: } ingo@2400: } ingo@2400: ingo@2400: ingo@2400: protected void zoomY( ingo@2400: XYPlot plot, ingo@2400: ValueAxis axis, ingo@2400: Bounds total, ingo@2400: Bounds user ingo@2400: ) { ingo@2400: if (logger.isDebugEnabled()) { ingo@2400: logger.debug("== Zoom Y axis =="); ingo@2400: logger.debug(" Total axis range : " + total); ingo@2400: logger.debug(" User defined range: " + user); ingo@2400: } ingo@2400: ingo@2400: if (user != null) { ingo@2400: double min = total.getLower().doubleValue(); ingo@2400: double max = total.getUpper().doubleValue(); ingo@2400: double diff = max > min ? max - min : min - max; ingo@2400: ingo@2400: double newMin = min + user.getLower().doubleValue() * diff; ingo@2400: double newMax = min + user.getUpper().doubleValue() * diff; ingo@2400: ingo@2400: DoubleBounds newBounds = new DoubleBounds(newMin, newMax); ingo@2400: ingo@2400: logger.debug(" Zoom axis to: " + newBounds); ingo@2400: ingo@2400: newBounds.applyBounds(axis, AXIS_SPACE); ingo@2400: } ingo@2400: else { ingo@2400: logger.debug("No user specified zoom values found!"); sascha@3140: if (total != null && axis != null) { sascha@3140: total.applyBounds(axis, AXIS_SPACE); sascha@3140: } ingo@2400: } ingo@2261: } ingo@2586: ingo@2586: ingo@2586: /** ingo@2586: * Adjusts the axes of a plot. This method sets the labelFont of the ingo@2586: * X axis. ingo@2586: * ingo@2586: * @param plot The XYPlot of the chart. ingo@2586: */ ingo@2586: protected void adjustAxes(XYPlot plot) { ingo@2586: ValueAxis xaxis = plot.getDomainAxis(); ingo@2586: ingo@2586: ChartSettings chartSettings = getChartSettings(); ingo@2586: if (chartSettings == null) { ingo@2586: return; ingo@2586: } ingo@2586: ingo@2586: Font labelFont = new Font( ingo@2586: DEFAULT_FONT_NAME, ingo@2586: Font.BOLD, ingo@2586: getXAxisLabelFontSize()); ingo@2586: ingo@2586: xaxis.setLabelFont(labelFont); ingo@2590: xaxis.setTickLabelFont(labelFont); ingo@2586: } raimund@2633: raimund@2633: raimund@2633: /** raimund@2633: * Do Points out. raimund@2633: */ raimund@2633: protected void doPoints( raimund@2633: Object o, raimund@2633: ArtifactAndFacet aandf, raimund@2633: Document theme, raimund@2633: boolean visible, raimund@2633: int axisIndex raimund@2633: ) { raimund@2633: String seriesName = aandf.getFacetDescription(); raimund@2633: TimeSeries series = new StyledTimeSeries(seriesName, theme); raimund@2633: raimund@2633: // Add text annotations for single points. raimund@2633: List xy = new ArrayList(); raimund@2633: HashMap names = new HashMap(); raimund@2633: raimund@2633: try { raimund@2633: JSONArray points = new JSONArray((String) o); sascha@3087: for (int i = 0, P = points.length(); i < P; i++) { raimund@2633: JSONArray array = points.getJSONArray(i); raimund@2633: double x = array.getDouble(0); raimund@2633: double y = array.getDouble(1); raimund@2633: String name = array.getString(2); raimund@2633: boolean act = array.getBoolean(3); raimund@2633: if (!act) { raimund@2633: continue; raimund@2633: } raimund@2633: long l = (new Double(x)).longValue(); raimund@2633: Date date = new Date(l); raimund@2633: Day day = new Day(date); raimund@2633: series.add(day, y, false); raimund@2633: names.put(day, name); raimund@2633: } raimund@2633: } raimund@2633: catch(JSONException e){ raimund@2633: logger.error("Could not decode json."); raimund@2633: } raimund@2633: raimund@2633: TimeSeriesCollection tsc = new TimeSeriesCollection(); raimund@2633: tsc.addSeries(series); raimund@2633: // Add Annotations. sascha@3087: for (int i = 0, S = series.getItemCount(); i < S; i++) { raimund@2633: double x = tsc.getXValue(0, i); raimund@2633: double y = tsc.getYValue(0, i); raimund@2633: xy.add(new CollisionFreeXYTextAnnotation( raimund@2633: names.get(series.getTimePeriod(i)), x, y)); raimund@2633: } raimund@2633: FLYSAnnotation annotations = raimund@2633: new FLYSAnnotation(null, null, null, theme); raimund@2633: annotations.setTextAnnotations(xy); raimund@2633: raimund@2633: // Do not generate second legend entry. (null was passed for the aand before). raimund@2634: doAnnotations(annotations, null, theme, visible); raimund@2633: raimund@2633: addAxisDataset(tsc, axisIndex, visible); raimund@2633: } raimund@2633: raimund@2633: /** raimund@2633: * Register annotations like MainValues for later plotting raimund@2633: * raimund@2633: * @param o list of annotations (data of facet). raimund@2633: * @param facet The facet. This facet does NOT support any data objects. Use raimund@2633: * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports raimund@2633: * data. raimund@2633: * @param theme Theme document for given annotations. raimund@2633: * @param visible The visibility of the annotations. raimund@2633: */ raimund@2633: protected void doAnnotations( raimund@2633: FLYSAnnotation annotations, raimund@2633: ArtifactAndFacet aandf, raimund@2633: Document theme, raimund@2633: boolean visible raimund@2633: ){ raimund@2633: // Running into trouble here. raimund@2633: logger.debug("doAnnotations"); raimund@2633: raimund@2633: // Add all annotations to our annotation pool. raimund@2633: annotations.setTheme(theme); raimund@2633: if (aandf != null) { raimund@2633: Facet facet = aandf.getFacet(); raimund@2633: annotations.setLabel(aandf.getFacetDescription()); raimund@2633: } raimund@2633: else { raimund@2633: logger.debug( raimund@2633: "Art/Facet for Annotations is null. " + raimund@2633: "This should never happen!"); raimund@2633: } raimund@2633: raimund@2633: addAnnotations(annotations, visible); raimund@2633: } raimund@2633: raimund@2633: raimund@2633: raimund@2633: /** raimund@2633: * Adds annotations to list (if visible is true). raimund@2633: */ raimund@2633: public void addAnnotations(FLYSAnnotation annotation, boolean visible) { raimund@2633: if (!visible) { raimund@2633: return; raimund@2633: } raimund@2633: raimund@2633: if (annotations == null) { raimund@2633: annotations = new ArrayList(); raimund@2633: } raimund@2633: raimund@2633: annotations.add(annotation); raimund@2633: } raimund@2633: raimund@2633: raimund@2633: /** Add annotations (Sticky, Text and hyk zones). */ christian@3212: /* public void addAnnotationsToRenderer(XYPlot plot) { christian@3212: logger.debug("addAnnotationsToRenderer"); raimund@2633: raimund@2633: if (annotations == null) { christian@3212: logger.debug("addAnnotationsToRenderer: no annotations."); raimund@2633: return; raimund@2633: } raimund@2633: raimund@2633: // Paints for the boxes/lines. raimund@2633: Stroke basicStroke = new BasicStroke(1.0f); raimund@2633: raimund@2633: Paint linePaint = new Color(255, 0,0,60); raimund@2633: Paint fillPaint = new Color(0, 255,0,60); raimund@2633: Paint tranPaint = new Color(0, 0,0, 0); raimund@2633: raimund@2633: // OPTMIMIZE: Pre-calculate positions raimund@2633: Area area = new Area( raimund@2633: plot.getDomainAxis(0).getRange(), raimund@2633: plot.getRangeAxis().getRange()); raimund@2633: raimund@2633: // Walk over all Annotation sets. raimund@2633: for (FLYSAnnotation fa: annotations) { raimund@2633: raimund@2633: // Access text styling, if any. raimund@2633: Document theme = fa.getTheme(); raimund@2633: ThemeAccess.TextStyle textStyle = null; raimund@2633: ThemeAccess.LineStyle lineStyle = null; raimund@2633: raimund@2633: // Get Themeing information and add legend item. raimund@2633: if (theme != null) { raimund@2633: ThemeAccess themeAccess = new ThemeAccess(theme); raimund@2633: textStyle = themeAccess.parseTextStyle(); raimund@2633: lineStyle = themeAccess.parseLineStyle(); raimund@2633: if (fa.getLabel() != null) { raimund@2633: LegendItemCollection lic = new LegendItemCollection(); raimund@2633: LegendItemCollection old = plot.getFixedLegendItems(); raimund@2633: lic.add(createLegendItem(theme, fa.getLabel())); raimund@2633: // (Re-)Add prior legend entries. raimund@2633: if (old != null) { raimund@2633: old.addAll(lic); raimund@2633: } raimund@2633: else { raimund@2633: old = lic; raimund@2633: } raimund@2633: plot.setFixedLegendItems(old); raimund@2633: } raimund@2633: } raimund@2633: raimund@2633: // Other Text Annotations (e.g. labels of manual points). raimund@2633: for (XYTextAnnotation ta: fa.getTextAnnotations()) { raimund@2633: // Style the text. raimund@2633: if (textStyle != null) { raimund@2633: textStyle.apply(ta); raimund@2633: } raimund@2633: ta.setY(area.above(0.05d, ta.getY())); raimund@2633: plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); raimund@2633: } raimund@2633: } christian@3212: }*/ christian@3212: christian@3212: /** christian@3212: * Add the annotations (Sticky, Text and hyk zones) stored christian@3212: * in the annotations field. christian@3212: */ christian@3212: public void addAnnotationsToRenderer(XYPlot plot) { christian@3212: logger.debug("addAnnotationsToRenderer"); christian@3212: christian@3212: if (annotations == null) { christian@3212: logger.debug("addAnnotationsToRenderer: no annotations."); christian@3212: return; christian@3212: } christian@3212: christian@3212: // Paints for the boxes/lines. christian@3212: Stroke basicStroke = new BasicStroke(1.0f); christian@3212: christian@3212: Paint linePaint = new Color(255, 0,0,60); christian@3212: Paint fillPaint = new Color(0, 255,0,60); christian@3212: Paint tranPaint = new Color(0, 0,0, 0); christian@3212: christian@3212: // OPTMIMIZE: Pre-calculate positions christian@3212: Area area = new Area( christian@3212: plot.getDomainAxis(0).getRange(), christian@3212: plot.getRangeAxis().getRange()); christian@3212: christian@3212: // Walk over all Annotation sets. christian@3212: for (FLYSAnnotation fa: annotations) { christian@3212: christian@3212: // Access text styling, if any. christian@3212: Document theme = fa.getTheme(); christian@3212: ThemeAccess.TextStyle textStyle = null; christian@3212: ThemeAccess.LineStyle lineStyle = null; christian@3212: christian@3212: // Get Themeing information and add legend item. christian@3212: if (theme != null) { christian@3212: ThemeAccess themeAccess = new ThemeAccess(theme); christian@3212: textStyle = themeAccess.parseTextStyle(); christian@3212: lineStyle = themeAccess.parseLineStyle(); christian@3212: if (fa.getLabel() != null) { christian@3212: LegendItemCollection lic = new LegendItemCollection(); christian@3212: LegendItemCollection old = plot.getFixedLegendItems(); christian@3212: lic.add(createLegendItem(theme, fa.getLabel())); christian@3212: // (Re-)Add prior legend entries. christian@3212: if (old != null) { christian@3212: old.addAll(lic); christian@3212: } christian@3212: else { christian@3212: old = lic; christian@3212: } christian@3212: plot.setFixedLegendItems(old); christian@3212: } christian@3212: } christian@3212: christian@3212: // The 'Sticky' Annotations (at axis, with line and text). christian@3212: /* for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) { christian@3212: addStickyAnnotation( christian@3212: sta, plot, area, lineStyle, textStyle, theme); christian@3212: }*/ christian@3212: christian@3212: // Other Text Annotations (e.g. labels of manual points). christian@3212: for (XYTextAnnotation ta: fa.getTextAnnotations()) { christian@3212: // Style the text. christian@3212: if (textStyle != null) { christian@3212: textStyle.apply(ta); christian@3212: } christian@3212: ta.setY(area.above(0.05d, ta.getY())); christian@3212: plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); christian@3212: } christian@3212: christian@3212: // Hyks. christian@3212: for (HYKFactory.Zone zone: fa.getBoxes()) { christian@3212: // For each zone, create a box to fill with color, a box to draw christian@3212: // the lines and a text to display the type. christian@3212: fillPaint = colorForHYKZone(zone.getName()); christian@3212: christian@3212: XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(), christian@3212: zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint); christian@3212: XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(), christian@3212: zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint); christian@3212: christian@3212: XYTextAnnotation tex = new XYTextAnnotation(zone.getName(), christian@3212: zone.getFrom() + (zone.getTo() - zone.getFrom()) / 1.0d, christian@3212: area.ofGround(0.015f)); christian@3212: if (textStyle != null) { christian@3212: textStyle.apply(tex); christian@3212: } christian@3212: christian@3212: plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND); christian@3212: plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND); christian@3212: plot.getRenderer().addAnnotation(tex, org.jfree.ui.Layer.BACKGROUND); christian@3212: } christian@3212: } christian@3212: } christian@3212: christian@3212: /** Get color for hyk zones by their type (which is the name). */ christian@3212: public Paint colorForHYKZone(String zoneName) { christian@3212: if (zoneName.startsWith("R")) { christian@3212: // Brownish. christian@3212: return new Color(153, 60, 0); christian@3212: } christian@3212: else if (zoneName.startsWith("V")) { christian@3212: // Greenish. christian@3212: return new Color(0, 255, 0); christian@3212: } christian@3212: else if (zoneName.startsWith("B")) { christian@3212: // Grayish. christian@3212: return new Color(128, 128, 128); christian@3212: } christian@3212: else if (zoneName.startsWith("H")) { christian@3212: // Blueish. christian@3212: return new Color(0, 0, 255); christian@3212: } christian@3212: else { christian@3212: // Default. christian@3212: logger.debug("Unknown zone type found."); christian@3212: return new Color(255, 0, 0); christian@3212: } raimund@2633: } raimund@2633: raimund@3130: public void addDomainAxisMarker(XYPlot plot) { raimund@3130: logger.debug("domainmarkers: " + domainMarker.size()); raimund@3130: for (Marker marker: domainMarker) { raimund@3130: logger.debug("adding domain marker"); raimund@3130: plot.addDomainMarker(marker, Layer.BACKGROUND); raimund@3130: } raimund@3130: domainMarker.clear(); raimund@3130: } raimund@3130: raimund@3130: public void addValueAxisMarker(XYPlot plot) { raimund@3130: for (Marker marker: valueMarker) { raimund@3130: logger.debug("adding value marker.."); raimund@3130: plot.addRangeMarker(marker, Layer.BACKGROUND); raimund@3130: } raimund@3130: valueMarker.clear(); raimund@3130: } raimund@2633: raimund@3134: public void addAttribute(String seriesKey, String name) { raimund@3134: attributes.put(seriesKey, name); raimund@3134: } raimund@3134: raimund@3134: protected void applySeriesAttributes(XYPlot plot) { raimund@3134: int count = plot.getDatasetCount(); raimund@3134: for (int i = 0; i < count; i++) { raimund@3134: XYDataset data = plot.getDataset(i); sascha@3140: if (data == null) { sascha@3140: continue; sascha@3140: } raimund@3134: int seriesCount = data.getSeriesCount(); raimund@3134: for (int j = 0; j < seriesCount; j++) { raimund@3134: StyledTimeSeries series = raimund@3134: (StyledTimeSeries)getSeriesOf(data, j); raimund@3134: String key = series.getKey().toString(); raimund@3134: if (attributes.containsKey(key)) { raimund@3134: if (attributes.get(key).equals("interpolate")) { raimund@3134: XYLineAndShapeRenderer renderer = raimund@3134: series.getStyle().getRenderer(); raimund@3134: renderer.setSeriesPaint( raimund@3134: j, raimund@3134: renderer.getSeriesFillPaint(j)); raimund@3134: renderer.setSeriesShapesFilled(j, false); raimund@3168: } raimund@3168: } raimund@3168: if (attributes.containsKey(key)) { raimund@3168: if(attributes.get(key).equals("outline")) { raimund@3168: XYLineAndShapeRenderer renderer = raimund@3168: series.getStyle().getRenderer(); raimund@3168: renderer.setSeriesPaint( raimund@3168: j, raimund@3168: renderer.getSeriesFillPaint(j)); raimund@3134: renderer.setDrawOutlines(true); raimund@3134: } raimund@3134: } raimund@3134: } raimund@3134: } raimund@3134: } raimund@3134: raimund@2633: /** Two Ranges that span a rectangular area. */ raimund@2633: public static class Area { raimund@2633: protected Range xRange; raimund@2633: protected Range yRange; raimund@2633: raimund@2633: public Area(Range rangeX, Range rangeY) { raimund@2633: this.xRange = rangeX; raimund@2633: this.yRange = rangeY; raimund@2633: } raimund@2633: raimund@2633: public Area(ValueAxis axisX, ValueAxis axisY) { raimund@2633: this.xRange = axisX.getRange(); raimund@2633: this.yRange = axisY.getRange(); raimund@2633: } raimund@2633: raimund@2633: public double ofLeft(double percent) { raimund@2633: return xRange.getLowerBound() raimund@2633: + xRange.getLength() * percent; raimund@2633: } raimund@2633: raimund@2633: public double ofRight(double percent) { raimund@2633: return xRange.getUpperBound() raimund@2633: - xRange.getLength() * percent; raimund@2633: } raimund@2633: raimund@2633: public double ofGround(double percent) { raimund@2633: return yRange.getLowerBound() raimund@2633: + yRange.getLength() * percent; raimund@2633: } raimund@2633: raimund@2633: public double atTop() { raimund@2633: return yRange.getUpperBound(); raimund@2633: } raimund@2633: raimund@2633: public double atGround() { raimund@2633: return yRange.getLowerBound(); raimund@2633: } raimund@2633: raimund@2633: public double atRight() { raimund@2633: return xRange.getUpperBound(); raimund@2633: } raimund@2633: raimund@2633: public double atLeft() { raimund@2633: return xRange.getLowerBound(); raimund@2633: } raimund@2633: raimund@2633: public double above(double percent, double base) { raimund@2633: return base + yRange.getLength() * percent; raimund@2633: } raimund@2633: } raimund@2633: ingo@2233: } ingo@2233: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :