Java tutorial
/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2004, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation; * either version 2.1 of the License, or (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ---------------------- * PanScrollZoomDemo.java * ---------------------- * (C) Copyright 2004, by Object Refinery Limited and Contributors. * * Original Author: Matthias Rose (Ablay & Fodi GmbH, Germany); * Contributor(s): Eduardo Ramalho; * David Gilbert (for Object Refinery Limited); * * $Id: PanScrollZoomDemo.java,v 1.10 2004/05/11 14:56:17 mungady Exp $ * * Changes * ------- * 18-Feb-2004 : Version 1 added to JFreeChart distribution, contributed by Matthias Rose (DG); * */ package apidemo; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import javax.swing.AbstractButton; import javax.swing.BoundedRangeModel; import javax.swing.ButtonGroup; import javax.swing.DefaultBoundedRangeModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JScrollBar; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartRenderingInfo; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.event.ChartChangeEvent; import org.jfree.chart.event.ChartChangeListener; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.ValueAxisPlot; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.StandardXYItemRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.title.TextTitle; import org.jfree.data.Range; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.RefineryUtilities; //import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; /** * A demo for panning, scrolling and zooming. */ public class PanScrollZoomDemo extends JFrame implements ActionListener, ChangeListener, ChartChangeListener, MouseListener/*, MouseMotionListener */ { /** The panel that displays the chart. */ private ChartPanel chartPanel; /** The scroll factor. */ private double scrollFactor = 1000; /** The scroll bar. */ private JScrollBar scrollBar; /** The starting point for panning. */ private Point2D panStartPoint; /** The min/max values for the primary axis. */ private double[] primYMinMax = new double[2]; /** The min/max values for the secondary axis. */ private double[] secondYMinMax = new double[2]; /** Action command for the 'Pan' button. */ private static final String ACTION_CMD_PAN = "pan"; /** Action command for the zoom box button. */ private static final String ACTION_CMD_ZOOM_BOX = "zoomBox"; /** Action command for the zoom fit button. */ private static final String ACTION_CMD_ZOOM_TO_FIT = "zoomFit"; /** Action command for the '+' button. */ private static final String ACTION_CMD_ZOOM_IN = "zoomIn"; /** Action command for the '-' button. */ private static final String ACTION_CMD_ZOOM_OUT = "zoomOut"; /** The zoom factor. */ private static final double ZOOM_FACTOR = 0.8; /** The toolbar. */ private JToolBar toolBar; /** The zoom button. */ private AbstractButton zoomButton; /** The pan button. */ private AbstractButton panButton; /** The zoom in button. */ private AbstractButton zoomInButton; /** The zoom out button. */ private AbstractButton zoomOutButton; /** The fit button. */ private AbstractButton fitButton; /** * Creates a new demo instance. * * @param frameTitle the frame title. */ public PanScrollZoomDemo(final String frameTitle) { super(frameTitle); this.toolBar = createToolbar(); getContentPane().setLayout(new BorderLayout()); getContentPane().add(this.toolBar, BorderLayout.SOUTH); final JFreeChart chart = createChart(); this.scrollBar.setModel(new DefaultBoundedRangeModel()); recalcScrollBar(chart.getPlot()); this.chartPanel = new ChartPanel(chart) { public void autoRangeBoth() { System.out.println("Use 'Fit all' button"); } }; chart.addChangeListener(this); // enable zoom actionPerformed(new ActionEvent(this, 0, ACTION_CMD_ZOOM_BOX)); // MouseListeners for pan function this.chartPanel.addMouseListener(this); // this.chartPanel.addMouseMotionListener(this); // remove popup menu to allow panning // with right mouse pressed this.chartPanel.setPopupMenu(null); getContentPane().add(this.chartPanel); } /** * Creates a sample chart. * * @return a sample chart. */ private JFreeChart createChart() { final XYSeriesCollection primaryJFreeColl = new XYSeriesCollection(); final XYSeries left1 = new XYSeries("Left 1"); left1.add(1, 2); left1.add(2.8, 5.9); left1.add(3, null); left1.add(3.4, 2); left1.add(5, -1); left1.add(7, 1); primaryJFreeColl.addSeries(left1); final XYSeriesCollection secondaryJFreeColl = new XYSeriesCollection(); final XYSeries right1 = new XYSeries("Right 1"); right1.add(3.5, 2.2); right1.add(1.2, 1.3); right1.add(5.7, 4.1); right1.add(7.5, 7.4); secondaryJFreeColl.addSeries(right1); final NumberAxis xAxis = new NumberAxis("X"); xAxis.setAutoRangeIncludesZero(false); xAxis.setAutoRangeStickyZero(false); final NumberAxis primaryYAxis = new NumberAxis("Y1"); primaryYAxis.setAutoRangeIncludesZero(false); primaryYAxis.setAutoRangeStickyZero(false); // create plot final XYItemRenderer y1Renderer = new StandardXYItemRenderer(StandardXYItemRenderer.LINES); y1Renderer.setSeriesPaint(0, Color.blue); y1Renderer.setToolTipGenerator(new StandardXYToolTipGenerator()); final XYPlot xyPlot = new XYPlot(primaryJFreeColl, xAxis, primaryYAxis, y1Renderer); // 2nd y-axis final NumberAxis secondaryYAxis = new NumberAxis("Y2"); secondaryYAxis.setAutoRangeIncludesZero(false); secondaryYAxis.setAutoRangeStickyZero(false); xyPlot.setRangeAxis(1, secondaryYAxis); xyPlot.setDataset(1, secondaryJFreeColl); xyPlot.mapDatasetToRangeAxis(1, 1); xyPlot.mapDatasetToDomainAxis(1, 1); final XYItemRenderer y2Renderer = new StandardXYItemRenderer(StandardXYItemRenderer.SHAPES_AND_LINES); y2Renderer.setToolTipGenerator(new StandardXYToolTipGenerator()); xyPlot.setRenderer(1, y2Renderer); // set some fixed y-dataranges and remember them // because default chartPanel.autoRangeBoth() // would destroy them ValueAxis axis = xyPlot.getRangeAxis(); this.primYMinMax[0] = -5; this.primYMinMax[1] = 15; axis.setLowerBound(this.primYMinMax[0]); axis.setUpperBound(this.primYMinMax[1]); axis = xyPlot.getRangeAxis(1); this.secondYMinMax[0] = -1; this.secondYMinMax[1] = 10; axis.setLowerBound(this.secondYMinMax[0]); axis.setUpperBound(this.secondYMinMax[1]); // Title + legend final String title = "To pan in zoom mode hold right mouse pressed"; final JFreeChart ret = new JFreeChart(title, null, xyPlot, true); final TextTitle textTitle = new TextTitle("(but you can only pan if the chart was zoomed before)"); ret.addSubtitle(textTitle); return ret; } /** * Creates the toolbar. * * @return the toolbar. */ private JToolBar createToolbar() { final JToolBar toolbar = new JToolBar(); final ButtonGroup groupedButtons = new ButtonGroup(); // ACTION_CMD_PAN this.panButton = new JToggleButton(); prepareButton(this.panButton, ACTION_CMD_PAN, " Pan ", "Pan mode"); groupedButtons.add(this.panButton); toolbar.add(this.panButton); // ACTION_CMD_ZOOM_BOX this.zoomButton = new JToggleButton(); prepareButton(this.zoomButton, ACTION_CMD_ZOOM_BOX, " Zoom ", "Zoom mode"); groupedButtons.add(this.zoomButton); this.zoomButton.setSelected(true); // no other makes sense after startup toolbar.add(this.zoomButton); // end of toggle-button group for select/pan/zoom-box toolbar.addSeparator(); // ACTION_CMD_ZOOM_IN this.zoomInButton = new JButton(); prepareButton(this.zoomInButton, ACTION_CMD_ZOOM_IN, " + ", "Zoom in"); toolbar.add(this.zoomInButton); // ACTION_CMD_ZOOM_OUT this.zoomOutButton = new JButton(); prepareButton(this.zoomOutButton, ACTION_CMD_ZOOM_OUT, " - ", "Zoom out"); toolbar.add(this.zoomOutButton); // ACTION_CMD_ZOOM_TO_FIT this.fitButton = new JButton(); prepareButton(this.fitButton, ACTION_CMD_ZOOM_TO_FIT, " Fit ", "Fit all"); toolbar.add(this.fitButton); toolbar.addSeparator(); this.scrollBar = new JScrollBar(JScrollBar.HORIZONTAL); // int ht = (int) zoomButton.getPreferredSize().getHeight(); // scrollBar.setPreferredSize(new Dimension(0, ht)); this.scrollBar.setModel(new DefaultBoundedRangeModel()); toolbar.add(this.scrollBar); this.zoomOutButton.setEnabled(false); this.fitButton.setEnabled(false); this.scrollBar.setEnabled(false); toolbar.setFloatable(false); return toolbar; } /** * Prepares a button. * * @param button the button. * @param actionKey the action key. * @param buttonLabelText the button label. * @param toolTipText the tooltip text. */ private void prepareButton(final AbstractButton button, final String actionKey, final String buttonLabelText, final String toolTipText) { // todo // as this action is empty and the button text is // redefined later, it can be safely removed ... // Action action = new AbstractAction(actionKey) { // public void actionPerformed(ActionEvent evt) { // // ignored // } // }; // button.addActionListener(action); button.setActionCommand(actionKey); button.setText(buttonLabelText); button.setToolTipText(toolTipText); button.addActionListener(this); } /** * Sets the pan mode. * * @param val a boolean. */ private void setPanMode(final boolean val) { // this.chartPanel.setHorizontalZoom(!val); // chartPanel.setHorizontalAxisTrace(! val); // this.chartPanel.setVerticalZoom(!val); // chartPanel.setVerticalAxisTrace(! val); if (val) { this.chartPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else { this.chartPanel.setCursor(Cursor.getDefaultCursor()); } } /** * Handles an action event. * * @param evt * the event. */ public void actionPerformed(final ActionEvent evt) { try { final String acmd = evt.getActionCommand(); if (acmd.equals(ACTION_CMD_ZOOM_BOX)) { setPanMode(false); } else if (acmd.equals(ACTION_CMD_PAN)) { setPanMode(true); } else if (acmd.equals(ACTION_CMD_ZOOM_IN)) { final ChartRenderingInfo info = this.chartPanel.getChartRenderingInfo(); final Rectangle2D rect = info.getPlotInfo().getDataArea(); zoomBoth(rect.getCenterX(), rect.getCenterY(), ZOOM_FACTOR); } else if (acmd.equals(ACTION_CMD_ZOOM_OUT)) { final ChartRenderingInfo info = this.chartPanel.getChartRenderingInfo(); final Rectangle2D rect = info.getPlotInfo().getDataArea(); zoomBoth(rect.getCenterX(), rect.getCenterY(), 1 / ZOOM_FACTOR); } else if (acmd.equals(ACTION_CMD_ZOOM_TO_FIT)) { // X-axis (has no fixed borders) // this.chartPanel.autoRangeHorizontal(); // Y-Axes) (autoRangeVertical // not useful because of fixed borders final Plot plot = this.chartPanel.getChart().getPlot(); if (plot instanceof ValueAxisPlot) { final XYPlot vvPlot = (XYPlot) plot; ValueAxis axis = vvPlot.getRangeAxis(); if (axis != null) { axis.setLowerBound(this.primYMinMax[0]); axis.setUpperBound(this.primYMinMax[1]); } if (plot instanceof XYPlot) { final XYPlot xyPlot = (XYPlot) plot; axis = xyPlot.getRangeAxis(1); if (axis != null) { axis.setLowerBound(this.secondYMinMax[0]); axis.setUpperBound(this.secondYMinMax[1]); } } } } } catch (Exception e) { e.printStackTrace(); } } /** * Handles a {@link ChangeEvent} (in this case, coming from the scrollbar). * * @param event the event. */ public void stateChanged(final ChangeEvent event) { try { final Object src = event.getSource(); final BoundedRangeModel scrollBarModel = this.scrollBar.getModel(); if (src == scrollBarModel) { final int val = scrollBarModel.getValue(); final int ext = scrollBarModel.getExtent(); final Plot plot = this.chartPanel.getChart().getPlot(); if (plot instanceof XYPlot) { final XYPlot hvp = (XYPlot) plot; final ValueAxis axis = hvp.getDomainAxis(); // avoid problems this.chartPanel.getChart().removeChangeListener(this); axis.setRange(val / this.scrollFactor, (val + ext) / this.scrollFactor); // restore chart listener this.chartPanel.getChart().addChangeListener(this); } } } catch (Exception e) { e.printStackTrace(); } } /** * Handles a {@link ChartChangeEvent}. * * @param event the event. */ public void chartChanged(final ChartChangeEvent event) { try { if (event.getChart() == null) { return; } final BoundedRangeModel scrollBarModel = this.scrollBar.getModel(); if (scrollBarModel == null) { return; } boolean chartIsZoomed = false; final Plot plot = event.getChart().getPlot(); if (plot instanceof XYPlot) { final XYPlot hvp = (XYPlot) plot; final ValueAxis xAxis = hvp.getDomainAxis(); final Range xAxisRange = xAxis.getRange(); // avoid recursion scrollBarModel.removeChangeListener(this); final int low = (int) (xAxisRange.getLowerBound() * this.scrollFactor); scrollBarModel.setValue(low); final int ext = (int) (xAxisRange.getUpperBound() * this.scrollFactor - low); scrollBarModel.setExtent(ext); // restore scrollBarModel.addChangeListener(this); // check if zoomed horizontally //Range hdr = hvp.getHorizontalDataRange(xAxis); final Range hdr = hvp.getDataRange(xAxis); final double len = hdr == null ? 0 : hdr.getLength(); chartIsZoomed |= xAxisRange.getLength() < len; } if (!chartIsZoomed && plot instanceof XYPlot) { // check if zoomed vertically final XYPlot vvp = (XYPlot) plot; ValueAxis yAxis = vvp.getRangeAxis(); if (yAxis != null) { chartIsZoomed = yAxis.getLowerBound() > this.primYMinMax[0] || yAxis.getUpperBound() < this.primYMinMax[1]; // right y-axis if (!chartIsZoomed && plot instanceof XYPlot) { final XYPlot xyPlot = (XYPlot) plot; yAxis = xyPlot.getRangeAxis(1); if (yAxis != null) { chartIsZoomed = yAxis.getLowerBound() > this.secondYMinMax[0] || yAxis.getUpperBound() < this.secondYMinMax[1]; } } } } // enable "zoom-out-buttons" if chart is zoomed // otherwise disable them this.panButton.setEnabled(chartIsZoomed); this.zoomOutButton.setEnabled(chartIsZoomed); this.fitButton.setEnabled(chartIsZoomed); this.scrollBar.setEnabled(chartIsZoomed); if (!chartIsZoomed) { setPanMode(false); this.zoomButton.setSelected(true); } } catch (Exception e) { e.printStackTrace(); } } // Mouse[Motion]Listeners for pan /** * Handles a mouse pressed event (to start panning). * * @param event the event. */ public void mousePressed(final MouseEvent event) { try { if (this.panButton.isSelected() || this.panButton.isEnabled() && SwingUtilities.isRightMouseButton(event)) { // final Rectangle2D dataArea = this.chartPanel.getScaledDataArea(); // final Point2D point = event.getPoint(); // if (dataArea.contains(point)) { // setPanMode(true); // this.panStartPoint = point; // } } } catch (Exception e) { e.printStackTrace(); } } /** * Handles a mouse released event (stops panning). * * @param event the event. */ public void mouseReleased(final MouseEvent event) { try { this.panStartPoint = null; // stop panning if (!this.panButton.isSelected()) { setPanMode(false); } } catch (Exception e) { e.printStackTrace(); } } /** * Handles a mouse dragged event to perform panning. * * @param event the event. *//* public void mouseDragged(final MouseEvent event) { try { if (this.panStartPoint != null) { // final Rectangle2D scaledDataArea = this.chartPanel.getScaledDataArea(); // this.panStartPoint = RefineryUtilities.getPointInRectangle( // this.panStartPoint.getX(), // this.panStartPoint.getY(), // scaledDataArea ); final Point2D panEndPoint = RefineryUtilities.getPointInRectangle( event.getX(), event.getY(), scaledDataArea ); // horizontal pan final Plot plot = this.chartPanel.getChart().getPlot(); if (plot instanceof XYPlot) { final XYPlot hvp = (XYPlot) plot; final ValueAxis xAxis = hvp.getDomainAxis(); if (xAxis != null) { final double translatedStartPoint = xAxis.java2DToValue( (float) this.panStartPoint.getX(), scaledDataArea, hvp.getDomainAxisEdge() ); final double translatedEndPoint = xAxis.java2DToValue( (float) panEndPoint.getX(), scaledDataArea, hvp.getDomainAxisEdge() ); final double dX = translatedStartPoint - translatedEndPoint; final double oldMin = xAxis.getLowerBound(); final double newMin = oldMin + dX; final double oldMax = xAxis.getUpperBound(); final double newMax = oldMax + dX; // do not pan out of range if (newMin >= hvp.getDataRange(xAxis).getLowerBound() && newMax <= hvp.getDataRange(xAxis).getUpperBound()) { xAxis.setLowerBound(newMin); xAxis.setUpperBound(newMax); } } } // vertical pan (1. Y-Axis) if (plot instanceof XYPlot) { final XYPlot vvp = (XYPlot) plot; final ValueAxis yAxis = vvp.getRangeAxis(); if (yAxis != null) { final double translatedStartPoint = yAxis.java2DToValue( (float) this.panStartPoint.getY(), scaledDataArea, vvp.getRangeAxisEdge() ); final double translatedEndPoint = yAxis.java2DToValue( (float) panEndPoint.getY(), scaledDataArea, vvp.getRangeAxisEdge() ); final double dY = translatedStartPoint - translatedEndPoint; final double oldMin = yAxis.getLowerBound(); final double newMin = oldMin + dY; final double oldMax = yAxis.getUpperBound(); final double newMax = oldMax + dY; // do not pan out of range if (newMin >= this.primYMinMax[0] && newMax <= this.primYMinMax[1]) { yAxis.setLowerBound(newMin); yAxis.setUpperBound(newMax); } } } // vertical pan (2. Y-Axis) if (plot instanceof XYPlot) { final XYPlot xyPlot = (XYPlot) plot; final ValueAxis yAxis = xyPlot.getRangeAxis(1); if (yAxis != null) { final double translatedStartPoint = yAxis.java2DToValue( (float) this.panStartPoint.getY(), scaledDataArea, xyPlot.getRangeAxisEdge(1) ); final double translatedEndPoint = yAxis.java2DToValue( (float) panEndPoint.getY(), scaledDataArea, xyPlot.getRangeAxisEdge(1) ); final double dY = translatedStartPoint - translatedEndPoint; final double oldMin = yAxis.getLowerBound(); final double newMin = oldMin + dY; final double oldMax = yAxis.getUpperBound(); final double newMax = oldMax + dY; if (newMin >= this.secondYMinMax[0] && newMax <= this.secondYMinMax[1]) { yAxis.setLowerBound(newMin); yAxis.setUpperBound(newMax); } } } // for the next time this.panStartPoint = panEndPoint; } } catch (Exception e) { e.printStackTrace(); } } */ /** * Handles a mouse clicked event, in this case by ignoring it. * * @param event the event. */ public void mouseClicked(final MouseEvent event) { // ignored } /** * Handles a mouse moved event, in this case by ignoring it. * * @param event the event. */ public void mouseMoved(final MouseEvent event) { // ignored } /** * Handles a mouse entered event, in this case by ignoring it. * * @param event the event. */ public void mouseEntered(final MouseEvent event) { // ignored } /** * Handles a mouse exited event, in this case by ignoring it. * * @param event the event. */ public void mouseExited(final MouseEvent event) { // ignored } /** * Starting point for the demo. * * @param args the command line arguments (ignored). */ public static void main(final String[] args) { /* try { final String lookAndFeelClassName = WindowsLookAndFeel.class.getName(); UIManager.setLookAndFeel(lookAndFeelClassName); } catch (Exception ex) { System.out.println(ex.getMessage()); } */ final PanScrollZoomDemo demo = new PanScrollZoomDemo("Pan & Scroll & Zoom - Demo"); demo.pack(); demo.setVisible(true); } // PRIVATE /** * Recalculates the scrollbar settings. * * @param plot the plot. */ private void recalcScrollBar(final Plot plot) { if (plot instanceof XYPlot) { final XYPlot hvp = (XYPlot) plot; final ValueAxis axis = hvp.getDomainAxis(); axis.setLowerMargin(0); axis.setUpperMargin(0); final Range rng = axis.getRange(); final BoundedRangeModel scrollBarModel = this.scrollBar.getModel(); final int len = scrollBarModel.getMaximum() - scrollBarModel.getMinimum(); if (rng.getLength() > 0) { this.scrollFactor = len / rng.getLength(); } final double dblow = rng.getLowerBound(); final int ilow = (int) (dblow * this.scrollFactor); scrollBarModel.setMinimum(ilow); final int val = ilow; scrollBarModel.setValue(val); final double dbup = rng.getUpperBound(); final int iup = (int) (dbup * this.scrollFactor); scrollBarModel.setMaximum(iup); final int ext = iup - ilow; scrollBarModel.setExtent(ext); scrollBarModel.addChangeListener(this); } } /** * Zooms in on an anchor point (measured in Java2D coordinates). * * @param x the x value. * @param y the y value. * @param zoomFactor the zoomFactor < 1 == zoom in; else out. */ private void zoomBoth(final double x, final double y, final double zoomFactor) { zoomHorizontal(x, zoomFactor); zoomVertical(y, zoomFactor); } /** * Decreases the range on the horizontal axis, centered about a Java2D x coordinate. * <P> * The range on the x axis is multiplied by zoomFactor * * @param x the x coordinate in Java2D space. * @param zoomFactor the zoomFactor < 1 == zoom in; else out. */ private void zoomHorizontal(final double x, final double zoomFactor) { final JFreeChart chart = this.chartPanel.getChart(); final ChartRenderingInfo info = this.chartPanel.getChartRenderingInfo(); if (chart.getPlot() instanceof XYPlot) { final XYPlot hvp = (XYPlot) chart.getPlot(); final ValueAxis axis = hvp.getDomainAxis(); if (axis != null) { final double anchorValue = axis.java2DToValue((float) x, info.getPlotInfo().getDataArea(), hvp.getDomainAxisEdge()); if (zoomFactor < 1.0) { axis.resizeRange(zoomFactor, anchorValue); } else if (zoomFactor > 1.0) { final Range range = hvp.getDataRange(axis); adjustRange(axis, range, zoomFactor, anchorValue); } } } } /** * Decreases the range on the vertical axis, centered about a Java2D y coordinate. * <P> * The range on the y axis is multiplied by zoomFactor * * @param y the y coordinate in Java2D space. * @param zoomFactor the zoomFactor < 1 == zoom in; else out. */ private void zoomVertical(final double y, final double zoomFactor) { final JFreeChart chart = this.chartPanel.getChart(); final ChartRenderingInfo info = this.chartPanel.getChartRenderingInfo(); // 1. (left) Y-Axis if (chart.getPlot() instanceof XYPlot) { final XYPlot vvp = (XYPlot) chart.getPlot(); final ValueAxis primYAxis = vvp.getRangeAxis(); if (primYAxis != null) { final double anchorValue = primYAxis.java2DToValue((float) y, info.getPlotInfo().getDataArea(), vvp.getRangeAxisEdge()); if (zoomFactor < 1.0) { // zoom in primYAxis.resizeRange(zoomFactor, anchorValue); } else if (zoomFactor > 1.0) { // zoom out final Range range = new Range(this.primYMinMax[0], this.primYMinMax[1]); adjustRange(primYAxis, range, zoomFactor, anchorValue); } } // 2. (right) Y-Axis if (chart.getPlot() instanceof XYPlot) { final XYPlot xyp = (XYPlot) chart.getPlot(); final ValueAxis secYAxis = xyp.getRangeAxis(1); if (secYAxis != null) { final double anchorValue = secYAxis.java2DToValue((float) y, info.getPlotInfo().getDataArea(), xyp.getRangeAxisEdge(1)); if (zoomFactor < 1.0) { // zoom in secYAxis.resizeRange(zoomFactor, anchorValue); } else if (zoomFactor > 1.0) { // zoom out final Range range = new Range(this.secondYMinMax[0], this.secondYMinMax[1]); adjustRange(secYAxis, range, zoomFactor, anchorValue); } } } } } /** * used for zooming * * @param axis the axis. * @param range the range. * @param zoomFactor the zoom factor. * @param anchorValue the anchor value. */ private void adjustRange(final ValueAxis axis, final Range range, final double zoomFactor, final double anchorValue) { if (axis == null || range == null) { return; } final double rangeMinVal = range.getLowerBound() - range.getLength() * axis.getLowerMargin(); final double rangeMaxVal = range.getUpperBound() + range.getLength() * axis.getUpperMargin(); final double halfLength = axis.getRange().getLength() * zoomFactor / 2; double zoomedMinVal = anchorValue - halfLength; double zoomedMaxVal = anchorValue + halfLength; double adjMinVal = zoomedMinVal; if (zoomedMinVal < rangeMinVal) { adjMinVal = rangeMinVal; zoomedMaxVal += rangeMinVal - zoomedMinVal; } double adjMaxVal = zoomedMaxVal; if (zoomedMaxVal > rangeMaxVal) { adjMaxVal = rangeMaxVal; zoomedMinVal -= zoomedMaxVal - rangeMaxVal; adjMinVal = Math.max(zoomedMinVal, rangeMinVal); } final Range adjusted = new Range(adjMinVal, adjMaxVal); axis.setRange(adjusted); } }