/* * ZoomableChart.java of project jchart2d, a chart enriched * by zoom functionality in x dimension. * Copyright (C) 2004 - 2011 Achim Westermann. * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA* * If you modify or optimize the code in a useful way please let me know. * Achim.Westermann@gmx.de * */ package info.monitorenter.gui.chart; import info.monitorenter.gui.chart.rangepolicies.RangePolicyFixedViewport; import info.monitorenter.gui.chart.rangepolicies.RangePolicyUnbounded; import info.monitorenter.util.Range; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; 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 java.util.Iterator; import java.util.List; /** * <code>{@link info.monitorenter.gui.chart.Chart2D}</code> enriched by a * zoom-functionality in the x and y dimension. * <p> * * @author Alessio Sambarino (Contributor) * @author Klaus Pesendorfer (Bugfix contributor) * @author Anadi Mishra (Bugfix contributor) * * @version $Revision: 1.19 $ * */ public class ZoomableChart extends Chart2D implements MouseListener, MouseMotionListener { /** * Generated <code>serial version UID</code>. * <p> */ private static final long serialVersionUID = 8799808716942023907L; /** * Store the last mouse click and test in the mouseDragged-method which * mouse-button was clicked. */ private int m_lastPressedButton; /** The starting point of the mouse drag operation (click, then move). */ private Point2D m_startPoint; /** * Range policy used to zoom out to the minimum bounds that show every data * point. */ private IRangePolicy m_zoomAllRangePolicy = new RangePolicyUnbounded(); /** The area to zoom. */ private Rectangle2D m_zoomArea; /** * Defcon. * <p> */ public ZoomableChart() { super(); this.addMouseListener(this); this.addMouseMotionListener(this); } /** * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ public void mouseClicked(final MouseEvent e) { // nop. } /** * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) */ public void mouseDragged(final MouseEvent e) { if (this.m_lastPressedButton != MouseEvent.BUTTON1) { return; } if ((e.getY() < 20) || (e.getY() > this.getYChartStart()) || (e.getX() < 20) || (e.getX() > this.getXChartEnd())) { // nop } else { double startX; double endX; double dimX; double dimY; double startY; double endY; // x-coordinate if (e.getX() > this.m_startPoint.getX()) { startX = this.m_startPoint.getX(); endX = e.getX(); } else { startX = e.getX(); endX = this.m_startPoint.getX(); } if (startX < this.getXChartStart()) { startX = this.getXChartStart(); } if (endX > (this.getWidth() - 20)) { endX = this.getWidth() - 20; } // y-coordinate if (e.getY() > this.m_startPoint.getY()) { startY = this.m_startPoint.getY(); endY = e.getY(); } else { startY = e.getY(); endY = this.m_startPoint.getY(); } if (startY > this.getYChartStart()) { startY = this.getYChartStart(); } if (endY > (this.getHeight() - 20)) { endY = this.getHeight() - 20; } dimX = endX - startX; dimY = endY - startY; this.m_zoomArea = new Rectangle2D.Double(startX, startY, dimX, dimY); this.setRequestedRepaint(true); } } /** * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ public void mouseEntered(final MouseEvent e) { // nop. } /** * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ public void mouseExited(final MouseEvent e) { // nop. } /** * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) */ public void mouseMoved(final MouseEvent e) { // nop. } /** * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ public void mousePressed(final MouseEvent e) { this.m_startPoint = new Point2D.Double(e.getX(), e.getY()); this.m_lastPressedButton = e.getButton(); } /** * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ public void mouseReleased(final MouseEvent e) { if (this.m_zoomArea != null) { // Modified by Anadi Mishra on 20110911 // IAxis axisX = this.getAxisX(); // IAxis axisY = this.getAxisY(); // x-coordinate double startPx = this.m_zoomArea.getX(); double endPx = this.m_zoomArea.getX() + this.m_zoomArea.getWidth(); // double xAxisMin = axisX.translatePxToValue((int) startPx); // double xAxisMax = axisX.translatePxToValue((int) endPx); // modified by Fabalabs (KP) 20060914: zoom also in y-direction // y-coordinate double startPy = this.m_zoomArea.getY(); double endPy = this.m_zoomArea.getY() + this.m_zoomArea.getHeight(); // double yAxisMin = axisY.translatePxToValue((int) startPy); // double yAxisMax = axisY.translatePxToValue((int) endPy); // do not zoom extremly small areas (does not work properly because of // calculation) if ((endPx - startPx) < 20 || (endPy - startPy) < 20) { this.m_zoomArea = null; this.setRequestedRepaint(true); return; } List<IAxis<?>> axisList = this.getAxes(); for (Iterator<IAxis<?>> i = axisList.iterator(); i.hasNext();) { IAxis<?> iAxis = i.next(); if ((Chart2D.CHART_POSITION_BOTTOM == iAxis.getAxisPosition()) || (Chart2D.CHART_POSITION_TOP == iAxis.getAxisPosition())) {// its // x // axis this.zoom(iAxis, startPx, endPx); } if ((Chart2D.CHART_POSITION_LEFT == iAxis.getAxisPosition()) || (Chart2D.CHART_POSITION_RIGHT == iAxis.getAxisPosition())) {// its // x // axis this.zoom(iAxis, startPy, endPy); } } // this.zoom(xAxisMin, xAxisMax, yAxisMin, yAxisMax); } } /** * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ @Override protected synchronized void paintComponent(final Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; if (this.m_zoomArea != null) { g2.draw(this.m_zoomArea); g2.setPaint(new Color(255, 255, 0, 100)); g2.fill(this.m_zoomArea); } } /** * Zooms to the selected bounds in x-axis. * <p> * * @param xmin * the lower x bound. * * @param xmax * the upper x bound. */ public void zoom(final double xmin, final double xmax) { this.m_zoomArea = null; IAxis<?> axis = this.getAxisX(); IRangePolicy zoomPolicy = new RangePolicyFixedViewport(new Range(xmin, xmax)); axis.setRangePolicy(zoomPolicy); } /** * Zooms the axis to the pixel value of start and end points. * <p> * Does not check for the position of axis so the caller must take care to * provide start x and end x for horizontal and start y and end y for vertical * axes. * * @param axis * the axis to zoom. * * @param startP * the start coordinate in the dimension of the given axis in pixel * coords. * * @param endP * the end coordinate in the dimension of the given axis in pixel * coords. */ public void zoom(IAxis<?> axis, final double startP, final double endP) { this.m_zoomArea = null; double axisMin = axis.translatePxToValue((int) startP); double axisMax = axis.translatePxToValue((int) endP); IRangePolicy zoomPolicy = new RangePolicyFixedViewport(new Range(axisMin, axisMax)); axis.setRangePolicy(zoomPolicy); } /** * Zooms to the selected bounds in both directions. * <p> * * @param xmin * the lower x bound (value of chart (vs. pixel of screen)). * * @param xmax * the upper x bound (value of chart (vs. pixel of screen)). * * @param ymin * the lower y bound (value of chart (vs. pixel of screen)). * * @param ymax * the upper y bound (value of chart (vs. pixel of screen)). */ public void zoom(final double xmin, final double xmax, final double ymin, final double ymax) { this.m_zoomArea = null; IAxis<?> axisX = this.getAxisX(); IRangePolicy zoomPolicyX = new RangePolicyFixedViewport(new Range(xmin, xmax)); axisX.setRangePolicy(zoomPolicyX); IAxis<?> axisY = this.getAxisY(); IRangePolicy zoomPolicyY = new RangePolicyFixedViewport(new Range(ymin, ymax)); axisY.setRangePolicy(zoomPolicyY); } /** * Resets the zooming area to a range that displays all data. * <p> */ public void zoomAll() { List<IAxis<?>> axisList = this.getAxes(); for (Iterator<IAxis<?>> i = axisList.iterator(); i.hasNext();) { IAxis<?> iAxis = i.next(); iAxis.setRangePolicy(this.m_zoomAllRangePolicy); } } }