I am using JavaFX to render some SVG stuff. I defined many methods, returning the paths of different SVG shapes (ellipsis, circle, rectangle, lines, etc). All of them seem to work, except the line method. JavaFX doesn't return an error (meaning that the path is probably correct), yet it doesn't draw anything. Here is my method.
public static SVGPath line(float startX, float endX, float startY, float endY, PositionType positionType)
{
SVGPath path = new SVGPath();
path.setContent(positionType.getMoveto()+startX+","+startY+positionType.getLineto("l")+endX+","+endY);
return path;
}
The method getMoveto()
returns either M
or m
, depending on the PositionType
, and getLineto()
returns either L
or l
.
Here is a sample method call :
SVGPath test2 = SVGPrimitives.line(20f, 30.1f, 23f, 89.21f, PositionType.ABSOLUTE);
And here is the path that's returned :
M20.0,23.0 L 30.1,89.21
It does seem valid to me, yet nothing is drawn...
An SVGPath
containing a single line encloses no area, so no pixels will be rendered. To see the effect, you can use setStroke()
on the path, which "Defines parameters of a stroke that is drawn around the outline of a Shape
."
root.getChildren().addAll(line(32), line(48), line(64));
…
private SVGPath line(int size) {
SVGPath path = new SVGPath();
path.setStroke(Color.BLUE);
path.setContent("M0,0L" + size + "," + size + "z");
return path;
}
The same applies to more complex paths shown here. In the example below, note the following
A path can be scaled as a function of the size
; a slightly different effect can be achieved by altering the scale of the enclosing Pane
, as shown here.
As an aid in composition, Java 8 makes it easier to pass a function as a parameter, as suggested here.
More complex paths can be constructed using an available SVG editor.
Finally, "Consider a builder when faced with many constructor parameters."
import java.util.function.IntFunction;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;
/**
* @see http://www.w3.org/TR/SVG/paths.html
* @see http://raphaeljs.com/icons/
*/
public class SVGIcons extends Application {
private static final int SIZE = 16;
@Override
public void start(Stage stage) {
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().add(createRow(this::lines));
root.getChildren().add(createRow(this::curve));
root.getChildren().add(createRow(this::arc));
Scene scene = new Scene(root);
stage.setTitle("SVGIcons");
stage.setScene(scene);
stage.show();
}
private HBox createRow(IntFunction<SVGPath> path) {
HBox row = new HBox(10);
row.setAlignment(Pos.CENTER);
for (int i = 2; i < 6; i++) {
row.getChildren().add(path.apply(i * SIZE));
}
return row;
}
private SVGPath lines(int size) {
SVGPath path = new SVGPath();
path.setFill(Color.ALICEBLUE);
path.setStroke(Color.BLUE);
path.setContent("M0," + size + "L" + size / 2 + ",0 "
+ size + "," + size + " " + size / 2 + "," + 2 * size / 3 + "z");
return path;
}
private SVGPath curve(int size) {
SVGPath path = new SVGPath();
path.setFill(Color.HONEYDEW);
path.setStroke(Color.GREEN);
path.setContent("M0,0Q" + size + ",0,"
+ size + "," + size + "L0," + size + "z");
return path;
}
private SVGPath arc(int size) {
SVGPath path = new SVGPath();
path.setFill(Color.MISTYROSE);
path.setStroke(Color.RED);
path.setContent("M0,0A" + size / 2 + "," + size
+ ",0,1,0," + size + ",0z");
return path;
}
public static void main(String[] args) {
launch(args);
}
}