import com.imsl.chart.*; import java.awt.*; import java.awt.event.*; import java.util.Stack; import javax.swing.JMenu; import javax.swing.JMenuItem; public class SampleZoom extends JFrameChart implements MouseListener, MouseMotionListener, ActionListener { private javax.swing.JPanel panel; private AxisXY axis; private int xFirst, yFirst; private int xLast, yLast; private Stack stack; public SampleZoom() { // create a scatter plot with some random points Chart chart = getChart(); axis = new AxisXY(chart); int n = 1000; double x[] = new double[n]; double y[] = new double[n]; for (int k = 0; k < n; k++) { x[k] = 10.*Math.random(); y[k] = 10.*Math.random(); } Data data = new Data(axis, x, y); data.setDataType(Data.DATA_TYPE_MARKER); // add menu "Zoom" menu JMenu jMenuZoom = new JMenu("Zoom"); jMenuZoom.setMnemonic('Z'); addMenuItem(jMenuZoom, "Out"); addMenuItem(jMenuZoom, "Restore"); getJMenuBar().add(jMenuZoom); // save x-axis and y-axis Window attributes on this stack. // they are used to zoom out one level. stack = new Stack(); // listen for mouse press events panel = getPanel(); panel.addMouseListener(this); } /** * Add a menu item */ private void addMenuItem(JMenu jMenuZoom, String title) { JMenuItem jMenuItem = new JMenuItem(title); jMenuItem.setActionCommand(title); jMenuItem.setMnemonic(title.charAt(0)); jMenuZoom.add(jMenuItem); jMenuItem.addActionListener(this); } /** * A mouse press starts the zoom * Record location of this point and listen for drag (motion) events. */ public void mousePressed(MouseEvent event) { xFirst = xLast = event.getX(); yFirst = yLast = event.getY(); panel.addMouseMotionListener(this); } /** * A mouse release ends the zoom. * Stop listening for drag events and update the * Window attribute in the x and y axes. */ public void mouseReleased(MouseEvent event) { panel.removeMouseMotionListener(this); // ignore degenerate zooms if (xFirst==xLast || yFirst==yLast) { repaint(); return; } // get window and convert to user coordinates double windowX[] = (double[])axis.getAxisX().getWindow(); double windowY[] = (double[])axis.getAxisY().getWindow(); // save the windows on the stack (for zoom out option) stack.add(windowX); stack.add(windowY); // get user coordinate of left-upper corner of the box // limit it to stay inside current window double boxLU[] = new double[2]; int x = Math.min(xFirst, xLast); int y = Math.min(yFirst, yLast); axis.mapDeviceToUser(x, y, boxLU); // get user coordinate of right-lower corner of the box // limit it to stay inside current window double boxRL[] = new double[2]; x = Math.max(xFirst, xLast); y = Math.max(yFirst, yLast); axis.mapDeviceToUser(x, y, boxRL); // set axis window to range of rubber-band box // and disable autoscale to force use of window settings axis.setAutoscaleInput(ChartNode.AUTOSCALE_OFF); double xa = Math.max(windowX[0], boxLU[0]); double xb = Math.min(windowX[1], boxRL[0]); double ya = Math.max(windowY[0], boxRL[1]); double yb = Math.min(windowY[1], boxLU[1]); axis.getAxisX().setWindow(xa, xb); axis.getAxisY().setWindow(ya, yb); // force redraw of the chart repaint(); } /** * A drag event continues the zoom. * Erase the old rubber-band box and draw a new one. * Also keep track of the location of this event. */ public void mouseDragged(MouseEvent event) { // erase previous rectangle Graphics g = panel.getGraphics(); g.setXORMode(Color.cyan); // complement of drawing color red drawBox(g); // draw new rectangle xLast = event.getX(); yLast = event.getY(); g.setPaintMode(); g.setColor(Color.red); drawBox(g); } public void mouseMoved(MouseEvent event) {} public void mouseEntered(MouseEvent event) {} public void mouseClicked(MouseEvent event) {} public void mouseExited(MouseEvent event) {} /** * Draw a box with (xFirst,yFirst) and (xLast,yLast) as its corners. */ private void drawBox(Graphics g) { int x = Math.min(xFirst, xLast); int y = Math.min(yFirst, yLast); int w = Math.abs(xLast - xFirst); int h = Math.abs(yLast - yFirst); g.drawRect(x, y, w, h); } /** * Handle menu item events. * Command "Out" zooms out one level. * Command "Restore" undoes all zooms. */ public void actionPerformed(ActionEvent actionEvent) { String command = actionEvent.getActionCommand(); if (command.equals("Out")) { try { // zoom out by restoring window settings from the stack axis.getAxisY().setWindow((double[])stack.pop()); axis.getAxisX().setWindow((double[])stack.pop()); } catch (java.util.EmptyStackException e) { // no more levels to zoom out // restore original setting by turning on autoscale axis.setAutoscaleInput(ChartNode.AUTOSCALE_DATA); } } else if (command.equals("Restore")) { // restore original setting by turning on autoscale an empty stack axis.setAutoscaleInput(ChartNode.AUTOSCALE_DATA); stack.empty(); } // force redraw of the chart repaint(); } public static void main(String argv[]) { new SampleZoom().setVisible(true); } }