Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ A lightweight, optimized JavaFX node for rendering SVG paths at any size. Fully

- 🎨 Render any SVG path as a JavaFX node
- 🔗 No dependencies - will use your provided JavaFX runtime
- ⚡ Optimized to be efficient and have a tiny footprint, so you can render 100 `SvgNode` without any problem.
- This is achieved by `SvgNode` extending from `Parent`, skipping size calculations and only initializing properties when needed
- ⚡ Optimized to be efficient and have a tiny footprint, so you can render 1000 `SvgNode` instances without any problem.
- 📐 Uniform rasterization with a single `size` property
- 📄 FXML-compatible with attribute and constant-based usage
- 🎭 CSS-stylable via `.svg-node` and `.svg` style classes. By default, the SVG automatically adjusts its color based on the background - just like text
Expand Down Expand Up @@ -217,11 +216,37 @@ The API of `SvgNode` matches what is the de-facto standard for SVG libraries, in

#### Changelog

> Version 2.0.0
##### Version 2.0.0

This is release contains breaking changes. See below.

- Made all properties CSS styleable. This is especially interesting together with CSS transitions.
- Renamed `svgColor` to `color`. This is a breaking change. See the naming above why this was done.
- Extend from `Region`. Initially, `SvgNode` extended from `Parent` but unfortunately the JavaFX API will be against you.
You can influence the layout bounds calculation, it simply is not public. JavaFX will then try to derive the layout bounds from the children, which is not what we want.
This will lead to a wrong positioning in some cases where the SVG is more rectangular. It also results in a weird double layout, which is not the case with `Region`
- Advantage: We can set a background and border. Performance is the same.

Example:

```text
+-------------------------------+
| SvgNode |
| 24x24 |
+-------------------------------+
| SVG |
| 24x12 |
+-------------------------------+
| SvgNode |
| 24x24 |
+-------------------------------+
```

Here, the layout bounds should be 24x24, but will be calculated as 24x12 because of the inner SVG.

The idea is that the `SvgNode` has always the same width and height and will adjust the inner SVG to be centered.
This works fine, but as soon as other nodes use the layout bounds for the calculation (which is done sometimes), it will be wrong, not honoring the pref size.

> Version 1.0.0
##### Version 1.0.0

- Initial release
52 changes: 22 additions & 30 deletions src/main/java/tools/maran/svgnode/SvgNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
import javafx.css.converter.PaintConverter;
import javafx.css.converter.SizeConverter;
import javafx.css.converter.StringConverter;
import javafx.scene.Parent;
import javafx.scene.layout.Background;
import javafx.scene.layout.Region;
import javafx.scene.paint.Paint;
import javafx.scene.shape.SVGPath;

/// Node to show an SVG path with the specified size.
/// Node to show an SVG path with the specified size and color.
///
/// # Java usage
///
Expand Down Expand Up @@ -55,7 +54,7 @@
/// ```
///
/// @author Marius Hanl
public class SvgNode extends Parent {
public class SvgNode extends Region {

private static final double DEFAULT_SIZE = 24.0;
private static final String DEFAULT_PATH = "";
Expand Down Expand Up @@ -220,54 +219,47 @@ public final void setColor(Paint value) {
}

@Override
public double minHeight(double width) {
return getSize();
}

@Override
public double minWidth(double height) {
return getSize();
}

@Override
public double prefHeight(double width) {
return getSize();
protected double computeMinHeight(double width) {
return snappedTopInset() + getSize() + snappedBottomInset();
}

@Override
public double prefWidth(double height) {
return getSize();
protected double computeMinWidth(double height) {
return snappedLeftInset() + getSize() + snappedRightInset();
}

@Override
protected double computeMinHeight(double width) {
return getSize();
protected double computePrefHeight(double width) {
return snappedTopInset() + getSize() + snappedBottomInset();
}

@Override
protected double computeMinWidth(double height) {
return getSize();
protected double computePrefWidth(double height) {
return snappedLeftInset() + getSize() + snappedRightInset();
}

@Override
protected double computePrefHeight(double width) {
return getSize();
protected double computeMaxHeight(double width) {
return snappedTopInset() + getSize() + snappedBottomInset();
}

@Override
protected double computePrefWidth(double height) {
return getSize();
protected double computeMaxWidth(double height) {
return snappedLeftInset() + getSize() + snappedRightInset();
}

@Override
protected void layoutChildren() {
double nodeSize = getSize();
double left = getInsets().getLeft();
double top = getInsets().getTop();
double contentWidth = getWidth() - left - getInsets().getRight();
double contentHeight = getHeight() - top - getInsets().getBottom();

double width = svgContent.svgWidth;
double height = svgContent.svgHeight;
double x = (nodeSize - width) / 2;
double y = (nodeSize - height) / 2;
svgContent.resizeRelocate(x, y, width, height);
double x = left + (contentWidth - width) / 2;
double y = top + (contentHeight - height) / 2;
svgContent.resizeRelocate(snapPositionX(x), snapPositionY(y), width, height);
}

/// Gets the {@code CssMetaData} associated with this class.
Expand Down Expand Up @@ -327,7 +319,7 @@ public StyleableProperty<Paint> getStyleableProperty(SvgNode node) {
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;

static {
List<CssMetaData<? extends Styleable, ?>> metadata = Parent.getClassCssMetaData();
List<CssMetaData<? extends Styleable, ?>> metadata = Region.getClassCssMetaData();
final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(metadata.size() + 3);
styleables.addAll(metadata);
styleables.add(PATH);
Expand Down
13 changes: 11 additions & 2 deletions src/test/java/tools/maran/svgnode/manual/SvgNodeSampler.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Background;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
Expand Down Expand Up @@ -138,7 +142,7 @@ private void addButtonGraphics() {
}

private void addLabels() {
view.getChildren().add(sectionLabel("Label and SvgNode styled with CSS (+hover effect)"));
view.getChildren().add(sectionLabel("Usage with Label, CSS (Hover), Background, Border"));

Label label = new Label("SVG with text", new SvgNode(HEART));

Expand All @@ -157,7 +161,12 @@ private void addLabels() {
}
"""));

view.getChildren().add(new HBox(4, label, svgNodeHover));
SvgNode svgNodeBg = new SvgNode(HEART);
svgNodeBg.setColor(Color.RED);
svgNodeBg.setBackground(Background.fill(Color.MISTYROSE));
svgNodeBg.setBorder( new Border(new BorderStroke(Color.LIGHTGREEN, BorderStrokeStyle.SOLID, null, BorderStroke.THICK)));

view.getChildren().add(new HBox(4, label, svgNodeHover, svgNodeBg));
}

private void addStaticSvgs() {
Expand Down