Skip to content

Commit a408c46

Browse files
committed
made TickMark more extensible and changed to FxFontMetrics
1 parent 49a8f2f commit a408c46

2 files changed

Lines changed: 52 additions & 29 deletions

File tree

chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/AbstractAxis.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ protected void updateMajorTickMarks(AxisRange range) {
681681
}
682682

683683
// Update the existing mark objects
684-
List<TickMark> marks = FXUtils.sizedList(getTickMarks(), newTickValues.size(), () -> new TickMark(getTickLabelStyle()));
684+
List<TickMark> marks = FXUtils.sizedList(getTickMarks(), newTickValues.size(), this::createTickMark);
685685
int i = 0;
686686
for (var mark : marks) {
687687
var tick = newTickValues.getDouble(i++);
@@ -705,7 +705,7 @@ protected void updateMinorTickMarks() {
705705
}
706706

707707
// Update
708-
List<TickMark> marks = FXUtils.sizedList(getMinorTickMarks(), newTickValues.size(), () -> new TickMark(getTickLabelStyle()));
708+
List<TickMark> marks = FXUtils.sizedList(getMinorTickMarks(), newTickValues.size(), this::createTickMark);
709709
int i = 0;
710710
for (var mark : marks) {
711711
mark.setValue(newTickValues.getDouble(i++), "");
@@ -715,6 +715,10 @@ protected void updateMinorTickMarks() {
715715
tickMarksUpdated();
716716
}
717717

718+
protected TickMark createTickMark() {
719+
return new TickMark(getTickLabelStyle());
720+
}
721+
718722
protected void updateTickMarkPositions(List<TickMark> tickMarks) {
719723
for (TickMark tickMark : tickMarks) {
720724
tickMark.setPosition(getDisplayPosition(tickMark.getValue()));
@@ -972,7 +976,7 @@ protected double measureTickMarkLength(final double major) {
972976
return getSide().isHorizontal() ? tmpTickMark.getWidth() : tmpTickMark.getHeight();
973977
}
974978

975-
private final TickMark tmpTickMark = new TickMark(getTickLabelStyle());
979+
private final TickMark tmpTickMark = createTickMark();
976980

977981
protected void updateAxisLabelAlignment() {
978982
// TODO: maybe set this via CSS?

chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/TickMark.java

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
package io.fair_acc.chartfx.axes.spi;
22

3-
import java.util.Objects;
4-
5-
import javafx.beans.property.BooleanProperty;
6-
import javafx.beans.property.SimpleBooleanProperty;
7-
import javafx.geometry.VPos;
8-
import javafx.scene.text.Text;
9-
import javafx.scene.text.TextAlignment;
10-
3+
import io.fair_acc.chartfx.fxinternals.FxFontMetrics;
114
import io.fair_acc.chartfx.ui.css.TextStyle;
125
import io.fair_acc.chartfx.ui.geometry.Side;
136

7+
import java.util.Objects;
8+
149
/**
1510
* TickMark represents the label text dimension, its associated tick mark value and position along the axis for each tick.
1611
* For performance reasons the tick mark gets rendered into the canvas rather than being a separate node.
@@ -19,14 +14,14 @@
1914
* @author ennerf
2015
*/
2116
public class TickMark {
22-
private double tickValue = Double.NaN; // tick mark in data units
23-
private String text = ""; // the actual label text
24-
private double height = Double.NaN; // the label height in display units
25-
private double width = Double.NaN; // the label width in display units
26-
27-
private double tickPosition = Double.NaN; // tick position along axis in display units
28-
private boolean visible = true; // whether the tick mark should be displayed
29-
private final TextStyle style;
17+
protected double tickValue = Double.NaN; // tick mark in data units
18+
protected String text = ""; // the actual label text
19+
protected double height = Double.NaN; // the label height in display units
20+
protected double width = Double.NaN; // the label width in display units
21+
22+
protected double tickPosition = Double.NaN; // tick position along axis in display units
23+
protected boolean visible = true; // whether the tick mark should be displayed
24+
protected final TextStyle style;
3025
private long usedStyle = -1;
3126

3227
/**
@@ -38,7 +33,8 @@ public TickMark(TextStyle style) {
3833

3934
/**
4035
* Updates a tick mark
41-
* @param tickValue numeric value of tick
36+
*
37+
* @param tickValue numeric value of tick
4238
* @param tickMarkLabel string label associated with tick
4339
*/
4440
public void setValue(double tickValue, String tickMarkLabel) {
@@ -51,23 +47,45 @@ public void setValue(double tickValue, String tickMarkLabel) {
5147
this.text = tickMarkLabel;
5248
}
5349

54-
private void updateTextSize() {
50+
protected void updateTextSize() {
5551
if (usedStyle != style.getChangeCounter() || height < 0) {
5652
if (text == null || text.isEmpty()) {
5753
height = 0;
5854
width = 0;
5955
} else {
60-
// N.B. important: usage of getBoundsInParent() which also takes into
61-
// account text rotations
62-
style.setText(text);
63-
var bounds = style.getBoundsInParent();
64-
height = bounds.getHeight();
65-
width = bounds.getWidth();
56+
updateBounds();
6657
}
6758
usedStyle = style.getChangeCounter();
6859
}
6960
}
7061

62+
protected void updateBounds() {
63+
// N.B. important: usage of getBoundsInParent() which also takes into account text rotations.
64+
//
65+
// Checking text bounds via a node is incredibly wasteful, so we try to use an internal API
66+
// that is available with appropriate jvm flags. The two results can differ by tiny amounts
67+
// as the width may depend on the actual character sequence (e.g. 4 followed by 3), but in
68+
// initial tests the diff was usually below 1px. This should not matter in practice.
69+
if (FxFontMetrics.isAvailable()) {
70+
this.height = FxFontMetrics.getLineHeight(style.getFont());
71+
this.width = FxFontMetrics.getWidth(style.getFont(), text);
72+
if (getRotation() != 0) {
73+
var rad = Math.toRadians(getRotation());
74+
var sin = Math.sin(rad);
75+
var cos = Math.cos(rad);
76+
var w = width;
77+
var h = height;
78+
this.width = (w * cos) + (h * sin) + 0.5; // account for AA
79+
this.height = (w * sin) + (h * cos) + 0.5; // account for AA
80+
}
81+
} else {
82+
style.setText(text);
83+
var bounds = style.getBoundsInParent();
84+
height = bounds.getHeight();
85+
width = bounds.getWidth();
86+
}
87+
}
88+
7189
/**
7290
* @return the style applied to this tickmark
7391
*/
@@ -129,9 +147,10 @@ public void setVisible(boolean visible) {
129147

130148
// ------- deprecated methods for backwards compatibility with unit tests -------
131149

132-
@Deprecated // TODO: update tests
150+
@Deprecated
151+
// TODO: update tests
133152
TickMark(final Side side, final double tickValue, final double tickPosition, final double tickRotation,
134-
final String tickMarkLabel) {
153+
final String tickMarkLabel) {
135154
this(new TextStyle());
136155
setValue(tickValue, tickMarkLabel);
137156
this.style.setRotate(tickRotation);

0 commit comments

Comments
 (0)