Last active
December 20, 2015 04:29
-
-
Save KhaledLela/6071422 to your computer and use it in GitHub Desktop.
JavaFx adding a text label on top of StackedBarChart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javafx.application.Application; | |
import javafx.beans.value.*; | |
import javafx.collections.FXCollections; | |
import javafx.collections.ObservableList; | |
import javafx.geometry.Bounds; | |
import javafx.geometry.Pos; | |
import javafx.scene.*; | |
import javafx.scene.chart.*; | |
import javafx.scene.control.Label; | |
import javafx.scene.layout.*; | |
import javafx.scene.paint.Color; | |
import javafx.scene.shape.*; | |
import javafx.scene.text.Text; | |
import javafx.stage.Stage; | |
/** | |
* Displays a Stackedbar with a multi series whose bars are different colors depending | |
* upon the bar value. A custom legend is created and displayed for the bar | |
* data. Bars in the chart are customized to include a text label of the bar's | |
* data value above the bar. | |
*/ | |
public class DynamicallyColoredBarChartWithLabel extends Application { | |
@Override | |
public void start(Stage stage) { | |
final NumberAxis yAxis = new NumberAxis(); | |
yAxis.setLabel("Value"); | |
String[] years = {"2007", "2008", "2009"}; | |
final CategoryAxis xAxis = new CategoryAxis(FXCollections.<String>observableArrayList(years)); | |
xAxis.setLabel("Bars"); | |
// final StackedBarChart<String, Number> bc = new StackedBarChart<>(xAxis, yAxis); | |
// bc.setLegendVisible(false); | |
// | |
// XYChart.Series<String,Number> series1 = new XYChart.Series(); | |
// XYChart.Series<String,Number> series2 = new XYChart.Series(); | |
// for (int i = 1; i <= 10; i++) { | |
// final XYChart.Data<String, Number> data = new XYChart.Data("Value " + i, i); | |
//// data.nodeProperty().addListener(new ChangeListener<Node>() { | |
//// @Override | |
//// public void changed(ObservableValue<? extends Node> ov, Node oldNode, final Node node) { | |
//// if (node != null) { | |
//// setNodeStyle(data); | |
//// displayLabelForData(data); | |
//// } | |
//// } | |
//// }); | |
// series1.getData().add(data); | |
// } | |
ObservableList<StackedBarChart.Series> barChartData = FXCollections.observableArrayList( | |
new StackedBarChart.Series("Region 1", FXCollections.observableArrayList( | |
new StackedBarChart.Data(years[0], 567d), | |
new StackedBarChart.Data(years[1], 1292d), | |
new StackedBarChart.Data(years[2], 1292d))), | |
new StackedBarChart.Series("Region 2", FXCollections.observableArrayList( | |
new StackedBarChart.Data(years[0], 956), | |
new StackedBarChart.Data(years[1], 1665), | |
new StackedBarChart.Data(years[2], 2559))), | |
new StackedBarChart.Series("Region 3", FXCollections.observableArrayList( | |
new StackedBarChart.Data(years[0], 1154), | |
new StackedBarChart.Data(years[1], 1927), | |
new StackedBarChart.Data(years[2], 2774)))); | |
final XYChart.Series<String, Number> lastSeries = barChartData.get(barChartData.size() - 1); | |
for (final XYChart.Data<String, Number> data : lastSeries.getData()) { | |
data.nodeProperty().addListener(new ChangeListener<Node>() { | |
@Override | |
public void changed(ObservableValue<? extends Node> ov, Node oldNode, final Node node) { | |
if (node != null) { | |
// setNodeStyle(data); | |
displayLabelForData(data); | |
} | |
} | |
}); | |
} | |
StackedBarChart<String, Number> chart = new StackedBarChart(xAxis, yAxis, barChartData, 25.0d); | |
LevelLegend legend = new LevelLegend(); | |
legend.setAlignment(Pos.CENTER); | |
VBox chartWithLegend = new VBox(); | |
chartWithLegend.getChildren().setAll(chart, legend); | |
VBox.setVgrow(chart, Priority.ALWAYS); | |
chartWithLegend.getStylesheets().add(getClass().getResource("colored-chart.css").toExternalForm()); | |
stage.setScene(new Scene(chartWithLegend)); | |
stage.setMinHeight(400); | |
stage.setMinWidth(400); | |
stage.show(); | |
} | |
/** | |
* Change color of bar if value of i is <5 then red, if >5 then green if i>8 | |
* then blue | |
*/ | |
private void setNodeStyle(XYChart.Data<String, Number> data) { | |
Node node = data.getNode(); | |
if (data.getYValue().intValue() > 8) { | |
node.setStyle("-fx-bar-fill: -fx-exceeded;"); | |
} else if (data.getYValue().intValue() > 5) { | |
node.setStyle("-fx-bar-fill: -fx-achieved;"); | |
} else { | |
node.setStyle("-fx-bar-fill: -fx-not-achieved;"); | |
} | |
} | |
/** | |
* places a text label with a bar's value above a bar node for a given | |
* XYChart.Data | |
*/ | |
private void displayLabelForData(XYChart.Data<String, Number> data) { | |
final Node node = data.getNode(); | |
final Text dataText = new Text(data.getYValue() + ""); | |
node.parentProperty().addListener(new ChangeListener<Parent>() { | |
@Override | |
public void changed(ObservableValue<? extends Parent> ov, Parent oldParent, Parent parent) { | |
Group parentGroup = (Group) parent; | |
parentGroup.getChildren().add(dataText); | |
} | |
}); | |
node.boundsInParentProperty().addListener(new ChangeListener<Bounds>() { | |
@Override | |
public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) { | |
dataText.setLayoutX( | |
Math.round( | |
bounds.getMinX() + bounds.getWidth() / 2 - dataText.prefWidth(-1) / 2)); | |
dataText.setLayoutY( | |
Math.round( | |
bounds.getMinY() - dataText.prefHeight(-1) * 0.5)); | |
} | |
}); | |
} | |
/** | |
* A simple custom legend for a three valued chart. | |
*/ | |
class LevelLegend extends GridPane { | |
LevelLegend() { | |
setHgap(10); | |
setVgap(10); | |
addRow(0, createSymbol("-fx-exceeded"), new Label("Exceeded")); | |
addRow(1, createSymbol("-fx-achieved"), new Label("Achieved")); | |
addRow(2, createSymbol("-fx-not-achieved"), new Label("Not Achieved")); | |
getStyleClass().add("level-legend"); | |
} | |
/** | |
* Create a custom symbol for a custom chart legend with the given | |
* fillStyle style string. | |
*/ | |
private Node createSymbol(String fillStyle) { | |
Shape symbol = new Ellipse(10, 5, 10, 5); | |
symbol.setStyle("-fx-fill: " + fillStyle); | |
symbol.setStroke(Color.BLACK); | |
symbol.setStrokeWidth(2); | |
return symbol; | |
} | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
But did you try updating data ? Labels on top of bar chart stay after updating data for me... It's annoying and I don't know how to remove them.
http://stackoverflow.com/questions/34286062/how-to-clear-text-added-in-a-javafx-barchart