package de.laures.cewolf.cpp; import java.io.Serializable; import java.util.Map; import java.util.Date; import java.util.Calendar; import java.util.GregorianCalendar; import java.text.SimpleDateFormat; import java.text.ParseException; import de.laures.cewolf.ChartPostProcessor; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.plot.*; /** * A postprocessor for altering the domain and range of a chart, essentially creating a way to "zoom into" a chart. * The zooming cabilities for the range (y) axis works for all plots.<BR> * The capabilities for the domain (x) axis work only for x/y and timeseries plots (currently only has capabilities to define hours) only, not category plots.<BR> * (Note: in order for the set range capabilities to work properly, it is recommended that the "rangeIncludesZero" be set to false using a VisualEnhancer postprocessor.)<BR> * The following parameters can be used: * <BR><b>lowerRangeVal</b> optional, default value produced by chart; the lowest value that will be graphed on the range (y) axis * <BR><b>upperRangeVal</b> optional; default value produced by chart; the highest value that will be graphed on the range (y) axis * <BR><b>lowerDomainValN</b> optional; default value produced by chart; the lowest value that will be graphed on the domain (x) axis for a numerical plot (xy plot) * <BR><b>upperDomainValN</b> optional; default value produced by chart; the highest value that will be graphed on the domain (x) axis for a numerical plot (xy plot) * <BR><b>lowerDomainValD</b> optional; default value produced by chart; the minimum time that will be graphed on the domain (x) axis for a time scale graph (timeseries plot) * <BR><b>upperDomainValD</b> optional; default value produced by chart; the maximum time that will be graphed on the domain (x) axis for a time scale graph (timeseries plot) * <BR><b>zoomFactor</b> optional; default 1.0; value to zoom in on the center point * <BR><b>anchorValueD</b> optional; no default value; the domain axis (X axis) of xyplots is centered around this value * <BR><b>anchorValueR</b> optional; no default value; the range axis (Y axis) of xyplots is centered around this value * <P> * Example usage:<P> * <chart:chartpostprocessor id="zoom"><BR> *   <chart:param name="lowerRangeVal" value="-3.2" /><BR> *   <chart:param name="upperRangeVal" value="3.2" /><BR> *   <chart:param name="lowerDomainValN" value="-6.0" /><BR> *   <chart:param name="upperDomainValN" value="12.5" /><BR> *   <chart:param name="lowerDomainValD" value="8:00" /><BR> *   <chart:param name="upperDomainValD" value="15:00" /><BR> *   <chart:param name="zoomFactor" value="1.5" /><BR> * </chart:chartpostprocessor> * <P> * @author Ann Kapusta */ public class ZoomBothAxis implements ChartPostProcessor, Serializable { static final long serialVersionUID = -3336573712263777733L; private double lowerRangeVal = 0.0, upperRangeVal = 0.0; private double lowerDomainValN = 0.0, upperDomainValN = 0.0; private GregorianCalendar lowerDomainValD = new GregorianCalendar(1901, 0, 1); private GregorianCalendar upperDomainValD = new GregorianCalendar(1901, 0, 1); private double zoomFactor = 1.0; private double anchorValueD = Double.NaN, anchorValueR = Double.NaN; public void processChart (Object chart, Map params) { JFreeChart localChart = (JFreeChart) chart; Plot plot = localChart.getPlot(); if (plot instanceof XYPlot) { XYPlot xyPlot = (XYPlot) plot; ValueAxis rangeAxis = xyPlot.getRangeAxis(); ValueAxis domainAxis = (ValueAxis) xyPlot.getDomainAxis(); if (rangeAxis instanceof NumberAxis){ lowerRangeVal = ((NumberAxis) rangeAxis).getLowerBound(); upperRangeVal = ((NumberAxis) rangeAxis).getUpperBound(); } if (domainAxis instanceof DateAxis){ lowerDomainValD.setTime((((DateAxis) domainAxis).getMinimumDate())); upperDomainValD.setTime((((DateAxis) domainAxis).getMaximumDate())); } else if (domainAxis instanceof NumberAxis){ lowerDomainValN = ((NumberAxis) domainAxis).getLowerBound(); upperDomainValN = ((NumberAxis) domainAxis).getUpperBound(); } } else if (plot instanceof CategoryPlot) { CategoryPlot catPlot = (CategoryPlot) plot; ValueAxis axis = catPlot.getRangeAxis(); lowerRangeVal = ((NumberAxis) axis).getLowerBound(); upperRangeVal = ((NumberAxis) axis).getUpperBound(); } String str = (String) params.get("lowerRangeVal"); if (str != null) { try { lowerRangeVal = Double.parseDouble(str); } catch (NumberFormatException nfex) { } } str = (String) params.get("upperRangeVal"); if (str != null) { try { upperRangeVal = Double.parseDouble(str); } catch (NumberFormatException nfex) { } } str = (String) params.get("zoomFactor"); if (str != null) { try { zoomFactor = Double.parseDouble(str); } catch (NumberFormatException nfex) { } } str = (String) params.get("anchorValueD"); if (str != null) { try { anchorValueD = Double.parseDouble(str); } catch (NumberFormatException nfex) { } } str = (String) params.get("anchorValueR"); if (str != null) { try { anchorValueR = Double.parseDouble(str); } catch (NumberFormatException nfex) { } } str = (String) params.get("lowerDomainValN"); if (str != null) { try { double newDomainVal = Double.parseDouble(str); if (newDomainVal >= lowerDomainValN) { lowerDomainValN = newDomainVal; } } catch (NumberFormatException nfex) { } } str = (String) params.get("upperDomainValN"); if (str != null) { try { double newDomainVal = Double.parseDouble(str); if (newDomainVal <= upperDomainValN) { upperDomainValN = newDomainVal; } } catch (NumberFormatException nfex) { } } String strL = (String) params.get("lowerDomainValD"); String strU = (String) params.get("upperDomainValD"); if (strL != null && strU != null) { if (!strL.equals(strU)) { String[] component = strL.split(":"); int hour = Integer.parseInt(component[0]); int minute = Integer.parseInt(component[1]); int tester = lowerDomainValD.get(Calendar.HOUR_OF_DAY); if (hour > tester) { lowerDomainValD.set(Calendar.HOUR_OF_DAY, hour); lowerDomainValD.set(Calendar.MINUTE, minute); } else if (hour == lowerDomainValD.HOUR_OF_DAY && minute > lowerDomainValD.MINUTE){ lowerDomainValD.set(Calendar.HOUR_OF_DAY, hour); lowerDomainValD.set(Calendar.MINUTE, minute); } component = strU.split(":"); hour = Integer.parseInt(component[0]); minute = Integer.parseInt(component[1]); tester = upperDomainValD.get(Calendar.HOUR_OF_DAY); if (hour < tester) { upperDomainValD.set(Calendar.HOUR_OF_DAY, hour); upperDomainValD.set(Calendar.MINUTE, minute); } else if (hour == upperDomainValD.HOUR_OF_DAY && minute < upperDomainValD.MINUTE){ upperDomainValD.set(Calendar.HOUR_OF_DAY, hour); upperDomainValD.set(Calendar.MINUTE, minute); } } } if (plot instanceof XYPlot) { XYPlot xyPlot = (XYPlot) plot; ValueAxis rAxis = xyPlot.getRangeAxis(); if (rAxis instanceof NumberAxis) { NumberAxis nAxis = (NumberAxis) rAxis; if (lowerRangeVal != upperRangeVal) { nAxis.setLowerBound(lowerRangeVal); nAxis.setUpperBound(upperRangeVal); } nAxis.resizeRange(zoomFactor); if (! Double.isNaN(anchorValueR)) nAxis.centerRange(anchorValueR); } ValueAxis dAxis = xyPlot.getDomainAxis(); if (dAxis instanceof DateAxis) { ((DateAxis) dAxis).setMinimumDate(lowerDomainValD.getTime()); ((DateAxis) dAxis).setMaximumDate(upperDomainValD.getTime()); } else if (dAxis instanceof NumberAxis) { NumberAxis nAxis = (NumberAxis) dAxis; if (lowerDomainValN != upperDomainValN) { nAxis.setRange(lowerDomainValN, upperDomainValN); } if (! Double.isNaN(anchorValueD)) nAxis.centerRange(anchorValueD); } } else if (plot instanceof CategoryPlot) { CategoryPlot catPlot = (CategoryPlot) plot; NumberAxis axis = (NumberAxis) catPlot.getRangeAxis(); axis.setLowerBound(lowerRangeVal); axis.setUpperBound(upperRangeVal); axis.resizeRange(zoomFactor); } } public double getAnchorValueD() { return anchorValueD; } public void setAnchorValueD (double anchorValueD) { this.anchorValueD = anchorValueD; } public double getAnchorValueR() { return anchorValueR; } public void setAnchorValueR (double anchorValueR) { this.anchorValueR = anchorValueR; } public double getZoomFactor() { return zoomFactor; } public void setZoomFactor (double zoomFactor) { this.zoomFactor = zoomFactor; } public double getLowerRangeVal() { return lowerRangeVal; } public void setLowerRangeVal (double lowerRangeVal) { this.lowerRangeVal = lowerRangeVal; } public double getUpperRangeVal() { return upperRangeVal; } public void setUpperRangeVal (double upperRangeVal) { this.upperRangeVal = upperRangeVal; } public double getUpperDomainValN() { return upperDomainValN; } public void setUpperDomainValN(double upperDomainVal) { this.upperDomainValN = upperDomainVal; } public double getLowerDomainValN() { return lowerDomainValN; } public void setLowerDomainValN (double lowerDomainVal) { this.lowerDomainValN = lowerDomainVal; } public String getUpperDomainValD() { if (upperDomainValD != null){ SimpleDateFormat format = new SimpleDateFormat("HH:mm"); return format.format(upperDomainValD.getTime()); } else { return null; } } public void setUpperDomainValD (String upperDomainVal) { if (upperDomainVal != null) { // allow for missing minutes if (! upperDomainVal.contains(":")) upperDomainVal += ":00"; String[] component = upperDomainVal.split(":"); int hour = Integer.parseInt(component[0]); int minute = Integer.parseInt(component[1]); this.upperDomainValD.set(Calendar.HOUR_OF_DAY, hour); this.upperDomainValD.set(Calendar.MINUTE, minute); } } public String getLowerDomainValD() { if (lowerDomainValD != null) { SimpleDateFormat format = new SimpleDateFormat("HH:mm"); return format.format(lowerDomainValD.getTime()); } else { return null; } } public void setLowerDomainValD (String lowerDomainVal) { if (lowerDomainVal != null) { // allow for missing minutes if (! lowerDomainVal.contains(":")) lowerDomainVal += ":00"; String[] component = lowerDomainVal.split(":"); int hour = Integer.parseInt(component[0]); int minute = Integer.parseInt(component[1]); this.lowerDomainValD.set(Calendar.HOUR_OF_DAY, hour); this.lowerDomainValD.set(Calendar.MINUTE, minute); } } }