org.pentaho.plugin.jfreereport.reportcharts.XYAreaLineChartExpression.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.plugin.jfreereport.reportcharts.XYAreaLineChartExpression.java

Source

/*
* Copyright 2002 - 2017 Hitachi Vantara.  All rights reserved.
* 
* This software was developed by Hitachi Vantara and is provided under the terms
* of the Mozilla Public License, Version 1.1, or any later version. You may not use
* this file except in compliance with the license. If you need a copy of the license,
* please go to http://www.mozilla.org/MPL/MPL-1.1.txt. TThe Initial Developer is Pentaho Corporation.
*
* Software distributed under the Mozilla Public License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to
* the license for the specific language governing your rights and limitations.
*/

package org.pentaho.plugin.jfreereport.reportcharts;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberAxis3D;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLine3DRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.general.Dataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.Minute;
import org.jfree.data.time.Month;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.Year;
import org.jfree.data.xy.XYDataset;
import org.pentaho.plugin.jfreereport.reportcharts.backport.ExtTimeTableXYDataset;
import org.pentaho.plugin.jfreereport.reportcharts.backport.FastNumberTickUnit;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.libraries.formatting.FastDecimalFormat;

import java.awt.*;
import java.text.DateFormatSymbols;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;

public class XYAreaLineChartExpression extends XYAreaChartExpression implements MultiPlotChartExpression {

    private static final long serialVersionUID = 7082583397390897215L;

    private String secondValueAxisLabel; //$NON-NLS-1$
    private ArrayList lineSeriesColor;

    private Font linesLabelFont; //$NON-NLS-1$
    private Font linesTickLabelFont; //$NON-NLS-1$
    private String lineTicksLabelFormat; //$NON-NLS-1$

    private boolean sharedRangeAxis;

    private double linePeriodCount;
    private Class lineTimePeriod;
    private Font lineTitleFont;
    private Font lineTickFont;
    private Double lineRangeMinimum;
    private Double lineRangeMaximum;
    private boolean lineAxisAutoRange;
    private String secondaryDataSet;
    private boolean lineAxisIncludesZero;
    private boolean lineAxisStickyZero;

    //constructor
    public XYAreaLineChartExpression() {
        lineSeriesColor = new ArrayList();
        secondValueAxisLabel = "";
        linePeriodCount = 0;
        lineAxisIncludesZero = true;
        lineAxisStickyZero = true;
    }

    public boolean isLineAxisIncludesZero() {
        return lineAxisIncludesZero;
    }

    public void setLineAxisIncludesZero(final boolean lineAxisIncludesZero) {
        this.lineAxisIncludesZero = lineAxisIncludesZero;
    }

    public boolean isLineAxisStickyZero() {
        return lineAxisStickyZero;
    }

    public void setLineAxisStickyZero(final boolean lineAxisStickyZero) {
        this.lineAxisStickyZero = lineAxisStickyZero;
    }

    public Font getLineTitleFont() {
        return lineTitleFont;
    }

    public void setLineTitleFont(final Font lineTitleFont) {
        this.lineTitleFont = lineTitleFont;
    }

    public Font getLineTickFont() {
        return lineTickFont;
    }

    public void setLineTickFont(final Font lineTickFont) {
        this.lineTickFont = lineTickFont;
    }

    public Double getLineRangeMinimum() {
        return lineRangeMinimum;
    }

    public void setLineRangeMinimum(final Double lineRangeMinimum) {
        this.lineRangeMinimum = lineRangeMinimum;
    }

    public Double getLineRangeMaximum() {
        return lineRangeMaximum;
    }

    public void setLineRangeMaximum(final Double lineRangeMaximum) {
        this.lineRangeMaximum = lineRangeMaximum;
    }

    public double getLinePeriodCount() {
        return linePeriodCount;
    }

    public void setLinePeriodCount(final double linePeriodCount) {
        this.linePeriodCount = linePeriodCount;
    }

