daylightchart.daylightchart.chart.DaylightChart.java Source code

Java tutorial

Introduction

Here is the source code for daylightchart.daylightchart.chart.DaylightChart.java

Source

/*
 *
 * Daylight Chart
 * http://sualeh.github.io/DaylightChart
 * Copyright (c) 2007-2016, Sualeh Fatehi.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */
package daylightchart.daylightchart.chart;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.time.Year;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoname.data.Location;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItemSource;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.IntervalMarker;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.title.Title;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

import daylightchart.daylightchart.calculation.DaylightBand;
import daylightchart.daylightchart.calculation.RiseSetUtility;
import daylightchart.daylightchart.calculation.RiseSetYearData;
import daylightchart.options.Options;
import daylightchart.options.chart.ChartOptions;
import daylightchart.options.chart.ChartOptionsListener;

/**
 * Produces a chart of daylight times for any location.
 *
 * @author Sualeh Fatehi
 */
public class DaylightChart extends JFreeChart implements ChartOptionsListener {

    private static final long serialVersionUID = 1223227216177061127L;

    private static final Logger LOGGER = Logger.getLogger(DaylightChart.class.getName());

    private final RiseSetYearData riseSetData;

    /**
     * Create an empty chart, just to get the default chart options.
     */
    public DaylightChart() {
        this(RiseSetUtility.createRiseSetYear(null, Year.now().getValue(), new Options()), new Options());
        setTitle("");
    }

    /**
     * Instantiate the chart for a given location, and given year.
     *
     * @param riseSetData
     *        Rise and set data for the year
     * @param options
     *        Options
     */
    public DaylightChart(final RiseSetYearData riseSetData, final Options options) {
        super(new XYPlot());
        this.riseSetData = riseSetData;
        createChart(options);
    }

    /**
     * {@inheritDoc}
     *
     * @see daylightchart.options.chart.ChartOptionsListener#afterSettingChartOptions(ChartOptions)
     */
    @Override
    public void afterSettingChartOptions(final ChartOptions chartOptions) {
        Font titleFont;
        final TextTitle title = getTitle();
        if (title != null) {
            titleFont = title.getFont();
        } else {
            titleFont = ChartConfiguration.chartFont;
        }
        createTitles(chartOptions, titleFont.deriveFont(Font.BOLD, 18));
    }

    /**
     * {@inheritDoc}
     *
     * @see daylightchart.options.chart.ChartOptionsListener#beforeSettingChartOptions(ChartOptions)
     */
    @Override
    public void beforeSettingChartOptions(final ChartOptions chartOptions) {
        // No-op
    }

    private void adjustForChartOrientation(final ChartOrientation chartOrientation) {
        if (chartOrientation == null) {
            return;
        }

        final XYPlot plot = getXYPlot();
        final ValueAxis hoursAxis = plot.getRangeAxis();
        final ValueAxis monthsAxis = plot.getDomainAxis();

        switch (chartOrientation) {
        case STANDARD:
            hoursAxis.setInverted(true);
            plot.setDomainAxisLocation(AxisLocation.TOP_OR_LEFT);
            break;
        case CONVENTIONAL:
            break;
        case VERTICAL:
            plot.setOrientation(PlotOrientation.HORIZONTAL);
            monthsAxis.setInverted(true);
            break;
        default:
            break;
        }
    }

    /**
     * Creates bands for the sunrise and sunset times for the whole year.
     */
    private void createBandsInPlot(final XYPlot plot) {
        final List<DaylightBand> bands = riseSetData.getBands();
        for (final DaylightBand band : bands) {
            final DaylightChartBand chartBand = new DaylightChartBand(band);
            LOGGER.log(Level.FINE, band.toString());
            final int currentDatasetNumber = plot.getDatasetCount();
            plot.setDataset(currentDatasetNumber, chartBand.getTimeSeriesCollection());
            plot.setRenderer(currentDatasetNumber, chartBand.getRenderer());
        }
    }

    /**
     * Creates the daylight chart.
     */
    private void createChart(final Options options) {

        setBackgroundPaint(Color.white);

        final XYPlot plot = getXYPlot();

        // Set the first renderer, so that the grid lines can be shown
        plot.setRenderer(new StandardXYItemRenderer());
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);

        plot.setBackgroundPaint(ChartConfiguration.nightColor);

        plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
        createMonthsAxis(plot);
        createHoursAxis(plot);

