Linear gradient's bounds computation takes parent's bounds in account, not the node on which it is applied on
Asked Answered
O

1

1

I want to put a linear gradient on a line(width wise ie across it's stroke width). This line is a child of a Group node. When I apply linear gradient on line, the color stops are calculated using Group's bounds not the lines bounds. In my code below, linear gradient will show up properly when added length-wise ie "to bottom", but not when added width wise, ie "to right". Can anyone tell me what can be work around for this? Here is the SSCCE

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class Test extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
    Group group = new Group();
    primaryStage.setScene(new Scene(group, 200, 350));

    Line line = new Line(100, 50, 100, 300);
    group.getChildren().add(line);
    line.setStyle("-fx-stroke-width:3em; -fx-stroke:linear-gradient(to right, red, green);");
    //line.setStyle("-fx-stroke-width:3em; -fx-stroke:linear-gradient(to bottom, red, green);");

    primaryStage.show();
}

public static void main(String[] args) {
    launch();
}

}
Of answered 19/1, 2015 at 14:32 Comment(0)
P
0

The assumption it takes the group's bounds is not correct. In fact, it's taking the line's bound. And here is the problem.

If you go to com.sun.prism.j2d.J2DPrismGraphics you'll see that for a shape with a gradient, this is how fill() is done:

void fill(java.awt.Shape shape) {
    if (paintWasProportional) {
        if (nodeBounds != null) {
            g2d.setPaint(toJ2DPaint(paint, nodeBounds));
        } else {
            g2d.setPaint(toJ2DPaint(paint, shape.getBounds2D()));
        }
    }
    g2d.fill(shape);
}

The paintWasProportional check gave me a hint to approach your problem with another perspective.

Let's start by using a LinearGradient object, by code instead of using CSS. Then this will be your starting point:

@Override
public void start(Stage primaryStage) throws Exception {
    Group group = new Group();
    primaryStage.setScene(new Scene(group, 200, 350));

    Line line = new Line(100, 50, 100, 300);
    LinearGradient linearGradient = new LinearGradient(0d, 0d, 0d, 1d, true,
      CycleMethod.NO_CYCLE, new Stop(0,Color.RED),new Stop(1,Color.GREEN));
line.setStrokeWidth(36); // 3em
    line.setStroke(linearGradient);
    group.getChildren().add(line);
    primaryStage.show();
}

With the expected result (the black line is just for reference):

Gradient 1

Now, to get the gradient to right, let's change the way we create the gradient, using a non proporcional one:

LinearGradient linearGradient = new LinearGradient(0d, 50d, 0d, 300d,
       false, CycleMethod.REFLECT,new Stop(0,Color.RED), new Stop(1,Color.GREEN));   

This will have the same result.

And if you want to change the direction, this is what you need:

LinearGradient linearGradient = new LinearGradient(100-18d, 0d, 100+18d, 0d,
 false, CycleMethod.REFLECT,new Stop(0,Color.RED), new Stop(1,Color.GREEN));

With this result:

Gradient 2

Note you could try now to get this done also by CSS.

Psychosocial answered 19/1, 2015 at 21:3 Comment(1)
Well articulated answer!! Thanks... I tried to do it using css, but there is no place we can specify proportional attribute's value. For doing that I will have to use px units. Can not do that either as size of my line is variable :(Of

© 2022 - 2024 — McMap. All rights reserved.