package org.jogamp.glg2d; import java.awt.BasicStroke; 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.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.QuadCurve2D; import java.awt.geom.RoundRectangle2D; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; @SuppressWarnings("serial") public class GraphTest extends JFrame { Random random = new Random(); AffineTransform transform = new AffineTransform(); long repaintCount; long firstRepaint; GraphTest() { final List<Vertex> vertices = makeVertices(1000, new Rectangle(1024, 768)); final List<Edge> edges = makeEdges(vertices, 2); JPanel paintingComponent = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); GraphTest.this.paint(vertices, edges, (Graphics2D) g); g.setColor(Color.LIGHT_GRAY); g.fillRect(45, getHeight() - 65, 70, 20); g.setColor(Color.BLACK); g.drawString(String.format("FPS: %.2f", getFPS()), 50, getHeight() - 50); } }; paintingComponent.setOpaque(true); // setContentPane(paintingComponent); setContentPane(new GLG2DCanvas(paintingComponent)); MouseHandler handler = new MouseHandler(); getContentPane().addMouseListener(handler); getContentPane().addMouseMotionListener(handler); getContentPane().addMouseWheelListener(handler); new Timer(10, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { getContentPane().repaint(); } }).start(); } private double getFPS() { if (firstRepaint == 0) { firstRepaint = System.currentTimeMillis(); repaintCount = 0; return 0; } repaintCount++; long now = System.currentTimeMillis(); double time = now - firstRepaint; return repaintCount / (time / 1000); } public static void main(String[] args) throws Exception { JFrame test = new GraphTest(); test.setTitle("Graph Test"); test.setPreferredSize(new Dimension(1024, 768)); test.pack(); test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); test.setLocationRelativeTo(null); test.setVisible(true); } public void paint(List<Vertex> vertices, List<Edge> edges, Graphics2D g2d) { g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (Edge edge : edges) { edge.paint(g2d); } for (Vertex vertex : vertices) { vertex.paint(g2d); } } List<Vertex> makeVertices(int count, Rectangle bounds) { int border = 30; List<Vertex> vertices = new ArrayList<Vertex>(count); for (int i = 0; i < count; i++) { Point position = new Point( random.nextInt(bounds.width - border * 2) + border, random.nextInt(bounds.height - border * 2) + border); String name = String.valueOf(random.nextLong()); vertices.add(new Vertex(name, position)); } return vertices; } List<Edge> makeEdges(List<Vertex> vertices, double density) { int numEdges = (int) (vertices.size() * density); List<Edge> edges = new ArrayList<Edge>(numEdges); for (int i = 0; i < numEdges; i++) { Vertex from = vertices.get(random.nextInt(vertices.size())); Vertex to = vertices.get(random.nextInt(vertices.size())); if (from == to) { i--; continue; } else { edges.add(new Edge(from, to)); } } return edges; } class Vertex { String name; Point position; Vertex(String name, Point position) { this.name = name; this.position = position; } Point getPosition() { Point pt = new Point(); transform.transform(position, pt); return pt; } void paint(Graphics2D g2d) { g2d.setStroke(new BasicStroke(3)); int width = g2d.getFontMetrics().stringWidth(name); int height = g2d.getFontMetrics().getHeight(); int border = 5; Point pt = getPosition(); RoundRectangle2D shape = new RoundRectangle2D.Float( pt.x - width / 2 - border, pt.y - height - border, width + border * 2, height + border * 2, border, border); g2d.setColor(new Color(14, 180, 255, 180)); g2d.fill(shape); g2d.setColor(Color.DARK_GRAY); g2d.draw(shape); g2d.drawString(name, pt.x - width / 2, pt.y); } } static class Edge { Vertex from; Vertex to; Edge(Vertex from, Vertex to) { this.from = from; this.to = to; } void paint(Graphics2D g2d) { Point fromPt = from.getPosition(); Point toPt = to.getPosition(); AffineTransform xform = AffineTransform.getTranslateInstance(fromPt.x, fromPt.y); float dx = toPt.x - fromPt.x; float dy = toPt.y - fromPt.y; float thetaRadians = (float) Math.atan2(dy, dx); xform.rotate(thetaRadians); float dist = (float) Math.sqrt(dx * dx + dy * dy); xform.scale(dist, 1.0); QuadCurve2D curve = new QuadCurve2D.Float(0, 0, 0, 1, 1, 1); Shape shape = xform.createTransformedShape(curve); g2d.setColor(Color.black); g2d.setStroke(new BasicStroke(2)); g2d.draw(shape); } } class MouseHandler extends MouseAdapter implements MouseWheelListener { Point firstPoint; @Override public void mouseWheelMoved(MouseWheelEvent e) { double scale = e.getWheelRotation() * 1.5; if (scale > 0) { scale = 1 / scale; } else { scale = -scale; } Point dst = e.getPoint(); transform.transform(e.getPoint(), dst); AffineTransform xform = AffineTransform.getTranslateInstance(dst.x, dst.y); xform.scale(scale, scale); xform.translate(-dst.x, -dst.y); transform.preConcatenate(xform); repaint(); } @Override public void mousePressed(MouseEvent e) { firstPoint = null; if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) { firstPoint = e.getPoint(); } } @Override public void mouseDragged(MouseEvent e) { if (firstPoint != null && (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) { Point dst = new Point(); try { transform.inverseTransform(firstPoint, firstPoint); transform.inverseTransform(e.getPoint(), dst); } catch (NoninvertibleTransformException ex) { ex.printStackTrace(); } int dx = dst.x - firstPoint.x; int dy = dst.y - firstPoint.y; transform.translate(dx, dy); firstPoint = e.getPoint(); } repaint(); } @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { if (e.getButton() == MouseEvent.BUTTON1) { transform.scale(2, 2); } else { transform.scale(.5, .5); } } repaint(); } } }