All Downloads are FREE. Search and download functionalities are using the official Maven repository.

smile.plot.swing.PlotPanel Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
/*
 * Copyright (c) 2010-2021 Haifeng Li. All rights reserved.
 *
 * Smile 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 3 of the License, or
 * (at your option) any later version.
 *
 * Smile 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 Smile.  If not, see .
 */

package smile.plot.swing;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import smile.swing.Button;
import smile.swing.FileChooser;
import smile.swing.Printer;
import smile.swing.Table;

/**
 * Canvas for mathematical plots.
 * 

* For both 2D and 3D plot, the user can zoom in/out by mouse wheel. For 2D plot, * the user can shift the coordinates by moving mouse after double click. The * user can also select an area by mouse for detailed view. For 3D plot, the user * can rotate the view by dragging mouse. * * @author Haifeng Li */ @SuppressWarnings("serial") public class PlotPanel extends JPanel { /** * The canvas of plots. */ private Canvas canvas; /** * The Swing component to draw the canvas. */ private JCanvas contentPane; /** * Optional tool bar to control plots. */ private JToolBar toolbar; /** * Right-click popup menu. */ private JPopupMenu popup; /** * Property table. */ private JTable propertyTable; /** * The Swing component to draw the canvas. */ private class JCanvas extends JComponent implements Printable, ComponentListener, MouseListener, MouseMotionListener, MouseWheelListener, ActionListener { /** * If the mouse double clicked. */ private boolean mouseDoubleClicked = false; /** * The x coordinate (in Java2D coordinate space) of mouse click. */ private int mouseClickX = -1; /** * The y coordinate (in Java2D coordinate space) of mouse click. */ private int mouseClickY = -1; /** * The x coordinate (in Java2D coordinate space) of mouse dragging. */ private int mouseDraggingX = -1; /** * The y coordinate (in Java2D coordinate space) of mouse dragging. */ private int mouseDraggingY = -1; /** * The coordinate base when the user start dragging the mouse. */ private Base backupBase; /** * Constructor. */ JCanvas() { setBackground(Color.white); setDoubleBuffered(true); addComponentListener(this); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); } @Override public void paintComponent(java.awt.Graphics g) { canvas.paint((Graphics2D) g, getWidth(), getHeight()); if (mouseDraggingX >= 0 && mouseDraggingY >= 0) { g.setColor(Color.BLACK); g.drawRect( Math.min(mouseClickX, mouseDraggingX), Math.min(mouseClickY, mouseDraggingY), Math.abs(mouseClickX - mouseDraggingX), Math.abs(mouseClickY - mouseDraggingY) ); } } @Override public int print(java.awt.Graphics g, PageFormat pf, int page) throws PrinterException { if (page > 0) { // We have only one page, and 'page' is zero-based return NO_SUCH_PAGE; } Graphics2D g2d = (Graphics2D) g; // User (0,0) is typically outside the printable area, so we must // translate by the X and Y values in the PageFormat to avoid clipping g2d.translate(pf.getImageableX(), pf.getImageableY()); // Scale plots to paper size. double scaleX = pf.getImageableWidth() / getWidth(); double scaleY = pf.getImageableHeight() / getHeight(); g2d.scale(scaleX, scaleY); // Now we perform our rendering canvas.paint(g2d, getWidth(), getHeight()); // tell the caller that this page is part of the printed document return PAGE_EXISTS; } @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); e.consume(); } else { mouseClickX = e.getX(); mouseClickY = e.getY(); e.consume(); } } @Override public void mouseDragged(MouseEvent e) { if (canvas.base.dimension == 2) { mouseDraggingX = e.getX(); mouseDraggingY = e.getY(); } else if (canvas.base.dimension == 3) { canvas.graphics.rotate(e.getX() - mouseClickX, e.getY() - mouseClickY); mouseClickX = e.getX(); mouseClickY = e.getY(); } repaint(); e.consume(); } @Override public void mouseReleased(MouseEvent e) { Base base = canvas.base; Graphics graphics = canvas.graphics; if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); e.consume(); } else { if (mouseDraggingX != -1 && mouseDraggingY != -1) { mouseDraggingX = -1; mouseDraggingY = -1; if (base.dimension == 2) { if (Math.abs(e.getX() - mouseClickX) > 20 && Math.abs(e.getY() - mouseClickY) > 20) { double[] sc1 = ((Projection2D) (graphics.projection)).inverseProjection(mouseClickX, mouseClickY); double[] sc2 = ((Projection2D) (graphics.projection)).inverseProjection(e.getX(), e.getY()); if (Math.min(sc1[0], sc2[0]) < base.upperBound[0] && Math.max(sc1[0], sc2[0]) > canvas.base.lowerBound[0] && Math.min(sc1[1], sc2[1]) < base.upperBound[1] && Math.max(sc1[1], sc2[1]) > base.lowerBound[1]) { base.lowerBound[0] = Math.max(base.lowerBound[0], Math.min(sc1[0], sc2[0])); base.upperBound[0] = Math.min(base.upperBound[0], Math.max(sc1[0], sc2[0])); base.lowerBound[1] = Math.max(base.lowerBound[1], Math.min(sc1[1], sc2[1])); base.upperBound[1] = Math.min(base.upperBound[1], Math.max(sc1[1], sc2[1])); for (int i = 0; i < base.dimension; i++) { base.setPrecisionUnit(i); } base.initBaseCoord(); graphics.projection.reset(); canvas.resetAxis(); } } } repaint(); e.consume(); } } } @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { mouseDoubleClicked = true; backupBase = canvas.base; } else { mouseDoubleClicked = false; } mouseClickX = e.getX(); mouseClickY = e.getY(); e.consume(); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void actionPerformed(ActionEvent e) { } @Override public void mouseMoved(MouseEvent e) { Base base = canvas.base; Graphics graphics = canvas.graphics; if (base.dimension == 2) { if (mouseDoubleClicked) { double x = mouseClickX - e.getX(); if (Math.abs(x) > 20) { int s = canvas.axis[0].slices(); x = x > 0 ? 1.0 / s : -1.0 / s; x *= (backupBase.upperBound[0] - backupBase.lowerBound[0]); base.lowerBound[0] = backupBase.lowerBound[0] + x; base.upperBound[0] = backupBase.upperBound[0] + x; mouseClickX = e.getX(); } double y = mouseClickY - e.getY(); if (Math.abs(y) > 20) { int s = canvas.axis[1].slices(); y = y > 0 ? -1.0 / s : 1.0 / s; y *= (backupBase.upperBound[1] - backupBase.lowerBound[1]); base.lowerBound[1] = backupBase.lowerBound[1] + y; base.upperBound[1] = backupBase.upperBound[1] + y; mouseClickY = e.getY(); } base.initBaseCoord(); graphics.projection.reset(); canvas.resetAxis(); repaint(); } else { String tooltip = null; double[] sc = ((Projection2D) (graphics.projection)).inverseProjection(e.getX(), e.getY()); String firstid = null; for (Shape shape : canvas.shapes) { if (shape instanceof Plot) { Plot plot = (Plot) shape; Optional s = plot.tooltip(sc); if (s.isPresent()) { if (tooltip == null) { tooltip = s.get(); firstid = null;//plot.name(); } else { if (firstid != null) { tooltip = "" + firstid + ":
" + tooltip; firstid = null; } String id = null;//plot.name(); if (id != null) { tooltip += "
" + id + ":
" + s; } else { tooltip += "
----------
" + s; } } } } } if (tooltip != null) { setToolTipText(String.format("%s", tooltip)); } else { setToolTipText(null); } } } e.consume(); } @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getWheelRotation() == 0) { return; } Base base = canvas.base; Graphics graphics = canvas.graphics; for (int i = 0; i < base.dimension; i++) { int s = canvas.axis[i].slices(); double r = e.getWheelRotation() > 0 ? 1.0 / s : -1.0 / s; if (r > -0.5) { double d = (base.upperBound[i] - base.lowerBound[i]) * r; base.lowerBound[i] -= d; base.upperBound[i] += d; } } for (int i = 0; i < base.dimension; i++) { base.setPrecisionUnit(i); } base.initBaseCoord(); graphics.projection.reset(); canvas.resetAxis(); repaint(); e.consume(); } @Override public void componentResized(ComponentEvent e) { Base base = canvas.base; Graphics graphics = canvas.graphics; if (graphics != null) { base.initBaseCoord(); graphics.projection.reset(); canvas.resetAxis(); } repaint(); } @Override public void componentHidden(ComponentEvent e) { } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { } } /** * Constructor */ public PlotPanel(Canvas canvas) { this.canvas = canvas; contentPane = new JCanvas(); setLayout(new BorderLayout()); add(contentPane, BorderLayout.CENTER); initContextMenauAndToolBar(); } /** * Returns a tool bar to control the plot. * @return a tool bar to control the plot. */ public JComponent getToolbar() { return toolbar; } /** * Toolbar button actions. */ private transient Action saveAction = new SaveAction(); private transient Action printAction = new PrintAction(); private transient Action zoomInAction = new ZoomInAction(); private transient Action zoomOutAction = new ZoomOutAction(); private transient Action resetAction = new ResetAction(); private transient Action enlargePlotAreaAction = new EnlargePlotAreaAction(); private transient Action shrinkPlotAreaAction = new ShrinkPlotAreaAction(); private transient Action propertyAction = new PropertyAction(); private transient Action increaseHeightAction = new IncreaseHeightAction(); private transient Action increaseWidthAction = new IncreaseWidthAction(); private transient Action decreaseHeightAction = new DecreaseHeightAction(); private transient Action decreaseWidthAction = new DecreaseWidthAction(); private JScrollPane scrollPane; /** * Initialize context menu and toolbar. */ private void initContextMenauAndToolBar() { toolbar = new JToolBar(); toolbar.add(new Button(saveAction)); toolbar.add(new Button(printAction)); toolbar.addSeparator(); toolbar.add(new Button(zoomInAction)); toolbar.add(new Button(zoomOutAction)); toolbar.add(new Button(resetAction)); toolbar.addSeparator(); toolbar.add(new Button(enlargePlotAreaAction)); toolbar.add(new Button(shrinkPlotAreaAction)); toolbar.add(new Button(increaseHeightAction)); toolbar.add(new Button(decreaseHeightAction)); toolbar.add(new Button(increaseWidthAction)); toolbar.add(new Button(decreaseWidthAction)); toolbar.addSeparator(); toolbar.add(new Button(propertyAction)); decreaseHeightAction.setEnabled(false); decreaseWidthAction.setEnabled(false); //Initialize popup menu. popup = new JPopupMenu(); popup.add(new JMenuItem(saveAction)); popup.add(new JMenuItem(printAction)); popup.addSeparator(); popup.add(new JMenuItem(zoomInAction)); popup.add(new JMenuItem(zoomOutAction)); popup.add(new JMenuItem(resetAction)); popup.addSeparator(); popup.add(new JMenuItem(enlargePlotAreaAction)); popup.add(new JMenuItem(shrinkPlotAreaAction)); popup.add(new JMenuItem(increaseHeightAction)); popup.add(new JMenuItem(decreaseHeightAction)); popup.add(new JMenuItem(increaseWidthAction)); popup.add(new JMenuItem(decreaseWidthAction)); popup.addSeparator(); popup.add(new JMenuItem(propertyAction)); AncestorListener ancestorListener = new AncestorListener() { @Override public void ancestorAdded(AncestorEvent ae) { boolean inScrollPane = false; Container parent = getParent(); while (parent != null) { if (parent instanceof JScrollPane) { inScrollPane = true; scrollPane = (JScrollPane) parent; break; } parent = parent.getParent(); } increaseHeightAction.setEnabled(inScrollPane); increaseWidthAction.setEnabled(inScrollPane); } @Override public void ancestorRemoved(AncestorEvent ae) { } @Override public void ancestorMoved(AncestorEvent ae) { } }; addAncestorListener(ancestorListener); } private class SaveAction extends AbstractAction { public SaveAction() { super("Save", new ImageIcon(PlotPanel.class.getResource("images/save16.png"))); } @Override public void actionPerformed(ActionEvent e) { try { save(); } catch (IOException ex) { JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } } private class PrintAction extends AbstractAction { public PrintAction() { super("Print", new ImageIcon(PlotPanel.class.getResource("images/print16.png"))); } @Override public void actionPerformed(ActionEvent e) { print(); } } private class ZoomInAction extends AbstractAction { public ZoomInAction() { super("Zoom In", new ImageIcon(PlotPanel.class.getResource("images/zoom-in16.png"))); } @Override public void actionPerformed(ActionEvent e) { zoom(true); } } private class ZoomOutAction extends AbstractAction { public ZoomOutAction() { super("Zoom Out", new ImageIcon(PlotPanel.class.getResource("images/zoom-out16.png"))); } @Override public void actionPerformed(ActionEvent e) { zoom(false); } } private class ResetAction extends AbstractAction { public ResetAction() { super("Reset", new ImageIcon(PlotPanel.class.getResource("images/refresh16.png"))); } @Override public void actionPerformed(ActionEvent e) { reset(); } } private class EnlargePlotAreaAction extends AbstractAction { public EnlargePlotAreaAction() { super("Enlarge", new ImageIcon(PlotPanel.class.getResource("images/resize-larger16.png"))); } @Override public void actionPerformed(ActionEvent e) { if (canvas.margin > 0.05) { canvas.margin -= 0.05; canvas.graphics.projection.reset(); repaint(); } if (canvas.margin <= 0.05) { setEnabled(false); } if (!shrinkPlotAreaAction.isEnabled()) { shrinkPlotAreaAction.setEnabled(true); } } } private class ShrinkPlotAreaAction extends AbstractAction { public ShrinkPlotAreaAction() { super("Shrink", new ImageIcon(PlotPanel.class.getResource("images/resize-smaller16.png"))); } @Override public void actionPerformed(ActionEvent e) { if (canvas.margin < 0.3) { canvas.margin += 0.05; canvas.graphics.projection.reset(); repaint(); } if (canvas.margin >= 0.3) { setEnabled(false); } if (!enlargePlotAreaAction.isEnabled()) { enlargePlotAreaAction.setEnabled(true); } } } private class IncreaseWidthAction extends AbstractAction { public IncreaseWidthAction() { super("Increase Width", new ImageIcon(PlotPanel.class.getResource("images/increase-width16.png"))); } @Override public void actionPerformed(ActionEvent e) { Dimension d = getSize(); d.width += 100; setPreferredSize(d); invalidate(); scrollPane.getParent().validate(); if (!decreaseWidthAction.isEnabled()) { decreaseWidthAction.setEnabled(true); } } } private class IncreaseHeightAction extends AbstractAction { public IncreaseHeightAction() { super("Increase Height", new ImageIcon(PlotPanel.class.getResource("images/increase-height16.png"))); } @Override public void actionPerformed(ActionEvent e) { Dimension d = getSize(); d.height += 100; setPreferredSize(d); invalidate(); scrollPane.getParent().validate(); if (!decreaseHeightAction.isEnabled()) { decreaseHeightAction.setEnabled(true); } } } private class DecreaseWidthAction extends AbstractAction { public DecreaseWidthAction() { super("Decrease Width", new ImageIcon(PlotPanel.class.getResource("images/decrease-width16.png"))); } @Override public void actionPerformed(ActionEvent e) { Dimension d = getSize(); d.width -= 100; Dimension vd = scrollPane.getViewport().getSize(); if (d.width <= vd.width) { d.width = vd.width; decreaseWidthAction.setEnabled(false); } setPreferredSize(d); invalidate(); scrollPane.getParent().validate(); } } private class DecreaseHeightAction extends AbstractAction { public DecreaseHeightAction() { super("Decrease Height", new ImageIcon(PlotPanel.class.getResource("images/decrease-height16.png"))); } @Override public void actionPerformed(ActionEvent e) { Dimension d = getSize(); d.height -= 100; Dimension vd = scrollPane.getViewport().getSize(); if (d.height <= vd.height) { d.height = vd.height; decreaseHeightAction.setEnabled(false); } setPreferredSize(d); invalidate(); scrollPane.getParent().validate(); } } private class PropertyAction extends AbstractAction { public PropertyAction() { super("Properties", new ImageIcon(PlotPanel.class.getResource("images/property16.png"))); } @Override public void actionPerformed(ActionEvent e) { JDialog dialog = createPropertyDialog(); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { } }); dialog.setVisible(true); dialog.dispose(); } } /** * Creates the property dialog. * @return the property dialog. */ private JDialog createPropertyDialog() { Frame frame = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, this); JDialog dialog = new JDialog(frame, "Plot Properties", true); Action okAction = new PropertyDialogOKAction(dialog); Action cancelAction = new PropertyDialogCancelAction(dialog); JButton okButton = new JButton(okAction); JButton cancelButton = new JButton(cancelAction); JPanel buttonsPanel = new JPanel(); buttonsPanel.setLayout(new FlowLayout(FlowLayout.TRAILING)); buttonsPanel.add(okButton); buttonsPanel.add(cancelButton); buttonsPanel.setBorder(BorderFactory.createEmptyBorder(25, 0, 10, 10)); ActionMap actionMap = buttonsPanel.getActionMap(); actionMap.put(cancelAction.getValue(Action.DEFAULT), cancelAction); actionMap.put(okAction.getValue(Action.DEFAULT), okAction); InputMap inputMap = buttonsPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), cancelAction.getValue(Action.DEFAULT)); inputMap.put(KeyStroke.getKeyStroke("ENTER"), okAction.getValue(Action.DEFAULT)); String[] columnNames = {"Property", "Value"}; Base base = canvas.base; if (canvas.base.dimension == 2) { Object[][] data = { {"Title", canvas.getTitle()}, {"Title Font", canvas.getTitleFont()}, {"Title Color", canvas.getTitleColor()}, {"X Axis Title", canvas.getAxis(0).getLabel()}, {"X Axis Range", new double[]{base.getLowerBounds()[0], base.getUpperBounds()[0]}}, {"Y Axis Title", canvas.getAxis(1).getLabel()}, {"Y Axis Range", new double[]{base.getLowerBounds()[1], base.getUpperBounds()[1]}} }; propertyTable = new Table(data, columnNames); } else { Object[][] data = { {"Title", canvas.getTitle()}, {"Title Font", canvas.getTitleFont()}, {"Title Color", canvas.getTitleColor()}, {"X Axis Title", canvas.getAxis(0).getLabel()}, {"X Axis Range", new double[]{base.getLowerBounds()[0], base.getUpperBounds()[0]}}, {"Y Axis Title", canvas.getAxis(1).getLabel()}, {"Y Axis Range", new double[]{base.getLowerBounds()[1], base.getUpperBounds()[1]}}, {"Z Axis Title", canvas.getAxis(2).getLabel()}, {"Z Axis Range", new double[]{base.getLowerBounds()[2], base.getUpperBounds()[2]}} }; propertyTable = new Table(data, columnNames); } // There is a known issue with JTables whereby the changes made in a // cell editor are not committed when focus is lost. // This can result in the table staying in 'edit mode' with the stale // value in the cell being edited still showing, although the change // has not actually been committed to the model. // // In fact what should happen is for the method stopCellEditing() // on CellEditor to be called when focus is lost. // So the editor can choose whether to accept the new value and stop // editing, or have the editing cancelled without committing. // There is a magic property which you have to set on the JTable // instance to turn this feature on. propertyTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); propertyTable.setFillsViewportHeight(true); JScrollPane tablePanel = new JScrollPane(propertyTable); dialog.getContentPane().add(tablePanel, BorderLayout.CENTER); dialog.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); dialog.pack(); dialog.setLocationRelativeTo(frame); return dialog; } private class PropertyDialogOKAction extends AbstractAction { protected static final String ACTION_NAME = "OK"; private JDialog dialog; protected PropertyDialogOKAction(JDialog dialog) { this.dialog = dialog; putValue(Action.DEFAULT, ACTION_NAME); putValue(Action.ACTION_COMMAND_KEY, ACTION_NAME); putValue(Action.NAME, ACTION_NAME); } @Override public void actionPerformed(ActionEvent e) { canvas.setTitle((String) propertyTable.getValueAt(0, 1)); canvas.setTitleFont((Font) propertyTable.getValueAt(1, 1)); canvas.setTitleColor((Color) propertyTable.getValueAt(2, 1)); canvas.getAxis(0).setLabel((String) propertyTable.getValueAt(3, 1)); double[] xbound = (double[]) propertyTable.getValueAt(4, 1); canvas.base.lowerBound[0] = xbound[0]; canvas.base.upperBound[0] = xbound[1]; canvas.getAxis(1).setLabel((String) propertyTable.getValueAt(5, 1)); double[] ybound = (double[]) propertyTable.getValueAt(6, 1); canvas.base.lowerBound[1] = ybound[0]; canvas.base.upperBound[1] = ybound[1]; if (canvas.base.dimension > 2) { canvas.getAxis(2).setLabel((String) propertyTable.getValueAt(7, 1)); double[] zbound = (double[]) propertyTable.getValueAt(8, 1); canvas.base.lowerBound[2] = zbound[0]; canvas.base.upperBound[2] = zbound[1]; } for (int i = 0; i < canvas.base.dimension; i++) { canvas.base.setPrecisionUnit(i); } canvas.base.initBaseCoord(); canvas.graphics.projection.reset(); canvas.resetAxis(); dialog.setVisible(false); contentPane.repaint(); } } private class PropertyDialogCancelAction extends AbstractAction { protected static final String ACTION_NAME = "Cancel"; private JDialog dialog; protected PropertyDialogCancelAction(JDialog dialog) { this.dialog = dialog; putValue(Action.DEFAULT, ACTION_NAME); putValue(Action.ACTION_COMMAND_KEY, ACTION_NAME); putValue(Action.NAME, ACTION_NAME); } @Override public void actionPerformed(ActionEvent e) { dialog.setVisible(false); } } /** * Shows a file chooser and exports the plot to the selected image file. * @throws IOException if an error occurs during writing. */ public void save() throws IOException { FileChooser.SimpleFileFilter filter = FileChooser.SimpleFileFilter.getWritableImageFIlter(); JFileChooser chooser = FileChooser.getInstance(); chooser.setFileFilter(filter); chooser.setAcceptAllFileFilterUsed(false); chooser.setSelectedFiles(new File[0]); int returnVal = chooser.showSaveDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); if (!filter.accept(file)) { file = new File(file.getParentFile(), file.getName() + ".png"); } save(file); } } /** * Exports the plot to an image file. * @param file the destination file. * @throws IOException if an error occurs during writing. */ public void save(File file) throws IOException { BufferedImage bi = canvas.toBufferedImage(contentPane.getWidth(), contentPane.getHeight()); ImageIO.write(bi, FileChooser.getExtension(file), file); } /** * Prints the plot. */ public void print() { Printer.getPrinter().print(contentPane); } /** * Zooms in/out the plot. * @param inout true if zoom in. Otherwise, zoom out. */ public void zoom(boolean inout) { Base base = canvas.base; for (int i = 0; i < base.dimension; i++) { int s = canvas.axis[i].slices(); double r = inout ? -1.0 / s : 1.0 / s; double d = (base.upperBound[i] - base.lowerBound[i]) * r; base.lowerBound[i] -= d; base.upperBound[i] += d; } for (int i = 0; i < base.dimension; i++) { base.setPrecisionUnit(i); } base.initBaseCoord(); canvas.graphics.projection.reset(); canvas.resetAxis(); contentPane.repaint(); } /** * Resets the plot. */ public void reset() { Base base = canvas.base; Graphics graphics = canvas.graphics; base.reset(); graphics.projection.reset(); canvas.resetAxis(); if (graphics.projection instanceof Projection3D) { ((Projection3D) graphics.projection).setDefaultView(); } contentPane.repaint(); } /** The number of created windows, as the default window title. */ static AtomicInteger WindowCount = new AtomicInteger(); /** * Shows the plot in a window. * @return a new JFrame that contains the plot. */ public JFrame window() throws InterruptedException, InvocationTargetException { JFrame frame = new JFrame(); String title = canvas.getTitle(); if (title != null) { title = String.format("Smile Plot %d", WindowCount.addAndGet(1)); } frame.setTitle(title); add(toolbar, BorderLayout.NORTH); frame.getContentPane().add(this); frame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(new java.awt.Dimension(1280, 800)); frame.setLocationRelativeTo(null); frame.setVisible(true); javax.swing.SwingUtilities.invokeAndWait(() -> { reset(); repaint(); frame.toFront(); }); return frame; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy