We are having a school project, where we are drawing a highly detailed map on a canvas using JavaFX and integrating Swing via JFXPanel. Everytime we open the application the canvas is black until either resized or any interaction with the canvas has taken place, for instance panning or zooming. I have been through the entire internet searching the error, but unfortunatly without luck.
Code Snippet:
public class CanvasViewNew extends Application {
private AnchorPane rootLayout;
private Stage primaryStage;
private Canvas canvas;
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
Model model = new Model("Data/Data/cph.zip");
canvas = new Canvas(model);
new MouseController(canvas, model);
SwingNode swingNode = new SwingNode();
rootLayout = new AnchorPane();
createSwingContent(swingNode);
//Sets canvas to a prefered size.
canvas.setPreferredSize(new Dimension(1000, 1000));
//Creates and sets the scene to an AnchorPane.
Scene scene = new Scene(rootLayout);
//Adds the swingnode to the RootLayout.
rootLayout.getChildren().addAll(swingNode);
System.out.println(swingNode.getScene());
primaryStage.setScene(scene);
primaryStage.show();
rootLayout.requestFocus();
swingNode.requestFocus();
swingNode.autosize();
swingNode.resize(1000,1000);
//Calls the panning and zoom methods in canvas, which enables the zooming and panning on canvas.
canvas.pan(-model.getMinLon(), -model.getMaxLat());
canvas.zoom((primaryStage.getWidth()) + 200 / (model.getMaxLon() - model.getMinLon()), 0, 0);
canvas.zoomFactor = primaryStage.getWidth() / (model.getMaxLon() - model.getMinLon());
canvas.minZoom = canvas.zoomFactor / 4;
canvas.maxZoom = canvas.zoomFactor * 200;
}
private void createSwingContent(SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
// AnchorPane canvasPane = adjustSwingNode(swingNode);
swingNode.setContent(canvas);
});
}
public static void main(String args[]) {
launch(args);
}
.
public class Canvas extends JFXPanel implements Observer {
private final Model model;
private boolean useAntiAliasing = false;
private AffineTransform transform = new AffineTransform();
private boolean drawingModeEnabled = false;
private final String drawingModeMessage = "Drawing Mode enabled";
private double fps = 0.0;
private KDTree.Rect searchRect;
private KDTreePath.Rect searchRectway;
private DrawTreeSplits splits;
public double maxZoom;
public double minZoom;
public double zoomFactor;
public Canvas(Model m) {
this.model = m;
model.addObserver(this);
splits = new DrawTreeSplits(model.getWayTree(), model.getMinLon(), model.getMaxLon(), model.getMinLat(), model.getMaxLat());
repaint();
}
@Override
public void paint(Graphics _g) {
long t1 = System.nanoTime();
Graphics2D g = (Graphics2D) _g;
g.setStroke(new BasicStroke(Float.MIN_VALUE));
if (drawingModeEnabled) {
int width = g.getFontMetrics().stringWidth(drawingModeMessage);
int height = g.getFontMetrics().getHeight();
// draw string in red, reset to black afterwards.
g.setPaint(Color.red);
g.drawString(drawingModeMessage, getWidth() - width - 20, getHeight() - height - 10);
g.setPaint(Color.black);
}
Rectangle2D viewRect = new Rectangle2D.Double(0, 0, getWidth(), getHeight());
//Draw methods
g.setBackground(new Color(152, 152, 152));
g.setPaint(new Color(60, 149, 255));
g.fill(viewRect);
g.transform(transform);
try {
viewRect = transform.createInverse().createTransformedShape(viewRect).getBounds2D();
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
if (useAntiAliasing) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
//draw split lines for FUN
//draw Coastlines
g.setPaint(new Color(237, 237, 237));
for (Shape coastline : model.get(OSMWayType.COASTLINE)) {
if (coastline.intersects(viewRect)) {
g.fill(coastline);
}
}
//draw unknown lines
/* g.setStroke(new BasicStroke(0.00001f));
g.setPaint(new Color(0, 0, 0));
for (Shape line : model.get(OSMWayType.UNKNOWN)) {
if (line.intersects(viewRect)) {
g.draw(line);
}
}*/
searchRect = new KDTree.Rect(viewRect.getMinX(), viewRect.getMinY(), viewRect.getMaxX(), viewRect.getMaxY());
searchRectway = new KDTreePath.Rect(viewRect.getMinX(), viewRect.getMinY(), viewRect.getMaxX(), viewRect.getMaxY());
if (zoomFactor > 2300)
drawLandScapes(g);
if (zoomFactor > 5000)
drawOutlines(g);
if (zoomFactor > 10000) {
drawStructures(g);
drawCityDetails(g);
}
if (zoomFactor > 7500)
drawCityRoads(g);
if (zoomFactor > 28000)
drawCitySmallDetails(g);
if (zoomFactor > 100)
drawMainRoads(g);
if (zoomFactor > 15000)
drawCitySmallRoads(g);
if (zoomFactor > 35000)
drawPoints(g);
//splits.paint(g);
long t2 = System.nanoTime();
fps = (fps + 1e9 / (t2 - t1)) / 2;
g.setTransform(new AffineTransform());
g.setColor(Color.WHITE);
g.fillRect(5, 5, 80, 20);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g.setColor(Color.BLACK);
g.drawRect(5, 5, 80, 20);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawString(String.format("FPS: %.1f", fps), 10, 20);
}
private void drawMainRoads(Graphics2D g) {
for (OSMWayPath shape : model.getHighWayTree().rangeSearch(searchRectway)) {
//draw Highways
if (shape.getType() == OSMWayType.HIGHWAY) {
g.setStroke(new BasicStroke(0.00005f));
g.setPaint(new Color(182, 63, 61));
g.draw(shape);
}
//draw secondary highways
if (shape.getType() == OSMWayType.SECONDARYHIGHWAY) {
g.setStroke(new BasicStroke(0.0002f));
g.setPaint(new Color(214, 183, 25));
g.draw(shape);
}
//draw tertiary roads
if (shape.getType() == OSMWayType.TERTIARY && zoomFactor > 400) {
g.setStroke(new BasicStroke(0.0002f));
g.setPaint(new Color(0, 255, 122));
g.draw(shape);
}
}
}
private void drawOutlines(Graphics2D g) {
for (OSMWayPath shape : model.getWayTree().rangeSearch(searchRectway)) {
//draw residential area
if (shape.getType() == OSMWayType.RESIDENTIALAREA) {
g.setPaint(new Color(115, 115, 121));
g.fill(shape);
}
//draw industrial area
if (shape.getType() == OSMWayType.INDUSTRIALAREA) {
g.setPaint(new Color(95, 94, 95));
g.fill(shape);
}
}
}
private void drawLandScapes(Graphics2D g) {
for (OSMWayPath shape : model.getWayTree().rangeSearch(searchRectway)) {
//draw water
if (shape.getType() == OSMWayType.WATER) {
g.setPaint(new Color(60, 149, 255));
g.fill(shape);
}
//draw forests
if (shape.getType() == OSMWayType.FOREST) {
g.setPaint(new Color(0, 102, 2));
g.fill(shape);
}
//draw beaches
if (shape.getType() == OSMWayType.BEACH) {
g.setPaint(new Color(194, 178, 128));
g.fill(shape);
}
//draw grass
if (shape.getType() == OSMWayType.GRASS) {
g.setPaint(new Color(0, 249, 2));
g.fill(shape);
}
//draw sand areas
if (shape.getType() == OSMWayType.SAND) {
g.setPaint(new Color(194, 178, 128));
g.fill(shape);
}
//draw nature reserves
if (shape.getType() == OSMWayType.NATURERESERVE) {
g.setPaint(new Color(0, 203, 2));
g.fill(shape);
}
//draw woods
if (shape.getType() == OSMWayType.WOOD) {
g.setPaint(new Color(0, 156, 2));
g.fill(shape);
}
//draw waterways
if (shape.getType() == OSMWayType.WATERWAY) {
g.setStroke(new BasicStroke(0.00004f));
g.setPaint(new Color(60, 149, 255));
g.draw(shape);
}
//draw golf courses
if (shape.getType() == OSMWayType.GOLF) {
g.setPaint(new Color(78, 156, 0));
g.fill(shape);
}
}
}
private void drawPoints(Graphics2D g) {
//draw points
for (OSMPoint point : model.getPointTree().rangeSearch(searchRect)) {
g.setPaint(new Color(0, 11, 255));
if (point.getType() == OSMNodeType.STATION) {
Rectangle2D.Double rect = new Rectangle2D.Double(point.getX(), point.getY(), 0.00010, 0.00010);
g.fill(rect);
}
// draw cafes as points
if (point.getType() == OSMNodeType.CAFE) {
g.setPaint(new Color(211, 104, 16));
Ellipse2D.Double cafe = new Ellipse2D.Double(point.getX(), point.getY(), 0.00004, 0.00004);
g.fill(cafe);
}
//draw shops as points
if (point.getType() == OSMNodeType.SHOP) {
g.setPaint(new Color(31, 211, 17));
Ellipse2D.Double shop = new Ellipse2D.Double(point.getX(), point.getY(), 0.00004, 0.00004);
g.fill(shop);
}
//draw shops as points
if (point.getType() == OSMNodeType.EATINGPLACE) {
g.setPaint(new Color(47, 211, 210));
Ellipse2D.Double eat = new Ellipse2D.Double(point.getX(), point.getY(), 0.00004, 0.00004);
g.fill(eat);
}
}
}
private void drawCityRoads(Graphics2D g) {
for (OSMWayPath shape : model.getWayTree().rangeSearch(searchRectway)) {
if (shape.getType() == OSMWayType.RESIDENTIAL) {
g.setStroke(new BasicStroke(0.00002f));
g.setPaint(new Color(255, 255, 255));
g.draw(shape);
}
//draw railroad
if (shape.getType() == OSMWayType.RAIL) {
g.setStroke(new BasicStroke(0.00003f));
g.setPaint(new Color(198, 228, 26));
g.draw(shape);
}
}
}
private void drawCitySmallRoads(Graphics2D g) {
for (OSMWayPath shape : model.getWayTree().rangeSearch(searchRectway)) {
//draw normal roads
if (shape.getType() == OSMWayType.ROAD) {
g.setStroke(new BasicStroke(0.00003f));
g.setPaint(new Color(255, 255, 255));
g.draw(shape);
}
//draw metro lines
if (shape.getType() == OSMWayType.METRO) {
//g.setStroke(new BasicStroke(0.00005f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 0.00007f, new float[]{0.00012f}, 0.0005f));
g.setStroke(new BasicStroke(0.00005f));
g.setPaint(new Color(194, 0, 7));
g.draw(shape);
}
//draw bike roads
if (shape.getType() == OSMWayType.BIKE) {
//g.setStroke(new BasicStroke(0.00002f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0.00002f, new float[]{0.00003f}, 0f));
g.setStroke(new BasicStroke(0.00001f));
g.setPaint(new Color(19, 75, 214));
g.draw(shape);
}
//draw footway roads
if (shape.getType() == OSMWayType.FOOTWAY) {
//g.setStroke(new BasicStroke(0.00001f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0.00003f, new float[]{0.00003f}, 0f));
g.setStroke(new BasicStroke(0.00001f));
g.setPaint(new Color(214, 48, 46));
g.draw(shape);
}
//draw paths
if (shape.getType() == OSMWayType.PATH) {
g.setStroke(new BasicStroke(0.00001f));
g.setPaint(new Color(214, 48, 46));
g.draw(shape);
}
}
}
private void drawCityDetails(Graphics2D g) {
for (OSMWayPath shape : model.getCityDetailsTree().rangeSearch(searchRectway)) {
//draw allotments
if (shape.getType() == OSMWayType.ALLOTMENTS) {
g.setPaint(new Color(141, 195, 30));
g.fill(shape);
}
//draw parks
if (shape.getType() == OSMWayType.PARK) {
g.setPaint(new Color(29, 195, 0));
g.fill(shape);
}
//draw gardens
if (shape.getType() == OSMWayType.GARDEN) {
g.setPaint(new Color(117, 195, 16));
g.fill(shape);
}
//draw parkingLots
if (shape.getType() == OSMWayType.PARKING) {
g.setPaint(new Color(55, 70, 132));
g.fill(shape);
}
}
}
private void drawCitySmallDetails(Graphics2D g) {
for (OSMWayPath shape : model.getCityDetailsTree().rangeSearch(searchRectway)) {
//draw pitches (sporting area)
if (shape.getType() == OSMWayType.PITCH) {
g.setPaint(new Color(138, 169, 182));
g.fill(shape);
}
//draw Piers
if (shape.getType() == OSMWayType.PIER) {
g.setPaint(new Color(147, 80, 25));
g.fill(shape);
}
//draw Piers
if (shape.getType() == OSMWayType.PLAYGROUND) {
g.setPaint(new Color(203, 123, 10));
g.fill(shape);
}
}
}
private void drawStructures(Graphics2D g) {
//draw buildings
g.setStroke(new BasicStroke(0.00001f));
for (OSMWayPath shape : model.getWayTree().rangeSearch(searchRectway)) {
if (shape.getType() == OSMWayType.BUILDING) {
g.setPaint(new Color(144, 144, 150));
g.fill(shape);
}
//draw bridges
if (shape.getType() == OSMWayType.BRIDGE) {
g.setPaint(new Color(146, 142, 149));
g.fill(shape);
}
}
}
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
*/
@Override
public void update(Observable o, Object arg) {
repaint();
}
public void toggleAntiAliasing() {
useAntiAliasing = !useAntiAliasing;
repaint();
}
public void pan(double dx, double dy) {
transform.preConcatenate(AffineTransform.getTranslateInstance(dx, dy));
repaint();
}
public void zoomToCenter(double factor) {
zoom(factor, -getWidth() / 2, -getHeight() / 2);
}
public void zoom(double factor, double x, double y) {
if (factor < 1 && zoomFactor < minZoom) {
System.out.println("You can't zoom anymore");
} else if (factor > 1 && zoomFactor > maxZoom) {
System.out.println("You can't zoom anymore");
} else {
zoomFactor *= factor;
System.out.println(zoomFactor);
pan(x, y);
transform.preConcatenate(AffineTransform.getScaleInstance(factor, factor));
pan(-x, -y);
repaint();
}
}
public void toggleDrawingMode() {
drawingModeEnabled = !drawingModeEnabled;
}
public boolean inDrawingMode() {
return drawingModeEnabled;
}
public Point2D toModelCoords(Point2D p) {
try {
return transform.inverseTransform(p, null);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return null;
}
Thanks for the help!