canvassvgjavafxgraphicscontext

JavaFX: How to use the GraphicsContext method appendSVGPath(String svgpath)


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?


Solution

  • 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();
        }
    }