'How to dynamically resize an svg in javafx according to the size of the region

I'm keen on svg and would like to put many of them in my User Interface. But I have a problem with the size of svg. I would like to load any svg I retrieve as a parameter and resize it dynamically to the size of the control. All the examples I found are resize thanks to the "rescale" method (as found in the following article JavaFX: How to resize button containing svg image.

But since I have no idea of the size of the original svg I don't know what factor to apply in the rescale method. So, my question is how do I generify the following code:

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;

public class Main extends Application{
private final int MIN_BUTTON_SIZE = 10;

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

@Override
public void start(Stage primaryStage) throws Exception {
    HBox root = new HBox();
    root.setAlignment(Pos.CENTER);
    SVGPath svg = new SVGPath();
    svg.setContent("M87.5,50.002C87.5,29.293,70.712,12.5,50,12.5c-20.712,0-37.5,16.793-37.5,37.502C12.5,70.712,29.288,87.5,50,87.5" +
            "c6.668,0,12.918-1.756,18.342-4.809c0.61-0.22,1.049-0.799,1.049-1.486c0-0.622-0.361-1.153-0.882-1.413l0.003-0.004l-6.529-4.002" +
    "L61.98,75.79c-0.274-0.227-0.621-0.369-1.005-0.369c-0.238,0-0.461,0.056-0.663,0.149l-0.014-0.012" +
    "C57.115,76.847,53.64,77.561,50,77.561c-15.199,0-27.56-12.362-27.56-27.559c0-15.195,12.362-27.562,27.56-27.562" +
    "c14.322,0,26.121,10.984,27.434,24.967C77.428,57.419,73.059,63,69.631,63c-1.847,0-3.254-1.23-3.254-3.957" +
    "c0-0.527,0.176-1.672,0.264-2.111l4.163-19.918l-0.018,0c0.012-0.071,0.042-0.136,0.042-0.21c0-0.734-0.596-1.33-1.33-1.33h-7.23" +
    "c-0.657,0-1.178,0.485-1.286,1.112l-0.025-0.001l-0.737,3.549c-1.847-3.342-5.629-5.893-10.994-5.893" +
    "c-10.202,0-19.877,9.764-19.877,21.549c0,8.531,5.101,14.775,13.632,14.775c4.75,0,9.587-2.727,12.665-7.035l0.088,0.527" +
    "c0.615,3.342,9.843,7.576,15.121,7.576c7.651,0,16.617-5.156,16.617-19.932l-0.022-0.009C87.477,51.13,87.5,50.569,87.5,50.002z" +
    "M56.615,56.844c-1.935,2.727-5.101,5.805-9.763,5.805c-4.486,0-7.212-3.166-7.212-7.738c0-6.422,5.013-12.754,12.049-12.754" +
    "c3.958,0,6.245,2.551,7.124,4.486L56.615,56.844z");

    Button buttonWithGraphics = new Button();
    buttonWithGraphics.setGraphic(svg);

    // Bind the Image scale property to the buttons size
    svg.scaleXProperty().bind(buttonWithGraphics.widthProperty().divide(100));
    svg.scaleYProperty().bind(buttonWithGraphics.heightProperty().divide(100));

    // Declare a minimum size for the button
    buttonWithGraphics.setMinSize(MIN_BUTTON_SIZE, MIN_BUTTON_SIZE);

    root.getChildren().addAll(buttonWithGraphics);
    root.layoutBoundsProperty().addListener((observableValue, oldBounds, newBounds) -> {
            double size = Math.max(MIN_BUTTON_SIZE, Math.min(newBounds.getWidth(), newBounds.getHeight()));
            buttonWithGraphics.setPrefSize(size, size);
        }
    );

    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.show();
}

I guess this is linked with the following lines:

 svg.scaleXProperty().bind(buttonWithGraphics.widthProperty().divide(100));


Solution 1:[1]

