1

I'm working on a project that makes use of SVG's. Currently the program has the SVG's stored as SVGPath objects in an FXML file. The file is then loaded into a Group which is then added to the screen. In the FXML file, there are approximately 300 such SVGPaths. Which I believe ultimately means that there are 300 nodes on the scene graph.

I'm going to eventually have to scale up the number of SVGPath and am having concerns about putting more nodes on the scene, so I began to look at using a Cavas/GraphicsContext instead.

GraphicsContext has a method appendSVGPath(String svgpath) that I think I could use to draw my SVGs on the cavas, but am not having any luck getting them to appear.

I'm using the CanvasTest.java file from Oracle as starting point: http://docs.oracle.com/javafx/2/canvas/jfxpub-canvas.htm

I modified the file to include the following method:

private void appendSVG(GraphicsContext gc) {
     SVGPath svg = new SVGPath();
     svg.setContent("M 100 100 L 300 100 L 200 300 z");
     svg.setFill(Color.RED);
     svg.setStroke(Color.BLUE);
     gc.appendSVGPath(svg.getContent());
}

But I can't get the shape to appear on the canvas.

Full test code here:

package canvastest;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;

public class CanvasTest extends Application {

private Canvas canvas = new Canvas(200, 200);
private GraphicsContext gc = canvas.getGraphicsContext2D();
private Group root = new Group();

public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) {
    primaryStage.setTitle("Canvas Test");

    appendSVG(gc);

//        SVGPath svg = new SVGPath();
//        svg.setContent("M 100 100 L 300 100 L 200 300 z");
//        svg.setFill(Color.RED);
//        svg.setStroke(Color.BLUE);

    root.getChildren().add(root);
    primaryStage.setScene(new Scene(root, 400, 400));
    primaryStage.show();
}

private void appendSVG(GraphicsContext gc) {
    SVGPath svg = new SVGPath();
    svg.setContent("M 100 100 L 300 100 L 200 300 z");
    svg.setFill(Color.RED);
    svg.setStroke(Color.BLUE);
    gc.appendSVGPath(svg.getContent());
}
}

If I uncomment out the SVG section from start, and just add the svg to root, the svg will display.

Has anyone had any success using appendSVGPath?

ectobar
  • 13
  • 1
  • 4
  • This comment is a little off-topic for the question, but just mentioned in case you want to consider a different approach (which I am not even saying is a better one - just different). If the only reason you are using Canvas is because you are concerned about the number of nodes, you could instead add your shapes to an off-screen scene, and snapshot that to an Image and just render that image into an ImageView - then JavaFX doesn't have to deal with managing all those nodes on an on-going basis, it would just be a a one-time thing to initially render and snapshot the nodes. – jewelsea Jun 04 '15 at 08:01
  • In this case it might be easier to just enable caching of your Group node. You can tune the caching behaviour even further by providing an appropriate cache hint. This helped me a lot in the past and is much easier than switching to one of the other mentioned options. – mipa Jun 04 '15 at 08:55

1 Answers1

2

Canvas isn't like the scene graph, stroking and filling paths does not happen automatically. Instead you need to feed your path segments to the canvas, then explicitly call fill() or stroke() to have those operations applied. For more information, see the "path rendering" section at the front of the GraphicsContext javadoc.

svgpath

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class CanvasTest extends Application {

    private Canvas canvas = new Canvas(200, 200);
    private GraphicsContext gc = canvas.getGraphicsContext2D();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        appendSVG(gc);

        stage.setScene(new Scene(new Group(canvas)));
        stage.show();
    }

    private void appendSVG(GraphicsContext gc) {
        gc.setFill(Color.RED);
        gc.setStroke(Color.BLUE);
        gc.appendSVGPath("M 50 50 L 150 50 L 100 150 z");
        gc.fill();
        gc.stroke();
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406