RFR: 8358820: Allow interpolation outside of range [0,1] [v3]
Alessadro Parisi
duke at openjdk.org
Fri Aug 22 07:51:03 UTC 2025
On Sun, 27 Jul 2025 18:48:18 GMT, Michael Strauß <mstrauss at openjdk.org> wrote:
>> JavaFX unnecessarily restricts interpolation in the following ways:
>> 1. `Interpolatable` implementations often clamp intermediate values to the interpolation factor range [0,1].
>> 2. `SplineInterpolator` doesn't accept Y coordinates outside of [0,1] for its control points. While this was probably done so that the computed interpolation factor doesn't exceed [0,1], the restriction goes far beyond that. For example, the following function is not representable, even though its values are all within the [0,1] range:<br>
>> <img src="https://github.com/user-attachments/assets/368b6142-052d-4ead-8a59-cbddf4a19660" width="400"/><br>
>> The following function is also not representable, but would be very useful for [bouncy animations](https://easings.net/#easeOutBack):<br>
>> <img src="https://github.com/user-attachments/assets/af02b044-ae4c-4250-b181-72178ad9f3f3" width="400"/>
>>
>> Fortunately, there is no technical reason why JavaFX can't support the full range of animations that can be represented with a cubic Beziér interpolation function.
>>
>> This PR includes the following changes:
>> 1. The specification of `Interpolatable` is changed to require implementations to accept interpolation factors outside of [0,1].
>> 2. All implementations of `Interpolatable` now correctly return intermediate values outside of [0,1].
>> 3. `SplineInterpolator` now accepts control points with any Y coordinate.
>>
>> Here's how the result looks like for the previously unrepresentable interpolation function `cubic-bezier(0.34, 2.2, 0.64, 1)`:<br>
>> <img src="https://github.com/user-attachments/assets/72c10d0d-71b4-4bb5-b58c-ae377279b0fd" width="500"/>
>
> Michael Strauß has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains three additional commits since the last revision:
>
> - Merge branch 'master' into feature/relaxed-interpolation
> - javadoc
> - Allow interpolation outside of range [0,1]
Currently the workaround I use for this is to have a custom Interpolator implementation like:
public class Cubic extends Interpolator {
private final double x1;
private final double y1;
private final double x2;
private final double y2;
private static final double CUBIC_ERROR_BOUND = 0.001;
public Cubic(double x1, double y1, double x2, double y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
double elevateCubic(double a, double b, double m) {
return 3 * a * (1 - m) * (1 - m) * m +
3 * b * (1 - m) * m * m +
m * m * m;
}
@Override
public double curve(double t) {
double start = 0.0;
double end = 1.0;
while (true) {
final double midpoint = (start + end) / 2;
final double estimate = elevateCubic(x1, x2, midpoint);
if (Math.abs(t - estimate) < CUBIC_ERROR_BOUND) {
return elevateCubic(y1, y2, midpoint);
}
if (estimate < t) {
start = midpoint;
} else {
end = midpoint;
}
}
}
}
Which allows me to define such curves:
public static final MotionPreset EXPRESSIVE_FAST_SPATIAL = MotionPreset.of(
new Cubic(0.42, 1.67, 0.21, 0.90),
MEDIUM3 // Duration constant
);
I believe I copied this from Flutter.
(The new Material 3 Expressive makes use a lot of springs, see [Material 3 Docs](https://m3.material.io/styles/motion/overview/specs#1b299695-5822-4738-ae56-ef9389b412d2))
Unfortunately, I need to use such curves in CSS too, so I kinda need this commit to be merged
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1822#issuecomment-3213417480
More information about the openjfx-dev
mailing list