aheinecke@7044: /* Copyright (C) 2013 by Bundesanstalt für Gewässerkunde
aheinecke@7044: * Software engineering by Intevation GmbH
aheinecke@7044: *
aheinecke@7044: * This file is Free Software under the GNU AGPL (>=v3)
aheinecke@7044: * and comes with ABSOLUTELY NO WARRANTY! Check out the
aheinecke@7044: * documentation coming with Dive4Elements River for details.
aheinecke@7044: */
aheinecke@7044:
aheinecke@7044: package org.dive4elements.river.exports;
aheinecke@7044:
aheinecke@7044: import java.awt.Color;
aheinecke@7044: import java.awt.Font;
aheinecke@7044: import java.text.NumberFormat;
aheinecke@7044: import java.util.ArrayList;
aheinecke@7044: import java.util.HashMap;
aheinecke@7044: import java.util.List;
aheinecke@7044: import java.util.Map;
aheinecke@7044:
aheinecke@7044: import javax.swing.ImageIcon;
aheinecke@7044:
aheinecke@7044: import org.apache.log4j.Logger;
aheinecke@7044: import org.jfree.chart.ChartFactory;
aheinecke@7044: import org.jfree.chart.JFreeChart;
aheinecke@7044: import org.jfree.chart.LegendItem;
aheinecke@7044: import org.jfree.chart.annotations.XYAnnotation;
aheinecke@7044: import org.jfree.chart.annotations.XYImageAnnotation;
aheinecke@7044: import org.jfree.chart.annotations.XYTextAnnotation;
aheinecke@7044: import org.jfree.chart.axis.NumberAxis;
aheinecke@7044: import org.jfree.chart.axis.ValueAxis;
aheinecke@7044: import org.jfree.chart.axis.LogarithmicAxis;
aheinecke@7044: import org.jfree.chart.plot.Marker;
aheinecke@7044: import org.jfree.chart.plot.PlotOrientation;
aheinecke@7044: import org.jfree.chart.plot.XYPlot;
aheinecke@7044: import org.jfree.data.Range;
aheinecke@7044: import org.jfree.data.general.Series;
aheinecke@7044: import org.jfree.data.xy.XYDataset;
aheinecke@7044: import org.jfree.data.xy.XYSeries;
aheinecke@7044: import org.jfree.data.xy.XYSeriesCollection;
aheinecke@7044: import org.json.JSONArray;
aheinecke@7044: import org.json.JSONException;
aheinecke@7044:
aheinecke@7044: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
aheinecke@7044: import org.dive4elements.artifactdatabase.state.Facet;
aheinecke@7068: import org.dive4elements.river.artifacts.D4EArtifact;
aheinecke@7059: import org.dive4elements.river.exports.process.Processor;
aheinecke@7044: import org.dive4elements.river.jfree.AxisDataset;
aheinecke@7044: import org.dive4elements.river.jfree.AnnotationHelper;
aheinecke@7044: import org.dive4elements.river.jfree.Bounds;
aheinecke@7044: import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
aheinecke@7044: import org.dive4elements.river.jfree.DoubleBounds;
aheinecke@7044: import org.dive4elements.river.jfree.RiverAnnotation;
aheinecke@7044: import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
aheinecke@7044: import org.dive4elements.river.jfree.StyledXYSeries;
aheinecke@7044: import org.dive4elements.river.themes.ThemeDocument;
aheinecke@7044:
teichmann@7051: import org.w3c.dom.Element;
teichmann@7051:
aheinecke@7044: /**
aheinecke@7044: * The main diagram creation class.
aheinecke@7044: *
aheinecke@7044: * This class is the glue between output processors and facets.
aheinecke@7044: * The generator creates one diagram and calls the appropiate
aheinecke@7044: * processors for the state and
aheinecke@7044: *
aheinecke@7044: * With respect to datasets, ranges and axis, there are following requirements:
aheinecke@7044: *
aheinecke@7044: * - First in, first drawn: "Early" datasets should be of lower Z-Oder
aheinecke@7044: * than later ones (only works per-axis).
aheinecke@7044: * - Visible axis should initially show the range of all datasets that
aheinecke@7044: * show data for this axis (even invisible ones). Motivation: Once
aheinecke@7044: * a dataset (theme) has been activated, it should be on screen.
aheinecke@7044: * - There should always be a Y-Axis on the "left".
aheinecke@7044: *
aheinecke@7044: */
aheinecke@7068: public class DiagramGenerator extends ChartGenerator2 {
aheinecke@7044:
aheinecke@7044: public static final int AXIS_SPACE = 5;
aheinecke@7044:
aheinecke@7044: /** The logger that is used in this generator. */
aheinecke@7044: private static Logger logger = Logger.getLogger(DiagramGenerator.class);
aheinecke@7044:
aheinecke@7044: protected List domainMarkers = new ArrayList();
aheinecke@7044:
aheinecke@7044: protected List valueMarkers = new ArrayList();
aheinecke@7044:
aheinecke@7044: /** The max X range to include all X values of all series for each axis. */
aheinecke@7044: protected Map xBounds;
aheinecke@7044:
aheinecke@7044: /** The max Y range to include all Y values of all series for each axis. */
aheinecke@7044: protected Map yBounds;
aheinecke@7044:
aheinecke@7044: /** Whether or not the plot is inverted (left-right). */
aheinecke@7044: private boolean inverted;
aheinecke@7044:
teichmann@7051: protected DiagramAttributes diagramAttributes;
teichmann@7051:
aheinecke@7044: public DiagramGenerator() {
aheinecke@7044: super();
aheinecke@7044:
aheinecke@7044: xBounds = new HashMap();
aheinecke@7044: yBounds = new HashMap();
aheinecke@7044: }
aheinecke@7044:
teichmann@7051: @Override
teichmann@7051: public void setup(Element config) {
teichmann@7051: logger.debug("DiagramGenerator.setup");
teichmann@7051: diagramAttributes = new DiagramAttributes(config);
teichmann@7051: }
teichmann@7051:
aheinecke@7044: /**
aheinecke@7044: * Generate the chart anew (including localized axis and all).
aheinecke@7044: */
aheinecke@7044: @Override
aheinecke@7044: public JFreeChart generateChart() {
aheinecke@7044: logger.debug("DiagramGenerator.generateChart");
aheinecke@7044:
aheinecke@7044: JFreeChart chart = ChartFactory.createXYLineChart(
aheinecke@7044: getChartTitle(),
aheinecke@7044: getXAxisLabel(),
aheinecke@7044: getYAxisLabel(0),
aheinecke@7044: null,
aheinecke@7044: PlotOrientation.VERTICAL,
aheinecke@7044: isLegendVisible(),
aheinecke@7044: false,
aheinecke@7044: false);
aheinecke@7044:
aheinecke@7044: XYPlot plot = (XYPlot) chart.getPlot();
aheinecke@7044: ValueAxis axis = createXAxis(getXAxisLabel());
aheinecke@7044: plot.setDomainAxis(axis);
aheinecke@7044:
aheinecke@7044: chart.setBackgroundPaint(Color.WHITE);
aheinecke@7044: plot.setBackgroundPaint(Color.WHITE);
aheinecke@7044: addSubtitles(chart);
aheinecke@7044: adjustPlot(plot);
aheinecke@7044:
aheinecke@7044: //debugAxis(plot);
aheinecke@7044:
aheinecke@7044: addDatasets(plot);
aheinecke@7044:
aheinecke@7044: //debugDatasets(plot);
aheinecke@7044:
aheinecke@7044: addMarkers(plot);
aheinecke@7044:
aheinecke@7044: recoverEmptyPlot(plot);
aheinecke@7044: preparePointRanges(plot);
aheinecke@7044:
aheinecke@7044: //debugAxis(plot);
aheinecke@7044:
aheinecke@7044: localizeAxes(plot);
aheinecke@7044: adjustAxes(plot);
aheinecke@7044: if (!(axis instanceof LogarithmicAxis)) {
aheinecke@7044: // XXX:
aheinecke@7044: // The auto zoom without a range tries
aheinecke@7044: // to include 0 in a logarithmic axis
aheinecke@7044: // which triggers a bug in jfreechart that causes
aheinecke@7044: // the values to be drawn carthesian
aheinecke@7044: autoZoom(plot);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: //debugAxis(plot);
aheinecke@7044:
aheinecke@7044: // These have to go after the autozoom.
aheinecke@7044: AnnotationHelper.addAnnotationsToRenderer(annotations, plot,
aheinecke@7044: getChartSettings(), datasets);
aheinecke@7044:
aheinecke@7044: // Add a logo (maybe).
aheinecke@7044: addLogo(plot);
aheinecke@7044:
aheinecke@7044: aggregateLegendEntries(plot);
aheinecke@7044:
aheinecke@7044: return chart;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Return left most data points x value (on first axis).
aheinecke@7044: * Shortcut, especially to be overridden in (LS) charts where
aheinecke@7044: * axis could be inverted.
aheinecke@7044: */
aheinecke@7044: protected double getLeftX() {
aheinecke@7044: return (Double)getXBounds(0).getLower();
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Return right most data points x value (on first axis).
aheinecke@7044: * Shortcut, especially to be overridden in (LS) charts where
aheinecke@7044: * axis could be inverted.
aheinecke@7044: */
aheinecke@7044: protected double getRightX() {
aheinecke@7044: return (Double)getXBounds(0).getUpper();
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Add a logo as background annotation to plot. */
aheinecke@7044: protected void addLogo(XYPlot plot) {
aheinecke@7044: String logo = showLogo();
aheinecke@7044: if (logo == null) {
aheinecke@7044: logger.debug("No logo to show chosen");
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: ImageIcon imageIcon = null;
aheinecke@7044: if (logo.equals("none")) {
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044: /*
aheinecke@7044: If you want to add images, remember to change code in these places:
aheinecke@7044: flys-artifacts:
aheinecke@7044: DiagramGenerator.java
aheinecke@7044: Timeseries*Generator.java and
aheinecke@7044: in the flys-client projects Chart*Propert*Editor.java.
aheinecke@7044: Also, these images have to be put in
aheinecke@7044: flys-artifacts/src/main/resources/images/
aheinecke@7044: flys-client/src/main/webapp/images/
aheinecke@7044: */
aheinecke@7044: java.net.URL imageURL;
aheinecke@7044: if (logo.equals("Intevation")) {
aheinecke@7044: imageURL = DiagramGenerator.class.getResource("/images/intevation.png");
aheinecke@7044: }
aheinecke@7044: else { // TODO else if ...
aheinecke@7044: imageURL = DiagramGenerator.class.getResource("/images/bfg_logo.gif");
aheinecke@7044: }
aheinecke@7044: imageIcon = new ImageIcon(imageURL);
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: double xPos = 0d, yPos = 0d;
aheinecke@7044:
aheinecke@7044: String placeh = logoHPlace();
aheinecke@7044: String placev = logoVPlace();
aheinecke@7044:
aheinecke@7044: if (placev == null || placev.equals("none")) {
aheinecke@7044: placev = "top";
aheinecke@7044: }
aheinecke@7044: if (placev.equals("top")) {
aheinecke@7044: yPos = (Double)getYBounds(0).getUpper();
aheinecke@7044: }
aheinecke@7044: else if (placev.equals("bottom")) {
aheinecke@7044: yPos = (Double)getYBounds(0).getLower();
aheinecke@7044: }
aheinecke@7044: else if (placev.equals("center")) {
aheinecke@7044: yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d;
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: logger.debug("Unknown place-v value: " + placev);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (placeh == null || placeh.equals("none")) {
aheinecke@7044: placeh = "center";
aheinecke@7044: }
aheinecke@7044: if (placeh.equals("left")) {
aheinecke@7044: xPos = getLeftX();
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("right")) {
aheinecke@7044: xPos = getRightX();
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("center")) {
aheinecke@7044: xPos = ((Double)getXBounds(0).getUpper() + (Double)getXBounds(0).getLower())/2d;
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: logger.debug("Unknown place-h value: " + placeh);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: logger.debug("logo position: " + xPos + "/" + yPos);
aheinecke@7044:
aheinecke@7044: org.jfree.ui.RectangleAnchor anchor
aheinecke@7044: = org.jfree.ui.RectangleAnchor.TOP;
aheinecke@7044: if (placev.equals("top")) {
aheinecke@7044: if (placeh.equals("left")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("right")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("center")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.TOP;
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: else if (placev.equals("bottom")) {
aheinecke@7044: if (placeh.equals("left")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("right")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("center")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.BOTTOM;
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: else if (placev.equals("center")) {
aheinecke@7044: if (placeh.equals("left")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.LEFT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("right")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.RIGHT;
aheinecke@7044: }
aheinecke@7044: else if (placeh.equals("center")) {
aheinecke@7044: anchor = org.jfree.ui.RectangleAnchor.CENTER;
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: XYAnnotation xyannotation =
aheinecke@7044: new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor);
aheinecke@7044: plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected NumberAxis createXAxis(String label) {
aheinecke@7044: return new NumberAxis(label);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: @Override
aheinecke@7044: protected Series getSeriesOf(XYDataset dataset, int idx) {
aheinecke@7044: return ((XYSeriesCollection) dataset).getSeries(idx);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: @Override
aheinecke@7044: protected AxisDataset createAxisDataset(int idx) {
aheinecke@7044: logger.debug("Create new AxisDataset for index: " + idx);
aheinecke@7044: return new AxisDataset(idx);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Put debug output about datasets.
aheinecke@7044: */
aheinecke@7044: public void debugDatasets(XYPlot plot) {
aheinecke@7044: logger.debug("Number of datasets: " + plot.getDatasetCount());
aheinecke@7044: for (int i = 0, P = plot.getDatasetCount(); i < P; i++) {
aheinecke@7044: if (plot.getDataset(i) == null) {
aheinecke@7044: logger.debug("Dataset #" + i + " is null");
aheinecke@7044: continue;
aheinecke@7044: }
aheinecke@7044: logger.debug("Dataset #" + i + ":" + plot.getDataset(i));
aheinecke@7044: XYSeriesCollection series = (XYSeriesCollection) plot.getDataset(i);
aheinecke@7044: logger.debug("X-Extend of Dataset: " + series.getSeries(0).getMinX()
aheinecke@7044: + " " + series.getSeries(0).getMaxX());
aheinecke@7044: logger.debug("Y-Extend of Dataset: " + series.getSeries(0).getMinY()
aheinecke@7044: + " " + series.getSeries(0).getMaxY());
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Put debug output about axes.
aheinecke@7044: */
aheinecke@7044: public void debugAxis(XYPlot plot) {
aheinecke@7044: logger.debug("...............");
aheinecke@7044: for (int i = 0, P = plot.getRangeAxisCount(); i < P; i++) {
aheinecke@7044: if (plot.getRangeAxis(i) == null)
aheinecke@7044: logger.debug("Range-Axis #" + i + " == null");
aheinecke@7044: else {
aheinecke@7044: logger.debug("Range-Axis " + i + " != null [" +
aheinecke@7044: plot.getRangeAxis(i).getRange().getLowerBound() +
aheinecke@7044: " " + plot.getRangeAxis(i).getRange().getUpperBound() +
aheinecke@7044: "]");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: for (int i = 0, P = plot.getDomainAxisCount(); i < P; i++) {
aheinecke@7044: if (plot.getDomainAxis(i) == null)
aheinecke@7044: logger.debug("Domain-Axis #" + i + " == null");
aheinecke@7044: else {
aheinecke@7044: logger.debug("Domain-Axis " + i + " != null [" +
aheinecke@7044: plot.getDomainAxis(i).getRange().getLowerBound() +
aheinecke@7044: " " + plot.getDomainAxis(i).getRange().getUpperBound() +
aheinecke@7044: "]");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: logger.debug("...............");
aheinecke@7044: }
aheinecke@7044:
aheinecke@7068: /**
aheinecke@7068: * Registers an area to be drawn.
aheinecke@7068: * @param area Area to be drawn.
aheinecke@7068: * @param axisName Name of the axis.
aheinecke@7068: * @param visible Whether or not to be visible (important for range calculations).
aheinecke@7068: */
aheinecke@7068: public void addAreaSeries(StyledAreaSeriesCollection area, String axisName, boolean visible) {
aheinecke@7068: addAreaSeries(area, diagramAttributes.getAxisIndex(axisName), visible);
aheinecke@7068: }
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Registers an area to be drawn.
aheinecke@7044: * @param area Area to be drawn.
aheinecke@7044: * @param index 'axis index'
aheinecke@7044: * @param visible Whether or not to be visible (important for range calculations).
aheinecke@7044: */
aheinecke@7044: public void addAreaSeries(StyledAreaSeriesCollection area, int index, boolean visible) {
aheinecke@7044: if (area == null) {
aheinecke@7044: logger.warn("Cannot yet render above/under curve.");
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: AxisDataset axisDataset = (AxisDataset) getAxisDataset(index);
aheinecke@7044:
aheinecke@7044: if (visible) {
aheinecke@7044: axisDataset.addArea(area);
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: /* No range merging, for areas extending to infinity this
aheinecke@7044: * causes problems. */
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Add given series if visible, if not visible adjust ranges (such that
aheinecke@7044: * all points in data would be plotted once visible).
aheinecke@7068: * @param series the data series to include in plot.
aheinecke@7068: * @param index index of the axis.
aheinecke@7068: * @param visible whether or not the data should be plotted.
aheinecke@7044: */
aheinecke@7044: public void addAxisSeries(XYSeries series, int index, boolean visible) {
aheinecke@7044: if (series == null) {
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: logger.debug("Y Range of XYSeries: " +
aheinecke@7044: series.getMinY() + " | " + series.getMaxY());
aheinecke@7044:
aheinecke@7044: addAxisDataset(new XYSeriesCollection(series), index, visible);
aheinecke@7068: }
aheinecke@7044:
aheinecke@7068: /**
aheinecke@7068: * Add given series if visible, if not visible adjust ranges (such that
aheinecke@7068: * all points in data would be plotted once visible).
aheinecke@7068: * @param series the data series to include in plot.
aheinecke@7068: * @param axisName name of the axis.
aheinecke@7068: * @param visible whether or not the data should be plotted.
aheinecke@7068: */
aheinecke@7068: public void addAxisSeries(XYSeries series, String axisName, boolean visible) {
aheinecke@7068: addAxisSeries(series, diagramAttributes.getAxisIndex(axisName), visible);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Add the given vertical marker to the chart.
aheinecke@7044: */
aheinecke@7044: public void addDomainMarker(Marker marker) {
aheinecke@7044: addDomainMarker(marker, true);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Add the given vertical marker to the chart.Note: the marker is
aheinecke@7044: * added to the chart only if it is not null and if visible is true.
aheinecke@7044: * @param marker The marker that should be added to the chart.
aheinecke@7044: * @param visible The visibility of the marker.
aheinecke@7044: */
aheinecke@7044: public void addDomainMarker(Marker marker, boolean visible) {
aheinecke@7044: if (visible && marker != null) {
aheinecke@7044: domainMarkers.add(marker);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Add the given vertical marker to the chart.
aheinecke@7044: */
aheinecke@7044: public void addValueMarker(Marker marker) {
aheinecke@7044: addValueMarker(marker, true);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Add the given horizontal marker to the chart.Note: the marker is
aheinecke@7044: * added to the chart only if it is not null and if visible is true.
aheinecke@7044: * @param marker The marker that should be added to the chart.
aheinecke@7044: * @param visible The visibility of the marker.
aheinecke@7044: */
aheinecke@7044: public void addValueMarker(Marker marker, boolean visible) {
aheinecke@7044: if (visible && marker != null) {
aheinecke@7044: valueMarkers.add(marker);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected void addMarkers(XYPlot plot) {
aheinecke@7044: for(Marker marker : domainMarkers) {
aheinecke@7044: plot.addDomainMarker(marker);
aheinecke@7044: }
aheinecke@7044: for(Marker marker : valueMarkers) {
aheinecke@7044: plot.addRangeMarker(marker);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Effect: extend range of x axis to include given limits.
aheinecke@7044: *
aheinecke@7044: * @param bounds the given ("minimal") bounds.
aheinecke@7044: * @param index index of axis to be merged.
aheinecke@7044: */
aheinecke@7044: @Override
aheinecke@7044: protected void combineXBounds(Bounds bounds, int index) {
aheinecke@7044: if (!(bounds instanceof DoubleBounds)) {
aheinecke@7044: logger.warn("Unsupported Bounds type: " + bounds.getClass());
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: DoubleBounds dBounds = (DoubleBounds) bounds;
aheinecke@7044:
aheinecke@7044: if (dBounds == null
aheinecke@7044: || Double.isNaN((Double) dBounds.getLower())
aheinecke@7044: || Double.isNaN((Double) dBounds.getUpper())) {
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: Bounds old = getXBounds(index);
aheinecke@7044:
aheinecke@7044: if (old != null) {
aheinecke@7044: dBounds = (DoubleBounds) dBounds.combine(old);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: setXBounds(index, dBounds);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: @Override
aheinecke@7044: protected void combineYBounds(Bounds bounds, int index) {
aheinecke@7044: if (!(bounds instanceof DoubleBounds)) {
aheinecke@7044: logger.warn("Unsupported Bounds type: " + bounds.getClass());
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: DoubleBounds dBounds = (DoubleBounds) bounds;
aheinecke@7044:
aheinecke@7044: if (dBounds == null
aheinecke@7044: || Double.isNaN((Double) dBounds.getLower())
aheinecke@7044: || Double.isNaN((Double) dBounds.getUpper())) {
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: Bounds old = getYBounds(index);
aheinecke@7044:
aheinecke@7044: if (old != null) {
aheinecke@7044: dBounds = (DoubleBounds) dBounds.combine(old);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: setYBounds(index, dBounds);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * If no data is visible, draw at least empty axis.
aheinecke@7044: */
aheinecke@7044: private void recoverEmptyPlot(XYPlot plot) {
aheinecke@7044: if (plot.getRangeAxis() == null) {
aheinecke@7044: logger.debug("debug: No range axis");
aheinecke@7044: plot.setRangeAxis(createYAxis(0));
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Expands X axes if only a point is shown.
aheinecke@7044: */
aheinecke@7044: private void preparePointRanges(XYPlot plot) {
aheinecke@7044: for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) {
aheinecke@7044:
aheinecke@7044: Integer key = Integer.valueOf(i);
aheinecke@7044: Bounds b = getXBounds(key);
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: if (b != null && b.getLower().equals(b.getUpper())) {
aheinecke@7044: logger.debug("Check whether to expand a x axis.i ("+b.getLower() + "-" + b.getUpper()+")");
aheinecke@7044: setXBounds(key, ChartHelper.expandBounds(b, 5));
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * This method zooms the plot to the specified ranges in the attribute
aheinecke@7044: * document or to the ranges specified by the min/max values in the
aheinecke@7044: * datasets. Note: We determine the range manually if no zoom ranges
aheinecke@7044: * are given, because JFreeCharts auto-zoom adds a margin to the left and
aheinecke@7044: * right of the data area.
aheinecke@7044: *
aheinecke@7044: * @param plot The XYPlot.
aheinecke@7044: */
aheinecke@7044: protected void autoZoom(XYPlot plot) {
aheinecke@7044: logger.debug("Zoom to specified ranges.");
aheinecke@7044:
aheinecke@7044: Range xrange = getDomainAxisRange();
aheinecke@7044: Range yrange = getValueAxisRange();
aheinecke@7044:
aheinecke@7044: ValueAxis xAxis = plot.getDomainAxis();
aheinecke@7044:
aheinecke@7044: Range fixedXRange = getRangeForAxisFromSettings("X");
aheinecke@7044: if (fixedXRange != null) {
aheinecke@7044: xAxis.setRange(fixedXRange);
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: zoomX(plot, xAxis, getXBounds(0), xrange);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) {
aheinecke@7044: ValueAxis yaxis = plot.getRangeAxis(i);
aheinecke@7044:
aheinecke@7044: if (yaxis instanceof IdentifiableNumberAxis) {
aheinecke@7044: IdentifiableNumberAxis idAxis = (IdentifiableNumberAxis) yaxis;
aheinecke@7044:
aheinecke@7044: Range fixedRange = getRangeForAxisFromSettings(idAxis.getId());
aheinecke@7044: if (fixedRange != null) {
aheinecke@7044: yaxis.setRange(fixedRange);
aheinecke@7044: continue;
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (yaxis == null) {
aheinecke@7044: logger.debug("Zoom problem: no Y Axis for index: " + i);
aheinecke@7044: continue;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: logger.debug("Prepare zoom settings for y axis at index: " + i);
aheinecke@7044: zoomY(plot, yaxis, getYBounds(Integer.valueOf(i)), yrange);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected Range getDomainAxisRange() {
aheinecke@7044: String[] ranges = getDomainAxisRangeFromRequest();
aheinecke@7044:
aheinecke@7044: if (ranges == null || ranges.length < 2) {
aheinecke@7044: logger.debug("No zoom range for domain axis specified.");
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (ranges[0].length() > 0 && ranges[1].length() > 0) {
aheinecke@7044: try {
aheinecke@7044: double from = Double.parseDouble(ranges[0]);
aheinecke@7044: double to = Double.parseDouble(ranges[1]);
aheinecke@7044:
aheinecke@7044: if (from == 0 && to == 0) {
aheinecke@7044: logger.debug("No range specified. Lower and upper X == 0");
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (from > to) {
aheinecke@7044: double tmp = to;
aheinecke@7044: to = from;
aheinecke@7044: from = tmp;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: return new Range(from, to);
aheinecke@7044: }
aheinecke@7044: catch (NumberFormatException nfe) {
aheinecke@7044: logger.warn("Wrong values for domain axis range.");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected Range getValueAxisRange() {
aheinecke@7044: String[] ranges = getValueAxisRangeFromRequest();
aheinecke@7044:
aheinecke@7044: if (ranges == null || ranges.length < 2) {
aheinecke@7044: logger.debug("No range specified. Lower and upper Y == 0");
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (ranges[0].length() > 0 && ranges[1].length() > 0) {
aheinecke@7044: try {
aheinecke@7044: double from = Double.parseDouble(ranges[0]);
aheinecke@7044: double to = Double.parseDouble(ranges[1]);
aheinecke@7044:
aheinecke@7044: if (from == 0 && to == 0) {
aheinecke@7044: logger.debug("No range specified. Lower and upper Y == 0");
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: return from > to
aheinecke@7044: ? new Range(to, from)
aheinecke@7044: : new Range(from, to);
aheinecke@7044: }
aheinecke@7044: catch (NumberFormatException nfe) {
aheinecke@7044: logger.warn("Wrong values for value axis range.");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: return null;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
aheinecke@7044: return zoom(plot, axis, bounds, x);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
aheinecke@7044: return zoom(plot, axis, bounds, x);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Zooms the x axis to the range specified in the attribute document.
aheinecke@7044: *
aheinecke@7044: * @param plot The XYPlot.
aheinecke@7044: * @param axis The axis the shoud be modified.
aheinecke@7044: * @param bounds The whole range specified by a dataset.
aheinecke@7044: * @param x A user defined range (null permitted).
aheinecke@7044: *
aheinecke@7044: * @return true, if a zoom range was specified, otherwise false.
aheinecke@7044: */
aheinecke@7044: protected boolean zoom(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
aheinecke@7044:
aheinecke@7044: if (bounds == null) {
aheinecke@7044: return false;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: if (x != null) {
aheinecke@7044: Bounds computed = calculateZoom(bounds, x);
aheinecke@7044: computed.applyBounds(axis, AXIS_SPACE);
aheinecke@7044:
aheinecke@7044: logger.debug("Zoom axis to: " + computed);
aheinecke@7044:
aheinecke@7044: return true;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: bounds.applyBounds(axis, AXIS_SPACE);
aheinecke@7044: return false;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Calculates the start and end km for zoomed charts.
aheinecke@7044: * @param bounds The given total bounds (unzoomed).
aheinecke@7044: * @param range The range specifying the zoom.
aheinecke@7044: *
aheinecke@7044: * @return The start and end km for the zoomed chart.
aheinecke@7044: */
aheinecke@7044: protected Bounds calculateZoom(Bounds bounds, Range range) {
aheinecke@7044: double min = bounds.getLower().doubleValue();
aheinecke@7044: double max = bounds.getUpper().doubleValue();
aheinecke@7044:
aheinecke@7044: if (logger.isDebugEnabled()) {
aheinecke@7044: logger.debug("Minimum is: " + min);
aheinecke@7044: logger.debug("Maximum is: " + max);
aheinecke@7044: logger.debug("Lower zoom is: " + range.getLowerBound());
aheinecke@7044: logger.debug("Upper zoom is: " + range.getUpperBound());
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: double diff = max > min ? max - min : min - max;
aheinecke@7044:
aheinecke@7044: DoubleBounds computed = new DoubleBounds(
aheinecke@7044: min + range.getLowerBound() * diff,
aheinecke@7044: min + range.getUpperBound() * diff);
aheinecke@7044: return computed;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Extract the minimum and maximum values for x and y axes
aheinecke@7044: * which are stored in xRanges and yRanges.
aheinecke@7044: *
aheinecke@7044: * @param index The index of the y-Axis.
aheinecke@7044: *
aheinecke@7044: * @return a Range[] as follows: [x-Range, y-Range].
aheinecke@7044: */
aheinecke@7044: @Override
aheinecke@7044: public Range[] getRangesForAxis(int index) {
aheinecke@7044: logger.debug("getRangesForAxis " + index);
aheinecke@7044:
aheinecke@7044: Bounds rx = getXBounds(Integer.valueOf(0));
aheinecke@7044: Bounds ry = getYBounds(Integer.valueOf(index));
aheinecke@7044:
aheinecke@7044: if (rx == null) {
aheinecke@7044: logger.warn("Range for x axis not set." +
aheinecke@7044: " Using default values: 0 - 1.");
aheinecke@7044: rx = new DoubleBounds(0, 1);
aheinecke@7044: }
aheinecke@7044: if (ry == null) {
aheinecke@7044: logger.warn("Range for y" + index +
aheinecke@7044: " axis not set. Using default values: 0 - 1.");
aheinecke@7044: ry = new DoubleBounds(0, 1);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: return new Range[] {
aheinecke@7044: new Range(rx.getLower().doubleValue(), rx.getUpper().doubleValue()),
aheinecke@7044: new Range(ry.getLower().doubleValue(), ry.getUpper().doubleValue())
aheinecke@7044: };
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Get X (usually horizontal) extent for given axis. */
aheinecke@7044: @Override
aheinecke@7044: public Bounds getXBounds(int axis) {
aheinecke@7044: return xBounds.get(axis);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Set X (usually horizontal) extent for given axis. */
aheinecke@7044: @Override
aheinecke@7044: protected void setXBounds(int axis, Bounds bounds) {
aheinecke@7044: if (bounds.getLower() == bounds.getUpper()) {
aheinecke@7044: xBounds.put(axis, ChartHelper.expandBounds(bounds, 5d));
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: xBounds.put(axis, bounds);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Get Y (usually vertical) extent for given axis. */
aheinecke@7044: @Override
aheinecke@7044: public Bounds getYBounds(int axis) {
aheinecke@7044: return yBounds.get(axis);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Set Y (usually vertical) extent for given axis. */
aheinecke@7044: @Override
aheinecke@7044: protected void setYBounds(int axis, Bounds bounds) {
aheinecke@7044: yBounds.put(axis, bounds);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Adjusts the axes of a plot. This method sets the labelFont of the
aheinecke@7044: * X axis.
aheinecke@7044: *
aheinecke@7044: * (Duplicate in TimeseriesChartGenerator)
aheinecke@7044: *
aheinecke@7044: * @param plot The XYPlot of the chart.
aheinecke@7044: */
aheinecke@7044: protected void adjustAxes(XYPlot plot) {
aheinecke@7044: ValueAxis xaxis = plot.getDomainAxis();
aheinecke@7044:
aheinecke@7044: ChartSettings chartSettings = getChartSettings();
aheinecke@7044: if (chartSettings == null) {
aheinecke@7044: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: Font labelFont = new Font(
aheinecke@7044: DEFAULT_FONT_NAME,
aheinecke@7044: Font.BOLD,
aheinecke@7044: getXAxisLabelFontSize());
aheinecke@7044:
aheinecke@7044: xaxis.setLabelFont(labelFont);
aheinecke@7044: xaxis.setTickLabelFont(labelFont);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * This method walks over all axes (domain and range) of plot and
aheinecke@7044: * calls localizeDomainAxis() for domain axes or localizeRangeAxis() for
aheinecke@7044: * range axes.
aheinecke@7044: *
aheinecke@7044: * @param plot The XYPlot.
aheinecke@7044: */
aheinecke@7044: private void localizeAxes(XYPlot plot) {
aheinecke@7044: for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) {
aheinecke@7044: ValueAxis axis = plot.getDomainAxis(i);
aheinecke@7044:
aheinecke@7044: if (axis != null) {
aheinecke@7044: localizeDomainAxis(axis);
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: logger.warn("Domain axis at " + i + " is null.");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) {
aheinecke@7044: ValueAxis axis = plot.getRangeAxis(i);
aheinecke@7044:
aheinecke@7044: if (axis != null) {
aheinecke@7044: localizeRangeAxis(axis);
aheinecke@7044: }
aheinecke@7044: else {
aheinecke@7044: logger.warn("Range axis at " + i + " is null.");
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Overrides the NumberFormat with the NumberFormat for the current locale
aheinecke@7044: * that is provided by getLocale().
aheinecke@7044: *
aheinecke@7044: * @param domainAxis The domain axis that needs localization.
aheinecke@7044: */
aheinecke@7044: protected void localizeDomainAxis(ValueAxis domainAxis) {
aheinecke@7044: NumberFormat nf = NumberFormat.getInstance(getLocale());
aheinecke@7044: ((NumberAxis) domainAxis).setNumberFormatOverride(nf);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Overrides the NumberFormat with the NumberFormat for the current locale
aheinecke@7044: * that is provided by getLocale().
aheinecke@7044: *
aheinecke@7044: * @param rangeAxis The domain axis that needs localization.
aheinecke@7044: */
aheinecke@7044: protected void localizeRangeAxis(ValueAxis rangeAxis) {
aheinecke@7044: NumberFormat nf = NumberFormat.getInstance(getLocale());
aheinecke@7044: ((NumberAxis) rangeAxis).setNumberFormatOverride(nf);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Do Points out.
aheinecke@7044: */
aheinecke@7044: protected void doPoints(
aheinecke@7044: Object o,
aheinecke@7044: ArtifactAndFacet aandf,
aheinecke@7044: ThemeDocument theme,
aheinecke@7044: boolean visible,
aheinecke@7044: int axisIndex
aheinecke@7044: ) {
aheinecke@7044: String seriesName = aandf.getFacetDescription();
aheinecke@7044: XYSeries series = new StyledXYSeries(seriesName, theme);
aheinecke@7044:
aheinecke@7044: // Add text annotations for single points.
aheinecke@7044: List xy = new ArrayList();
aheinecke@7044:
aheinecke@7044: try {
aheinecke@7044: JSONArray points = new JSONArray((String) o);
aheinecke@7044: for (int i = 0, P = points.length(); i < P; i++) {
aheinecke@7044: JSONArray array = points.getJSONArray(i);
aheinecke@7044: double x = array.getDouble(0);
aheinecke@7044: double y = array.getDouble(1);
aheinecke@7044: String name = array.getString(2);
aheinecke@7044: boolean act = array.getBoolean(3);
aheinecke@7044: if (!act) {
aheinecke@7044: continue;
aheinecke@7044: }
aheinecke@7044: //logger.debug(" x " + x + " y " + y );
aheinecke@7044: series.add(x, y, false);
aheinecke@7044: xy.add(new CollisionFreeXYTextAnnotation(name, x, y));
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: catch(JSONException e){
aheinecke@7044: logger.error("Could not decode json.");
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: RiverAnnotation annotation = new RiverAnnotation(null, null, null, theme);
aheinecke@7044: annotation.setTextAnnotations(xy);
aheinecke@7044:
aheinecke@7044: // Do not generate second legend entry. (null was passed for the aand before).
aheinecke@7044: if (visible) {
aheinecke@7044: annotations.add(annotation);
aheinecke@7044: }
aheinecke@7044: // doAnnotations(annotations, null, theme, visible);
aheinecke@7044: addAxisSeries(series, axisIndex, visible);
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /**
aheinecke@7044: * Create a hash from a legenditem.
aheinecke@7044: * This hash can then be used to merge legend items labels.
aheinecke@7044: * @return hash for given legenditem to identify mergeables.
aheinecke@7044: */
aheinecke@7044: public static String legendItemHash(LegendItem li) {
aheinecke@7044: // TODO Do proper implementation. Ensure that only mergable sets are created.
aheinecke@7044: // getFillPaint()
aheinecke@7044: // getFillPaintTransformer()
aheinecke@7044: // getLabel()
aheinecke@7044: // getLine()
aheinecke@7044: // getLinePaint()
aheinecke@7044: // getLineStroke()
aheinecke@7044: // getOutlinePaint()
aheinecke@7044: // getOutlineStroke()
aheinecke@7044: // Shape getShape()
aheinecke@7044: // String getToolTipText()
aheinecke@7044: // String getURLText()
aheinecke@7044: // boolean isLineVisible()
aheinecke@7044: // boolean isShapeFilled()
aheinecke@7044: // boolean isShapeOutlineVisible()
aheinecke@7044: // boolean isShapeVisible()
aheinecke@7044: String hash = li.getLinePaint().toString();
aheinecke@7044: String label = li.getLabel();
aheinecke@7044: if (label.startsWith("W (") || label.startsWith("W(")) {
aheinecke@7044: hash += "-W-";
aheinecke@7044: }
aheinecke@7044: else if (label.startsWith("Q(") || label.startsWith("Q (")) {
aheinecke@7044: hash += "-Q-";
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: // WQ.java holds example of using regex Matcher/Pattern.
aheinecke@7044:
aheinecke@7044: return hash;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: /** True if x axis has been inverted. */
aheinecke@7044: public boolean isInverted() {
aheinecke@7044: return inverted;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044:
aheinecke@7044: /** Set to true if x axis has been inverted. */
aheinecke@7044: public void setInverted(boolean inverted) {
aheinecke@7044: this.inverted = inverted;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7068: @Override
aheinecke@7068: public String getDefaultChartTitle() {
aheinecke@7068: DiagramAttributes.Title dTitle = diagramAttributes.getTitle();
aheinecke@7068: if (dTitle == null) {
aheinecke@7068: return "Title not configured in conf.xml";
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: return dTitle.evaluate((D4EArtifact)getMaster(), context);
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: @Override
aheinecke@7068: public String getDefaultChartSubtitle() {
aheinecke@7068: DiagramAttributes.Title dTitle = diagramAttributes.getSubtitle();
aheinecke@7068: if (dTitle == null) {
aheinecke@7068: return "Subtitle not configured in conf.xml";
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: return dTitle.evaluate((D4EArtifact)getMaster(), context);
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: /**
aheinecke@7068: * Get internationalized label for the x axis.
aheinecke@7068: */
aheinecke@7068: @Override
aheinecke@7068: protected String getDefaultXAxisLabel() {
aheinecke@7068: return "TODO X axis label";
aheinecke@7068: /* D4EArtifact flys = (D4EArtifact) master;
aheinecke@7068:
aheinecke@7068: return msg(
aheinecke@7068: I18N_XAXIS_LABEL,
aheinecke@7068: I18N_XAXIS_LABEL_DEFAULT,
aheinecke@7068: new Object[] { RiverUtils.getRiver(flys).getName() }); */
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: @Override
aheinecke@7068: protected String getDefaultYAxisLabel(int index) {
aheinecke@7068: return "TODO Y Axis label";
aheinecke@7068: /* String label = "default";
aheinecke@7068:
aheinecke@7068: if (index == YAXIS.W.idx) {
aheinecke@7068: label = getWAxisLabel();
aheinecke@7068: }
aheinecke@7068: else if (index == YAXIS.Q.idx) {
aheinecke@7068: label = msg(getQAxisLabelKey(), getQAxisDefaultLabel());
aheinecke@7068: }
aheinecke@7068: else if (index == YAXIS.D.idx) {
aheinecke@7068: label = msg(I18N_WDIFF_YAXIS_LABEL, I18N_WDIFF_YAXIS_LABEL_DEFAULT);
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: return label;*/
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068:
aheinecke@7068: /**
aheinecke@7068: * Creates a list of Section for the chart's Y axes.
aheinecke@7068: *
aheinecke@7068: * @return a list of Y axis sections.
aheinecke@7068: */
aheinecke@7068: protected List buildYAxisSections() {
aheinecke@7068: List axisSections = new ArrayList();
aheinecke@7068:
aheinecke@7068: List axesAttrs = diagramAttributes.getAxesAttributes();
aheinecke@7068:
aheinecke@7068: for (int i = 0, n = axesAttrs.size(); i < n; i++) {
aheinecke@7068: AxisSection ySection = new AxisSection();
aheinecke@7068: ySection.setIdentifier(diagramAttributes.getAxisName(i));
aheinecke@7068: ySection.setLabel(getYAxisLabel(i));
aheinecke@7068: ySection.setFontSize(14);
aheinecke@7068: ySection.setFixed(false);
aheinecke@7068:
aheinecke@7068: // XXX We are able to find better default ranges that [0,0], the
aheinecke@7068: // only problem is, that we do NOT have a better range than [0,0]
aheinecke@7068: // for each axis, because the initial chart will not have a dataset
aheinecke@7068: // for each axis set!
aheinecke@7068: ySection.setUpperRange(0d);
aheinecke@7068: ySection.setLowerRange(0d);
aheinecke@7068:
aheinecke@7068: axisSections.add(ySection);
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: return axisSections;
aheinecke@7068: }
aheinecke@7068:
aheinecke@7068: protected String axisIndexToName(int index) {
aheinecke@7068: return diagramAttributes.getAxisName(index);
aheinecke@7068: }
aheinecke@7068:
aheinecke@7044: /** Add the acutal data to the diagram according to the processors.
aheinecke@7044: * For every outable facets, this function is
aheinecke@7044: * called and handles the data accordingly. */
aheinecke@7044: @Override
teichmann@7052: public void doOut(
teichmann@7052: ArtifactAndFacet bundle,
teichmann@7052: ThemeDocument theme,
teichmann@7052: boolean visible
teichmann@7052: ) {
aheinecke@7044: String facetName = bundle.getFacetName();
aheinecke@7044: Facet facet = bundle.getFacet();
aheinecke@7044:
aheinecke@7044: /* A conservative security check */
aheinecke@7044: if (facetName == null || facet == null) {
aheinecke@7044: /* Can't happen,.. */
aheinecke@7044: logger.error("doOut called with null facet.");
teichmann@7052: return;
aheinecke@7044: }
aheinecke@7044:
aheinecke@7044: logger.debug("DoOut for facet: " + facetName);
aheinecke@7044:
aheinecke@7059: for (Processor pr: diagramAttributes.getProcessors()) {
aheinecke@7044: if (pr.canHandle(facetName)) {
aheinecke@7068: pr.doOut(this, bundle, theme, visible);
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: }
aheinecke@7044: }