是否可以将LinearGradient填充添加到已经具有ImagePattern填充的SVGPath中?

时间:2019-04-09 08:10:39

标签: javafx javafx-8

在我的主应用程序中,我有一些添加到XYChart的SVGPath。有时他们有一个ImagePattern填充,现在需要具有LinearGradient填充。 ImagePattern填充是一个交叉阴影线,需要使用LinearGradient对其进行着色,就像它是应用了LinearGradient的纯矩形矩形一样。 SVGPath也具有虚线轮廓,而LinearGradient应该填充虚线轮廓和ImagePattern填充,因为它们是同一形状的一部分。

我已经写了一些示例代码来显示我的位置。这会在创建交叉阴影线时为其着色,并且看起来还可以,但是我上面描述的效果不佳,因为ImagePattern中的每个交叉线都分别应用了LinearGradient。理想情况下,一旦应用了ImagePattern填充,则将LinearGradient仅应用于最终的SVGPath。 我还尝试了使用Blend和ColorInput进行一些效果,但没有设法进一步解决该问题。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Line;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
            ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);

            for (int i = 0; i < colors.size(); i++) {
                stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
                stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
            }

            LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);

            SVGPath svgPath = new SVGPath();
            svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");

            Image hatch = createCrossHatch(lg);
            ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);

            svgPath.setFill(pattern);
            svgPath.setStroke(lg);

            BorderPane root = new BorderPane();
            root.setCenter(svgPath);
            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected static Image createCrossHatch(Paint paint) {
        Pane pane = new Pane();
        pane.setPrefSize(20, 20);
        pane.setStyle("-fx-background-color: transparent;");
        Line fw = new Line(-5, -5, 25, 25);
        Line bw = new Line(-5, 25, 25, -5);
        fw.setStroke(paint);
        bw.setStroke(paint);
        fw.setStrokeWidth(3);
        bw.setStrokeWidth(3);
        pane.getChildren().addAll(fw, bw);
        new Scene(pane);
        SnapshotParameters sp = new SnapshotParameters();
        sp.setFill(Color.TRANSPARENT);

        return pane.snapshot(sp, null);
    }

    private double getOffset(double i, int count) {
        return (((double) 1) / (double) count * (double) i);
    }

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

如果运行提供的代码,您将看到它画出一条狗骨头。虚线轮廓线的线性渐变颜色应继续穿过阴影线的ImagePattern填充。我知道为什么阴影的ImagePattern像这样着色,但这是我目前最好的折衷方案。如前所述,我希望能够在应用ImagePattern填充后将LinearGradient填充应用于整个形状,以便LinearGradient对整个形状产生相同的影响。

谢谢

1 个答案:

答案 0 :(得分:0)

没有直接方法可以在一个节点上应用和组合两种涂料。我们可以通过CSS使用背景色叠加许多不同的paints(例如,实心,线性渐变甚至是图像图案),但不会结合使用。

因此,为了组合两种不同的绘画,一方面是线性渐变,另一方面是图案填充,我们需要将它们应用于两个节点,并在两种绘画之间使用混合效果。

根据发布的代码,这是具有线性渐变的SVGPath:

@Override
public void start(Stage primaryStage) {
    Node base = getNodeWithGradient();

    BorderPane root = new BorderPane();
    Group group = new Group(base);
    root.setCenter(group);

    Scene scene = new Scene(root, 400, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private SVGPath getNodeWithGradient() {
    List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
    ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);

    for (int i = 0; i < colors.size(); i++) {
        stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
        stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
    }

    LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);

    SVGPath svgPath = getSVGPath();
    svgPath.setFill(lg);
    svgPath.setStroke(lg);

    return svgPath;
}

private SVGPath getSVGPath() {
    SVGPath svgPath = new SVGPath();
    svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
    return svgPath;
}

private double getOffset(double i, int count) {
    return (((double) 1) / (double) count * (double) i);
}

Linear Gradient

这是带有图像图案填充的SVGPath:

@Override
public void start(Stage primaryStage) {
    Node overlay = getNodeWithPattern();

    BorderPane root = new BorderPane();
    Group group = new Group(overlay);

    root.setCenter(group);
    Scene scene = new Scene(root, 400, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private SVGPath getNodeWithPattern() {
    Image hatch = createCrossHatch();
    ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);

    SVGPath svgPath = getSVGPath();
    svgPath.setFill(pattern);

    return svgPath;
}

private SVGPath getSVGPath() {
    SVGPath svgPath = new SVGPath();
    svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
    return svgPath;
}

private static Image createCrossHatch() {
    Pane pane = new Pane();
    pane.setPrefSize(20, 20);
    Line fw = new Line(-5, -5, 25, 25);
    Line bw = new Line(-5, 25, 25, -5);
    fw.setStroke(Color.BLACK);
    bw.setStroke(Color.BLACK);
    fw.setStrokeWidth(3);
    bw.setStrokeWidth(3);
    pane.getChildren().addAll(fw, bw);
    new Scene(pane);
    SnapshotParameters sp = new SnapshotParameters();
    return pane.snapshot(sp, null);
}

Image Pattern

现在的诀窍是将两个SVGPath节点组合在一起,在其顶部添加一种混合模式。

根据BlendMode.ADD的{​​{3}}:

  

顶部输入的颜色和alpha分量被添加到底部输入的颜色和alpha分量。

@Override
public void start(Stage primaryStage) {
    Node base = getNodeWithGradient();
    Node overlay = getNodeWithPattern();
    overlay.setBlendMode(BlendMode.ADD);

    BorderPane root = new BorderPane();
    Group group = new Group(base, overlay);

    root.setCenter(group);
    Scene scene = new Scene(root, 400, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private SVGPath getNodeWithGradient() {
    List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
    ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);

    for (int i = 0; i < colors.size(); i++) {
        stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
        stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
    }

    LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);

    SVGPath svgPath = getSVGPath();
    svgPath.setFill(lg);
    svgPath.setStroke(lg);
    return svgPath;
}

private SVGPath getNodeWithPattern() {
    Image hatch = createCrossHatch();
    ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);

    SVGPath svgPath = getSVGPath();
    svgPath.setFill(pattern);
    return svgPath;
}

private SVGPath getSVGPath() {
    SVGPath svgPath = new SVGPath();
    svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
    return svgPath;
}

private static Image createCrossHatch() {
    Pane pane = new Pane();
    pane.setPrefSize(20, 20);
    Line fw = new Line(-5, -5, 25, 25);
    Line bw = new Line(-5, 25, 25, -5);
    fw.setStroke(Color.BLACK);
    bw.setStroke(Color.BLACK);
    fw.setStrokeWidth(3);
    bw.setStrokeWidth(3);
    pane.getChildren().addAll(fw, bw);
    new Scene(pane);
    SnapshotParameters sp = new SnapshotParameters();
    return pane.snapshot(sp, null);
}

private double getOffset(double i, int count) {
    return (((double) 1) / (double) count * (double) i);
}

我们得到了预期的结果:

JavaDoc