Package bs.bs2d.gui.plot

Source Code of bs.bs2d.gui.plot.PlotPanel

package bs.bs2d.gui.plot;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;

/**
*
* @author Djen
*/
public class PlotPanel extends JPanel implements UpdateListener{

    public static final Color SELECTION_RECT_COLOR = Color.GRAY;
   
    private static final int LEGEND_FRAME_PADDING = 10;
   
    public static final int UPPER_LEFT = 1;
    public static final int UPPER_RIGHT = 2;
    public static final int LOWER_LEFT = 3;
    public static final int LOWER_RIGHT = 4;
   
    // settings
    private Plottable plot;
    private Rectangle selectionRect;
   
    private JPanel canvas;
    private Dimension cnvsSize;
    private Ruler ruler;
    private final MeshPlotInfoBar infoBar;
   
    private AffineTransform transform;
    private AffineTransform invTransform;
   
    private AffineTransform legendTransform;
    private Rectangle2D legendBounds;
   
    private int legendPos;
   

    public PlotPanel() {
        super(new BorderLayout());
        setMinimumSize(new Dimension(300, 300));
       
        transform = AffineTransform.getScaleInstance(1, 1);
        invTransform = transform;
        legendTransform = transform;
       
        infoBar = new MeshPlotInfoBar();
        initCanvas();
       
        add(canvas);
        add(infoBar, BorderLayout.PAGE_END);
       
        legendPos = UPPER_LEFT;
    }

    private void initCanvas() {
        canvas = new JPanel(null, true) {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;
                paintCanvas(g2);
            }
        };
        canvas.setBackground(Color.WHITE);