        // Create a marker region for daylight savings time
        if (riseSetData.usesDaylightTime()) {
            createDSTMarker(plot);
        }

        createBandsInPlot(plot);

        ChartOrientation chartOrientation = ChartOrientation.STANDARD;
        if (options != null) {
            chartOrientation = options.getChartOrientation();
        }
        adjustForChartOrientation(chartOrientation);

        final Options optionsNotNull;
        if (options == null) {
            optionsNotNull = new Options();
        } else {
            optionsNotNull = options;
        }
        createTitles(optionsNotNull.getChartOptions(), ChartConfiguration.chartFont.deriveFont(Font.BOLD, 18));

        createLegend(optionsNotNull, ChartConfiguration.chartFont.deriveFont(Font.PLAIN, 12));

    }

    private void createDSTMarker(final XYPlot plot) {
        if (!riseSetData.usesDaylightTime()) {
            return;
        }

        final long intervalStart = riseSetData.getDstStartDate().atStartOfDay().atZone(ZoneId.systemDefault())
                .toInstant().toEpochMilli();
        final long intervalEnd = riseSetData.getDstEndDate().atStartOfDay().atZone(ZoneId.systemDefault())
                .toInstant().toEpochMilli();
        final IntervalMarker dstMarker = new IntervalMarker(intervalStart, intervalEnd,
                ChartConfiguration.nightColor, new BasicStroke(0.0f), null, null, 0.4f);
        dstMarker.setLabelPaint(Color.WHITE);
        dstMarker.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT);
        dstMarker.setLabelTextAnchor(TextAnchor.BASELINE_RIGHT);
        //
        plot.addDomainMarker(dstMarker, Layer.BACKGROUND);
    }

    @SuppressWarnings("deprecation")
    private void createHoursAxis(final XYPlot plot) {
        final DateAxis axis = new DateAxis();
        axis.setLowerMargin(0.0f);
        axis.setUpperMargin(0.0f);
        axis.setTickLabelFont(ChartConfiguration.chartFont.deriveFont(Font.PLAIN, 12));
        // Fix the axis range for all the hours in the day
        axis.setRange(new Date(70, 0, 1), new Date(70, 0, 2));
        //
        plot.setRangeAxis(axis);
    }

    private void createLegend(final Options options, final Font font) {
        removeLegend();

        if (options.isShowChartLegend()) {
            final LegendItemSource legendItemSource = new DaylightChartLegendItemSource(options);
            final LegendTitle legendTitle = new LegendTitle(legendItemSource);
            legendTitle.setItemFont(font);
            legendTitle.setPosition(RectangleEdge.BOTTOM);
            addLegend(legendTitle);
        }
    }

    @SuppressWarnings("deprecation")
    private void createMonthsAxis(final XYPlot plot) {
        final DateAxis axis = new DateAxis();
        axis.setTickMarkPosition(DateTickMarkPosition.START);
        axis.setLowerMargin(0.0f);
        axis.setUpperMargin(0.0f);
        axis.setTickLabelFont(ChartConfiguration.chartFont.deriveFont(Font.PLAIN, 12));
        axis.setDateFormatOverride(ChartConfiguration.monthsFormat);
        axis.setVerticalTickLabels(true);
        axis.setTickUnit(new DateTickUnit(DateTickUnit.MONTH, 1), true, true);
        // Fix the axis range for all the months in the year
        final int dateYear = riseSetData.getYear() - 1900;
        axis.setRange(new Date(dateYear, 0, 1), new Date(dateYear, 11, 31));
        //
        plot.setDomainAxis(axis);
    }

    @SuppressWarnings("unchecked")
    private void createTitles(final ChartOptions chartOptions, final Font titleFont) {

        // Clear all titles and subtitles
        setTitle((TextTitle) null);
        for (final Title subtitle : (List<Title>) getSubtitles()) {
            if (subtitle instanceof TextTitle) {
                removeSubtitle(subtitle);
            }
        }

        // Build new titles and legend
        final Location location = riseSetData.getLocation();
        final boolean showTitle = chartOptions.getTitleOptions().getShowTitle();
        if (location != null && showTitle) {
            final TextTitle title = new TextTitle(location.toString(), titleFont);
            setTitle(title);

            final Font subtitleFont = titleFont.deriveFont(Font.PLAIN);
            final TextTitle subtitle = new TextTitle(location.getDetails(), subtitleFont);
            subtitle.setPaint(title.getPaint());
            addSubtitle(subtitle);
        }
    }

}