    public Class getLineTimePeriod() {
        return lineTimePeriod;
    }

    public void setLineTimePeriod(final Class lineTimePeriod) {
        this.lineTimePeriod = lineTimePeriod;
    }

    public boolean isSharedRangeAxis() {
        return sharedRangeAxis;
    }

    public void setSharedRangeAxis(final boolean sharedRangeAxis) {
        this.sharedRangeAxis = sharedRangeAxis;
    }

    /**
     * Return a completly separated copy of this function. The copy does no longer share any changeable objects with the
     * original function.
     *
     * @return a copy of this function.
     */
    public Expression getInstance() {
        final XYAreaLineChartExpression chartExpression = (XYAreaLineChartExpression) super.getInstance();
        chartExpression.lineSeriesColor = (ArrayList) lineSeriesColor.clone();
        return chartExpression;
    }

    public String getSecondaryDataSet() {
        return secondaryDataSet;
    }

    public void setSecondaryDataSet(final String dataset) {
        secondaryDataSet = dataset;
    }

    public String getSecondValueAxisLabel() {
        return secondValueAxisLabel;
    }

    public void setSecondValueAxisLabel(final String secondValueAxisLabel) {
        this.secondValueAxisLabel = secondValueAxisLabel;
    }

    public Font getLinesLabelFont() {
        return linesLabelFont;
    }

    public void setLinesLabelFont(final Font linesLabelFont) {
        this.linesLabelFont = linesLabelFont;
    }

    public Font getLinesTickLabelFont() {
        return linesTickLabelFont;
    }

    public void setLinesTickLabelFont(final Font linesTickLabelFont) {
        this.linesTickLabelFont = linesTickLabelFont;
    }

    public String getLineTicksLabelFormat() {
        return lineTicksLabelFormat;
    }

    public void setLineTicksLabelFormat(final String lineTicksLabelFormat) {
        this.lineTicksLabelFormat = lineTicksLabelFormat;
    }

    public void setLineSeriesColor(final int index, final String field) {
        if (lineSeriesColor.size() == index) {
            lineSeriesColor.add(field);
        } else {
            lineSeriesColor.set(index, field);
        }
    }

    public String getLineSeriesColor(final int index) {
        return (String) this.lineSeriesColor.get(index);
    }

    public int getLineSeriesColorCount() {
        return this.lineSeriesColor.size();
    }

    public String[] getLineSeriesColor() {
        final Object[] toArray = this.lineSeriesColor.toArray(new String[this.lineSeriesColor.size()]);
        return (String[]) toArray;
    }

    public void setLineSeriesColor(final String[] fields) {
        this.lineSeriesColor.clear();
        this.lineSeriesColor.addAll(Arrays.asList(fields));
    }

    private XYDataset createLinesDataset() {
        final Object maybeCollector = getDataRow().get(getSecondaryDataSet());
        final Dataset dataset;
        if (maybeCollector instanceof ICollectorFunction) {
            final ICollectorFunction collector = (ICollectorFunction) maybeCollector;
            dataset = (Dataset) collector.getDatasourceValue();
        } else if (maybeCollector instanceof CollectorFunctionResult) {
            final CollectorFunctionResult collector = (CollectorFunctionResult) maybeCollector;
            dataset = collector.getDataSet();
        } else {
            dataset = null;
        }

        final XYDataset linesDataset;
        if (dataset instanceof XYDataset) {
            linesDataset = (XYDataset) dataset;
        } else {
            linesDataset = null;
        }
        return linesDataset;
    }

