JavaFX 2.0 - How to change legend color of a LineChart dynamically?
Asked Answered
P

5

6

I am trying to style my JavaFX linechart but I have some trouble with the legend.

I know how to change the legend color of a line chart in the css file:

.default-color0.chart-series-line { -fx-stroke:  #FF0000, white; } 
.default-color1.chart-series-line { -fx-stroke:  #00FF00, white; }
.default-color2.chart-series-line { -fx-stroke:  #0000FF, white; }
.default-color0.chart-line-symbol { -fx-background-color: #FF0000, white; }
.default-color1.chart-line-symbol { -fx-background-color: #00FF00, white; } 
.default-color2.chart-line-symbol { -fx-background-color: #0000FF, white; }

But this is not enough for my purposes. I have three or more colored toggle buttons and a series of data for every button. The data should be displayed in the same color the button has after I have selected the button. This should be possible with a multiselection of the buttons, so that more than one series of data can be displayed simultaneously.

For the chart lines I have managed it by changing the style after I clicked the button:

..
dataList.add(series); 
..
series.getNode().setStyle("-fx-stroke: rgba(" + rgba + ")");

If I deselect the button I remove the data from the list.

dataList.remove(series);

That is working fine for the strokes, but how can I do the same for the legend?

You can see an example below. First I clicked the red button, thus the stroke and the legend is red (default-color0). After that I clicked the blue button. Here you can see the problem. The stroke is blue but the legend is green, because default color1 is used and I do not know how to change the legend color.

enter image description here

Plummy answered 27/9, 2012 at 13:37 Comment(1)
Do you mean subtitle or label?Yetac
G
4

I ran into this issue as well. The issue seems to be that when data series are added to the chart, the legend isn't updated at the same time, so when you lookup components with that seriesN style class they don't exist yet. Came up with a work-around that detects when the legend items are created so that dynamic styling can be added to them.

I added a ListChangeListener to the chart legend's "getChildrenUnmodifiable()" ObservableList, which in turn adds a ListChangeListener to each of the legend's children as they get added. From within this listener, we can tell when new items are being added to the legend (or removed). This allow us to then make the dynamic style changes.

for (Node n : lineChart.getChildrenUnmodifiable())
    {
        if (n instanceof Legend)
        {
            final Legend legend = (Legend) n;

            // remove the legend
            legend.getChildrenUnmodifiable().addListener(new ListChangeListener<Object>()
            {
                @Override
                public void onChanged(Change<?> arg0)
                {
                    for (Node node : legend.getChildrenUnmodifiable())
                    {
                        if (node instanceof Label)
                        {
                            final Label label = (Label) node;
                            label.getChildrenUnmodifiable().addListener(new ListChangeListener<Object>()
                            {
                                @Override
                                public void onChanged(Change<?> arg0)
                                {
                                    //make style changes here
                                }

                            });
                        }
                    }
                }
            });
        }
    }
Greisen answered 1/5, 2013 at 21:3 Comment(2)
A thousand thanks for this, I was looking for something like that for days.Carcinoma
Maybe a dumb question but to what I'll add the style changes? to label? @CarcinomaLeucine
B
3

For future reference, this problem can be solved by wrapping your relevant code in a call to Platform.runLater(). For example:

LineChart<Number, Number> plot;
....
Platform.runLater(() -> {
    Node nl = plot.lookup(".default-color0.chart-series-line");
    Node ns = plot.lookup(".default-color0.chart-line-symbol");

    nl.setStyle("-fx-stroke: #333;");
    ns.setStyle("-fx-background-color: #333, white;");
}); 
Boyar answered 26/9, 2017 at 21:15 Comment(4)
Thank you very much! Where can I find all these cryptic css for JavaFX?Rabbinate
@Rabbinate This is what I use as reference gist.github.com/tmazeika/c90c03c645d18722ddb0Boyar
what is this plot.lookup?Leucine
@SamedSivaslıoğlu I have adjusted my example. Plot is the LineChart elementBoyar
T
0

This solution is based on @Chris' solution

 if (checkCombo.getCheckModel().isChecked(0)) {
    lineChart.getData().add(seriesTest1);
    changeColorSeries(lineChart.getData().size() - 1, "darkgreen");
 }

 if (checkCombo.getCheckModel().isChecked(3)) {
    lineChart.getData().add(seriesTest2);
    changeColorSeries(lineChart.getData().size() - 1, "darkred");
 }

 private void changeColor(int position, String color) {
        Platform.runLater(() -> {
            Node nl = lineChart.lookup(".default-color" + position + ".chart-series-line");
            Node ns = lineChart.lookup(".default-color" + position + ".chart-line-symbol");
            Node nsl = lineChart.lookup(".default-color" + position + ".chart-legend-item-symbol");

            nl.setStyle("-fx-stroke: " + color + ";");
            ns.setStyle("-fx-background-color: " + color + ", white;");
            nsl.setStyle("-fx-background-color: " + color + ", white;");
        });
 }
Truncate answered 22/12, 2018 at 19:34 Comment(0)
C
0

After digging a lot through google with no success I finally found a lean way to update the legend colors according line color through this method:

private void setLegendItemColor(String shop, String color, Legend lg) {
        for (Node n : lg.getChildren()) {
                Label lb = (Label) n;
                if (lb.getText().contains(shop)) {
                    lb.getGraphic().setStyle("-fx-background-color:" + color + ";");
                }
        }
}

So you just need to call the method setLegendItemColor() when you´re going to update the chart lines to update the legend label symbols to the correspondent color.

enter image description here

Chartist answered 31/3, 2022 at 3:54 Comment(0)
M
-1

It seems that this guy is able to lookup the nodes used for legend using their class, and then calling setStyle() on those nodes. (I don't think his problem is relevant for yours)

Midkiff answered 2/1, 2013 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.