11package 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 ;
114import io .fair_acc .chartfx .ui .css .TextStyle ;
125import 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.
1914 * @author ennerf
2015 */
2116public 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