    protected JFreeChart computeXYChart(final XYDataset xyDataset) {
        final JFreeChart chart;
        if (xyDataset instanceof TimeSeriesCollection) {

            if (isStacked()) {
                final ExtTimeTableXYDataset tableXYDataset = convertToTable(xyDataset);
                chart = createTimeSeriesChart(computeTitle(), getDomainTitle(), getRangeTitle(), tableXYDataset,
                        isShowLegend(), false, false, isStacked());
            } else {
                chart = createTimeSeriesChart(computeTitle(), getDomainTitle(), getRangeTitle(), xyDataset,
                        isShowLegend(), false, false, isStacked());
            }
        } else {
            final PlotOrientation orientation = computePlotOrientation();
            if (isStacked()) {
                chart = createStackedXYAreaChart(computeTitle(), getDomainTitle(), getRangeTitle(), xyDataset,
                        orientation, isShowLegend(), false, false);
            } else {
                chart = ChartFactory.createXYAreaChart(computeTitle(), getDomainTitle(), getRangeTitle(), xyDataset,
                        orientation, isShowLegend(), false, false);
            }
        }

        configureLogarithmicAxis(chart.getXYPlot());
        configureLineChart(chart.getXYPlot());
        return chart;
    }

    protected void configureLineChart(final XYPlot plot) {
        final XYDataset linesDataset = createLinesDataset();
        if (linesDataset == null || linesDataset.getSeriesCount() == 0) {
            return;
        }

        //Create Axis Objects
        final ValueAxis linesAxis;
        if (isSharedRangeAxis()) {
            linesAxis = plot.getRangeAxis();
        } else if (isThreeD()) {
            linesAxis = new NumberAxis3D(getSecondValueAxisLabel());
        } else {
            linesAxis = new NumberAxis(getSecondValueAxisLabel());
        }

        final XYItemRenderer lineRenderer;
        if (isThreeD()) {
            lineRenderer = new XYLine3DRenderer();
        } else {
            lineRenderer = new XYLineAndShapeRenderer();
        }

        plot.setRenderer(1, lineRenderer);
        plot.setDataset(1, linesDataset);
        plot.setRangeAxis(1, linesAxis);

        //map lines to second axis
        plot.mapDatasetToRangeAxis(1, 1);

        //set location of second axis
        plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT);
    }

    protected void configureChart(final JFreeChart chart) {
        super.configureChart(chart);

        final XYPlot plot = chart.getXYPlot();

        if (isSharedRangeAxis() == false) {
            final ValueAxis linesAxis = plot.getRangeAxis(1);
            if (linesAxis instanceof NumberAxis) {
                final NumberAxis numberAxis = (NumberAxis) linesAxis;
                numberAxis.setAutoRangeIncludesZero(isLineAxisIncludesZero());
                numberAxis.setAutoRangeStickyZero(isLineAxisStickyZero());

                if (getLinePeriodCount() > 0) {
                    if (getLineTicksLabelFormat() != null) {
                        final FastDecimalFormat formatter = new FastDecimalFormat(getLineTicksLabelFormat(),
                                getResourceBundleFactory().getLocale());
                        numberAxis.setTickUnit(new FastNumberTickUnit(getLinePeriodCount(), formatter));
                    } else {
                        numberAxis.setTickUnit(new FastNumberTickUnit(getLinePeriodCount()));
                    }
                } else {
                    if (getLineTicksLabelFormat() != null) {
                        final DecimalFormat formatter = new DecimalFormat(getLineTicksLabelFormat(),
                                new DecimalFormatSymbols(getResourceBundleFactory().getLocale()));
                        numberAxis.setNumberFormatOverride(formatter);
                    }
                }
            } else if (linesAxis instanceof DateAxis) {
                final DateAxis numberAxis = (DateAxis) linesAxis;

                if (getLinePeriodCount() > 0 && getLineTimePeriod() != null) {
                    if (getLineTicksLabelFormat() != null) {
                        final SimpleDateFormat formatter = new SimpleDateFormat(getLineTicksLabelFormat(),
                                new DateFormatSymbols(getResourceBundleFactory().getLocale()));
                        numberAxis.setTickUnit(new DateTickUnit(getDateUnitAsInt(getLineTimePeriod()),
                                (int) getLinePeriodCount(), formatter));
                    } else {
                        numberAxis.setTickUnit(new DateTickUnit(getDateUnitAsInt(getLineTimePeriod()),
                                (int) getLinePeriodCount()));
                    }
                } else if (getRangeTickFormatString() != null) {
                    final SimpleDateFormat formatter = new SimpleDateFormat(getRangeTickFormatString(),
                            new DateFormatSymbols(getResourceBundleFactory().getLocale()));
                    numberAxis.setDateFormatOverride(formatter);
                }
            }

            if (linesAxis != null) {
                final Font labelFont = Font.decode(getLabelFont());
                linesAxis.setLabelFont(labelFont);
                linesAxis.setTickLabelFont(labelFont);

                if (getLineTitleFont() != null) {
                    linesAxis.setLabelFont(getLineTitleFont());
                }
                if (getLineTickFont() != null) {
                    linesAxis.setTickLabelFont(getLineTickFont());
                }
                final int level = getRuntime().getProcessingContext().getCompatibilityLevel();
                if (ClassicEngineBoot.isEnforceCompatibilityFor(level, 3, 8)) {
                    final double lineRangeMinimumVal = lineRangeMinimum == null ? 0 : lineRangeMinimum;
                    final double lineRangeMaximumVal = lineRangeMaximum == null ? 0 : lineRangeMaximum;
                    if (lineRangeMinimum != null) {
                        linesAxis.setLowerBound(getLineRangeMinimum());
                    }
                    if (lineRangeMaximum != null) {
                        linesAxis.setUpperBound(getRangeMaximum());
                    }
                    if (lineRangeMinimumVal == 0 && lineRangeMaximumVal == 1) {
                        linesAxis.setLowerBound(0);
                        linesAxis.setUpperBound(1);
                        linesAxis.setAutoRange(true);
                    }
                } else {
                    if (lineRangeMinimum != null) {
                        linesAxis.setLowerBound(lineRangeMinimum);
                    }
                    if (lineRangeMaximum != null) {
                        linesAxis.setUpperBound(lineRangeMaximum);
                    }
                    linesAxis.setAutoRange(isLineAxisAutoRange());
                }
            }
        }

        final XYLineAndShapeRenderer linesRenderer = (XYLineAndShapeRenderer) plot.getRenderer(1);
        if (linesRenderer != null) {
            //set stroke with line width
            linesRenderer.setStroke(translateLineStyle(getLineWidth(), getLineStyle()));
            //hide shapes on line
            linesRenderer.setShapesVisible(isMarkersVisible());
            linesRenderer.setBaseShapesFilled(isMarkersVisible());

            //set colors for each line
            for (int i = 0; i < lineSeriesColor.size(); i++) {
                final String s = (String) lineSeriesColor.get(i);
                linesRenderer.setSeriesPaint(i, parseColorFromString(s));
            }
        }
    }

    public boolean isLineAxisAutoRange() {
        return lineAxisAutoRange;
    }

    public void setLineAxisAutoRange(final boolean lineAxisAutoRange) {
        this.lineAxisAutoRange = lineAxisAutoRange;
    }

    protected int getDateUnitAsInt(final Class domainTimePeriod) {
        if (Second.class.equals(domainTimePeriod)) {
            return DateTickUnit.SECOND;
        }
        if (Minute.class.equals(domainTimePeriod)) {
            return DateTickUnit.MINUTE;
        }
        if (Hour.class.equals(domainTimePeriod)) {
            return DateTickUnit.HOUR;
        }
        if (Day.class.equals(domainTimePeriod)) {
            return DateTickUnit.DAY;
        }
        if (Month.class.equals(domainTimePeriod)) {
            return DateTickUnit.MONTH;
        }
        if (Year.class.equals(domainTimePeriod)) {
            return DateTickUnit.YEAR;
        }
        if (Second.class.equals(domainTimePeriod)) {
            return DateTickUnit.MILLISECOND;
        }
        return DateTickUnit.DAY;
    }
}