  1. create a resizable canvas, you can find details here
  2. canvas can be scaled, and also graphic context can also be scale
var gc = canvas.getGraphicsContext2D();
gc.scale(0.1, 0.1);
  1. use gc to draw the svg path, line, circle, etc.

sample code here:

    var canvas = new ResizableCanvas() {
      @Override
      public void draw() {
        var gc = getGraphicsContext2D();
        gc.save();//make sure you save the status here and restore after all operations are finished
        //System.out.print(getWidth()+" ");
        //System.out.println(getHeight());
        var width = getWidth();
        var height = getHeight();
        gc.clearRect(0,0,width, height);
        gc.scale(width/512.002, height/512.002);

        gc.beginPath();
        gc.setFill(Color.web("#2D4961"));
        gc.appendSVGPath("""
          M399.994,0H112.008C94.337,0,80.009,14.327,80.009,31.999v342.624
          c0.08,16.159,8.288,31.191,21.839,39.998l145.433,94.796c5.304,3.448,12.135,3.448,17.439,0l145.433-94.556
          c13.551-8.808,21.759-23.839,21.839-39.998V31.999C431.993,14.327,417.665,0,399.994,0z M399.994,68.477
          c-6.872-6.24-15.399-10.352-24.559-11.839c-1.496-9.2-5.64-17.759-11.919-24.639h36.478V68.477z M148.486,31.999
          c-6.264,6.864-10.408,15.391-11.919,24.559c-9.168,1.512-17.695,5.656-24.559,11.919V31.999H148.486z M256.001,476.858
          l-26.479-17.199c11.047-4.6,20.327-12.623,26.479-22.879c6.152,10.256,15.431,18.279,26.479,22.879L256.001,476.858z
           M399.994,374.622c0.008,5.424-2.728,10.48-7.28,13.439l-91.756,59.917c-20.895-1.592-37.022-19.039-36.958-39.998
          c0-4.416-3.584-8-8-8s-8,3.584-8,8c0.064,20.959-16.063,38.406-36.958,39.998l-91.756-59.917c-4.552-2.96-7.288-8.016-7.28-13.439
          V103.995c0-17.671,14.327-31.998,31.998-31.998c4.416,0,8-3.584,8-8c0-17.671,14.327-31.999,31.999-31.999h143.993
          c17.671,0,31.999,14.327,31.999,31.999c0,4.416,3.584,8,8,8c17.671,0,31.999,14.327,31.999,31.998L399.994,374.622L399.994,374.622z""");
        gc.fill();
        gc.setFill(Color.web("#44637F"));
        gc.beginPath();
        gc.appendSVGPath("""
          M80.009,31.999v271.987l0,0c8.84,0,15.999-7.16,15.999-15.999V31.999
          c0-8.84,7.16-15.999,15.999-15.999h271.987c8.84,0,15.999-7.16,15.999-15.999H112.008C94.329,0,80.009,14.327,80.009,31.999z""");
        gc.fill();
        gc.setFill(Color.web("#123247"));
        gc.beginPath();
        gc.appendSVGPath("""
          M410.154,414.861c13.551-8.808,21.759-23.839,21.839-39.998V55.997l0,0
          c-8.84,0-15.999,7.16-15.999,15.999v304.466c0,8.04-4.024,15.551-10.719,19.999L269.28,487.097
          c-8.304,5.56-13.287,14.887-13.279,24.879l0,0c3.096,0.008,6.12-0.88,8.72-2.56L410.154,414.861z""");
        gc.fill();
        gc.restore();
      }
    };

    canvas.widthProperty().bind(canvas.heightProperty());
    canvas.heightProperty().bind(stage.getScene().heightProperty().multiply(0.1));

Solution 2:[2]

The solution above tries to do it dynamically, although (as you said) fails to do it in respect to the original SvgPath size.

I would recommend doing it like that:

double size = 30;
svg.setScaleX(size / svg.boundsInLocalProperty().get().getWidth());
svg.setScaleY(size / svg.boundsInLocalProperty().get().getHeight());

This will scale your SvgPath to size.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Neuron - Freedom for Ukraine