Rudy Gamberini
Rudy Gamberini

Reputation: 25

JavaFX using a SVGPath as a mask

I'm having issues trying to use an SVGPath to clip another node, for example the following code:

Rectangle rectangle = new Rectangle(430, 80);
rectangle.setFill(Paint.valueOf("FF0000"));
SVGPath path = new SVGPath();
path.setContent("m 131.07143,433.07649 c 359.64286,0 360,0.35714 360,0.35714 l 4.28571,1.07143 5.71429,2.5 4.64286,2.85714 4.64285,5 4.64286,7.14286 1.42857,4.28572 1.42857,7.5 -1.07142,10 -1.42858,4.64285 -3.21428,5 -4.64286,5.35715 -5.35714,3.57142 -6.42857,2.85715 -2.85715,1.07143 -3.92857,0.71428 -360.35714,0 -3.21429,-1.07143 -3.92857,-1.42857 -3.57143,-1.78571 -5.71428,-3.30358 -3.21429,-3.48214 -2.05357,-2.67857 -2.67857,-4.28571 -0.98214,-2.76786 -1.69643,-4.01786 -0.44643,-4.375 0.0893,-4.46428 0.35715,-4.375 0.17857,-2.41072 1.60714,-3.57143 1.42857,-3.57143 1.60715,-2.41071 2.32142,-3.03571 2.94643,-3.39286 3.75,-2.67857 3.48215,-1.96429 5.26785,-2.32143 3.57143,-0.44643 z");
primaryStage.setScene(new Scene(new VBox(rectangle, path)));

Results in the SVG being drawn underneath the rectangle correctly. However once I try to clip the rectangle by changing the last line to

rectangle.setClip(path);
primaryStage.setScene(new Scene(new VBox(rectangle)));`

Results in the rectangle being completely hidden. Does anyone know what I might be able to do?

Upvotes: 1

Views: 721

Answers (1)

jewelsea
jewelsea

Reputation: 159290

VBox is a layout manager, it will change the layout of added components. If you place your objects in a Group (which does no layout) instead of a VBox, you will see that that rectangle shape and your SVGPath, don't intersect (the SVGPath is located approximately 100 pixels to the right and four hundred pixels below the rectangle, according to your definition of the path).

You can translate the SVGPath so that it intersects the rectangle and clips it.

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

public class SVGMasker extends Application {    
    @Override
    public void start(Stage stage) throws Exception {
        Rectangle rectangle = new Rectangle(430, 80, Color.RED);
        SVGPath path = new SVGPath();
        path.setContent("m 131.07143,433.07649 c 359.64286,0 360,0.35714 360,0.35714 l 4.28571,1.07143 5.71429,2.5 4.64286,2.85714 4.64285,5 4.64286,7.14286 1.42857,4.28572 1.42857,7.5 -1.07142,10 -1.42858,4.64285 -3.21428,5 -4.64286,5.35715 -5.35714,3.57142 -6.42857,2.85715 -2.85715,1.07143 -3.92857,0.71428 -360.35714,0 -3.21429,-1.07143 -3.92857,-1.42857 -3.57143,-1.78571 -5.71428,-3.30358 -3.21429,-3.48214 -2.05357,-2.67857 -2.67857,-4.28571 -0.98214,-2.76786 -1.69643,-4.01786 -0.44643,-4.375 0.0893,-4.46428 0.35715,-4.375 0.17857,-2.41072 1.60714,-3.57143 1.42857,-3.57143 1.60715,-2.41071 2.32142,-3.03571 2.94643,-3.39286 3.75,-2.67857 3.48215,-1.96429 5.26785,-2.32143 3.57143,-0.44643 z");
        path.setTranslateX(-path.getBoundsInLocal().getMinX());
        path.setTranslateY(-path.getBoundsInLocal().getMinY());
        rectangle.setClip(new Group(path));
        System.out.println(path.getBoundsInLocal());
        stage.setScene(new Scene(new Group(rectangle)));
        stage.show();
    }

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

Output is as below (note the minX and minY values for the rectangle which are used for the negative translation):

BoundingBox [minX:101.07147979736328, minY:433.07647705078125, minZ:0.0, width:416.78570556640625, height:63.9285888671875, depth:0.0, maxX:517.8571853637695, maxY:497.00506591796875, maxZ:0.0]

clip

Upvotes: 2

Related Questions