        canvas.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                Dimension ocs = cnvsSize; // old size
                cnvsSize = canvas.getSize();
                if (ocs == null) {
                    cnvsSize = canvas.getSize();
                    resetView();
                } else {
                    //translate center of viewport
                    double dx = (cnvsSize.width - ocs.width) / 2.0;
                    double dy = (cnvsSize.height - ocs.height) / 2.0;
                    translateView(dx, dy);

                    if (ruler != null) {
                        ruler.updateBounds(cnvsSize);
                    }
                   
                    // update legend
                    if(plot != null && plot.hasLegend()){
                        legendBounds = plot.getLegendBounds();
                        legendTransform = getLegendTransform(legendBounds);
                    }
                }
            }
        });

        MouseAdapter ma = new MouseAdapter() {
            private Point oldPos;
            boolean selecting = false;

            // MouseListener methods
            @Override
            public void mousePressed(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    oldPos = e.getPoint();
                    selecting = false;
                } else if (e.getButton() == MouseEvent.BUTTON1) {
                    oldPos = e.getPoint();
                    selecting = true;
                } else {
                    oldPos = null;
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (!selecting || selectionRect == null)
                    return;
               
                //widen rectangle to include points that are exactly on the line
                selectionRect.width++;
                selectionRect.height++;

                select(selectionRect, e.isShiftDown(), e.isControlDown());
               
                selectionRect = null;
                selecting = false;
               
                updateCanvas();
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1) {
                    // single node selection
                    Point p = e.getPoint();
                    Rectangle r = new Rectangle(p.x-3, p.y-3, 7, 7);
                   
                    select(r, e.isShiftDown(), e.isControlDown());
                   
                } else if (e.getButton() == MouseEvent.BUTTON2) {
                    resetView();
                }
            }

            //MouseMotionListener methods
            @Override
            public void mouseMoved(MouseEvent e) {
                Point2D p = new Point2D.Double();
                invTransform.transform(e.getPoint(), p);
                infoBar.setMousePosition(p);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                if (oldPos == null) // shouldn't happen anyway
                    return;
               
                Point pos = e.getPoint();

                if (selecting) {
                    selectionRect = getRectangle(oldPos, pos);
                    canvas.repaint();
                } else {
                    translateView(pos.x - oldPos.x, pos.y - oldPos.y);
                    oldPos = pos;
                }
            }

            //MouseWheelListener methods
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                if(plot == null)
                    return;
                double r = e.getPreciseWheelRotation();
                double s = -r / 30 + 1;
                zoomView(e.getX(), e.getY(), s);
            }

            // utility methods
            private Rectangle getRectangle(Point p1, Point p2) {
                Rectangle r = new Rectangle(p1);
                r.add(p2);
                return r;
            }
           
            private void select(Rectangle rect, boolean shift, boolean ctrl){
                if(!(plot instanceof Selectable))
                    return;
               
                Selectable selectable = (Selectable) plot;
               
                // transform selection rectangle back into world coordinates
                Rectangle2D trect;
                trect = invTransform.createTransformedShape(rect).getBounds2D();
               
                if (ctrl) {
                    selectable.removeSelection(trect);
                } else if(shift){
                    selectable.addSelection(trect);
                } else {
                    selectable.setSelection(trect);
                }
            }
           
        };
        canvas.addMouseListener(ma);
        canvas.addMouseMotionListener(ma);
        canvas.addMouseWheelListener(ma);
    }

    private void paintCanvas(Graphics2D g) {

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       
        if(plot != null)
            plot.paint(g, transform);
       
        if(selectionRect != null){
            g.setColor(SELECTION_RECT_COLOR);
            g.draw(selectionRect);
        }
       
        //paint ruler
        if (ruler != null && ruler.isVisible()) {
            ruler.paint(g);
        }
       
        // paint legend
        if(plot == null || !plot.hasLegend())
            return;
       
        AffineTransform gt = g.getTransform();
        g.transform(legendTransform);
       
        plot.paintLegend(g);
       
        g.setTransform(gt);
    }
   
    private AffineTransform getLegendTransform(Rectangle2D legendBounds){
        double x, y, s;
       
        double bx = legendBounds.getX();
        double by = legendBounds.getY();
        double bwidth = legendBounds.getWidth();
        double bheight = legendBounds.getHeight();
       
        // usable canvas bounds
        int rlr = ruler.isVisible() ? Ruler.RULER_WIDTH : 0;
        Rectangle cb = new Rectangle(rlr, 0, cnvsSize.width - rlr,
                                             cnvsSize.height - rlr);
       
        // determine scale
        double sy = (cb.height - 2 * LEGEND_FRAME_PADDING) / bheight;
        s = Math.min(sy, 1);
       
        // determine translation
        bx *= s;
        by *= s;
       
        double xtarget = 0, ytarget = 0;
        switch(legendPos){
            case UPPER_LEFT:
                xtarget = cb.x + LEGEND_FRAME_PADDING;
                ytarget = cb.y + LEGEND_FRAME_PADDING;
                break;
            case UPPER_RIGHT:
                xtarget = cb.getMaxX() - bwidth - LEGEND_FRAME_PADDING;
                ytarget = cb.y + LEGEND_FRAME_PADDING;
                break;
            case LOWER_LEFT:
                xtarget = cb.x + LEGEND_FRAME_PADDING;
                ytarget = cb.getMaxY() - bheight - LEGEND_FRAME_PADDING;
                break;
            case LOWER_RIGHT:
                xtarget = cb.getMaxX() - bwidth - LEGEND_FRAME_PADDING;
                ytarget = cb.getMaxY() - bheight - LEGEND_FRAME_PADDING;
        }
       
        x = xtarget - bx;
        y = ytarget - by;
       
        // compile transform
        AffineTransform t = AffineTransform.getTranslateInstance(x, y);
        t.concatenate(AffineTransform.getScaleInstance(s, s));
       
        return t;
    }

    /**
     * @return the current plot object
     */
    public Plottable getPlotObject(){
        return plot;
    }
   
    /**
     * @param plot the object to plot
     * @param reset set true to reset the view upon showing the new plot
     */
    public void setPlotObject(Plottable plot, boolean reset) {
        if(this.plot == plot)
            return;
       
        this.plot = plot;
       
        if(plot != null)
            plot.setUpdateListener(this);
       
        if(reset)
            resetView();
        else
            setLegendPosition(legendPos); // updates legend and issues repaint
    }
   
    /**
     * Scales and translates the current plot to fill the canvas
     */
    public void resetView() {
       
        if(cnvsSize == null)// component is not yet visible
            return;
       
        ruler = new Ruler(cnvsSize);
       
        //reset transform
        transform = AffineTransform.getScaleInstance(1, 1);
        invTransform = transform;
           
        if(plot == null){
            updateCanvas();
            return;
        }
       
        // determine plot bounds and available space
        Rectangle2D pb = plot.getBounds(); //plot bounds
       
        Point pmin = new Point();
        Point pmax = new Point(cnvsSize.width, cnvsSize.height);
        if(ruler.isVisible()){
            pmin.translate(Ruler.RULER_WIDTH, 0);
            pmax.translate(0, -Ruler.RULER_WIDTH);
        }
       
        // update legend and subtract legend space from plot space
        if(plot.hasLegend()){
            legendBounds = plot.getLegendBounds();
            legendTransform = getLegendTransform(legendBounds);
           
            Shape tb = legendTransform.createTransformedShape(legendBounds);
            Rectangle lb = tb.getBounds();
           
            if(legendPos == UPPER_LEFT || legendPos == LOWER_LEFT)
                pmin.x = (int)lb.getMaxX();
            else if (legendPos == UPPER_RIGHT || legendPos == LOWER_RIGHT)
                pmax.x = (int)lb.getMinX();
        }

        Rectangle ups = new Rectangle(pmin); // usable plot space
        ups.add(pmax);
       

        double scale = Math.min((ups.getWidth() - 40.0) / pb.getWidth(),
                (ups.getHeight() - 40.0) / pb.getHeight());

        AffineTransform atS = AffineTransform.getScaleInstance(scale, -scale);
        pb = atS.createTransformedShape(pb).getBounds2D();

        double dx, dy;
        dx = ups.getCenterX() - pb.getCenterX();
        dy = ups.getCenterY() - pb.getCenterY();
       
        AffineTransform atT = AffineTransform.getTranslateInstance(dx, dy);
        atT.concatenate(atS);

        appendTransform(atT);
       
        updateCanvas();
    }
   
    private void translateView(double dx, double dy) {
        AffineTransform t = AffineTransform.getTranslateInstance(dx, dy);
        appendTransform(t);

        updateCanvas();
    }

    /**
     * Scales the current view around a given center
     * @param cx x coordinate of the scale center
     * @param cy y coordinate of the scale center
     * @param scale the scale factor
     */
    private void zoomView(double cx, double cy, double scale) {
        // move center of scaling (cx|cy) to (0|0)
        AffineTransform t1 = AffineTransform.getTranslateInstance(-cx, -cy);
        // scale
        AffineTransform ts = AffineTransform.getScaleInstance(scale, scale);
        // move back to original position
        AffineTransform t2 = AffineTransform.getTranslateInstance(cx, cy);

        t2.concatenate(ts);
        t2.concatenate(t1);

        appendTransform(t2);

        updateCanvas();
    }

    private void appendTransform(AffineTransform t) {
        t.concatenate(transform);
        transform = t;
       
        try {
            invTransform = t.createInverse();
        } catch (NoninvertibleTransformException e) {//shouldn't ever happen
            System.err.println("invertible transformation matrix!");
        }
    }

    /**
     * Issues a repaint of the canvas and updates the ruler if necessary.
     */
    private void updateCanvas() {
        if (ruler.isVisible()) {
            ruler.updateTicks(transform, invTransform);
        }
        canvas.repaint();
    }

    @Override
    public void update(String info) {
        if(info != null)
            infoBar.setInfo(info);
       
        setLegendPosition(legendPos);
    }

    public void setInfo(String info){
        infoBar.setInfo(info);
    }

    public void setLegendPosition (int legendPos) {
        if(legendPos < 1 || legendPos > 4)
            throw new IllegalArgumentException("Illegal legend position!");
       
        this.legendPos = legendPos;
       
        if(plot.hasLegend() && cnvsSize != null){ // if cnvsIze is null the canvas is not visible
            legendBounds = plot.getLegendBounds();
            legendTransform = getLegendTransform(legendBounds);
        }
       
        canvas.repaint();
    }
   
   
   
}
TOP

Related Classes of bs.bs2d.gui.plot.PlotPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.