/* * (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at> * * 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., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package com.fr3ts0n.ecu.gui.application; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.DefaultDrawingSupplier; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.XYDataset; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.text.SimpleDateFormat; import java.util.Iterator; import javax.swing.JPanel; /** * OBD data graphing panel */ public class ObdDataPlotter extends JPanel { private static final long serialVersionUID = 9085602185360330792L; /* Font for all legent items */ static final Font legendFont = new Font("Dialog", 0, 7); /** generator for all tool tips */ static final XYToolTipGenerator toolTipGen = StandardXYToolTipGenerator.getTimeSeriesInstance(); /** switch to use range series per series */ public static boolean oneRangePerSeries = true; protected int raIndex = 0; TimeSeriesCollection dataset = new TimeSeriesCollection(); JFreeChart chart; /** * create the graphing panel */ public ObdDataPlotter() { setLayout(new BorderLayout()); chart = createChart(dataset); ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setMouseZoomable(true, false); add(chartPanel, BorderLayout.CENTER); } /** * set a new graph title * * @param newTitle the frame title. */ public void setTitle(String newTitle) { chart.setTitle(newTitle); } /** * Creates a chart. * * @param dataset a dataset. * @return A chart. */ private JFreeChart createChart(XYDataset dataset) { chart = ChartFactory.createTimeSeriesChart( "OBD Data Graph", // title "Time", // x-axis label "Value", // y-axis label dataset, // data true, // create legend? true, // generate tooltips? false // generate URLs? ); chart.setBackgroundPaint(Color.white); XYPlot plot = (XYPlot) chart.getPlot(); plot.setBackgroundPaint(Color.lightGray); plot.setDomainGridlinePaint(Color.white); plot.setRangeGridlinePaint(Color.white); plot.setDomainCrosshairVisible(true); plot.setRangeCrosshairVisible(true); plot.getDomainAxis().setTickLabelFont(legendFont); DateAxis axis = (DateAxis) plot.getDomainAxis(); axis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss")); chart.getLegend().setItemFont(legendFont); return chart; } /** * remove all data series from graph object */ public synchronized void removeAllSeries() { dataset.removeAllSeries(); if (oneRangePerSeries) { XYPlot plot = (XYPlot) chart.getPlot(); for (; raIndex > 0; raIndex--) { plot.setDataset(raIndex, null); plot.setRenderer(raIndex, null); plot.setRangeAxis(raIndex, null); } plot.setDataset(dataset); } } /** * add a new series to the graph * * @param series The new series to be added */ public synchronized void addSeries(TimeSeries series) { if (oneRangePerSeries) { // get paint for current axis/range/... Paint currPaint = DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE[ raIndex % DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE.length]; XYPlot plot = (XYPlot) chart.getPlot(); // set dataset plot.setDataset(raIndex, new TimeSeriesCollection(series)); // ** set axis NumberAxis axis = new NumberAxis(); axis.setTickLabelFont(legendFont); axis.setAxisLinePaint(currPaint); axis.setTickLabelPaint(currPaint); axis.setTickMarkPaint(currPaint); // ** set axis in plot plot.setRangeAxis(raIndex, axis); plot.setRangeAxisLocation(raIndex, raIndex % 2 == 0 ? AxisLocation.TOP_OR_LEFT : AxisLocation.BOTTOM_OR_RIGHT); plot.mapDatasetToRangeAxis(raIndex, raIndex); // ** create renderer XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false); renderer.setBaseToolTipGenerator(toolTipGen); renderer.setSeriesPaint(0, currPaint); // ** set renderer in plot plot.setRenderer(raIndex, renderer); raIndex++; } dataset.addSeries(series); } /** * Holds value of property graphTime. */ private int graphTime; /** * Getter for property graphTime. * * @return Value of property graphTime. */ public int getGraphTime() { return this.graphTime; } /** * Setter for property graphTime. * * @param graphTime New value of property graphTime. */ @SuppressWarnings("rawtypes") public synchronized void setGraphTime(int graphTime) { TimeSeries currSer; TimeSeriesCollection currDs; XYPlot currPlot = (XYPlot) chart.getPlot(); this.graphTime = graphTime; // lop through all datasets for (int i = currPlot.getDatasetCount(); i >= 0; --i) { currDs = (TimeSeriesCollection) currPlot.getDataset(i); // Update all series within dataset Iterator it = currDs.getSeries().iterator(); while (it.hasNext()) { currSer = (TimeSeries) it.next(); currSer.setMaximumItemAge(graphTime); } } } }