I have created a barChart in javaFX and I have a problem with categoryAxis. Practice I would like to divide the number of CategoryAxis by 1000. For the moment the graph I get is this:
When I divide the values by 1000 then the graph changes the y axis.
How should I do to get the xaxis values as the second graph with barChart of the first pictures?
Class to populate and show the graph.
package application;
import java.io.File;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import spectrogram.SpectrogramExtractor;
public class ControllerSpectrogram {
private final static double MINSPECTROGRAMHZ = 20.0;
static DecimalFormat df = new DecimalFormat("#.##");
#SuppressWarnings("unchecked")
public static void plotSpectrogramFull(File file, Stage stage) {
df.setRoundingMode(RoundingMode.CEILING);
final CategoryAxis xAxisSpectrogram = new CategoryAxis();
final NumberAxis yAxisSpectrogram = new NumberAxis();
final BarChart<String,Number> scatterChartSpectrogram =
new BarChart<String,Number>(xAxisSpectrogram,yAxisSpectrogram);
ArrayList<Double> extractedData;
ArrayList<Double> extractedTime;
scatterChartSpectrogram.getData().clear();
scatterChartSpectrogram.setOpacity(0.8);
scatterChartSpectrogram.setAnimated(true);
xAxisSpectrogram.setLabel("Time(s)");
yAxisSpectrogram.setLabel("Spectrogram(Hz)");
try {
extractedData = SpectrogramExtractor.extractionSpectrum();
extractedTime = SpectrogramExtractor.pointTime();
Series<String, Number> series = new XYChart.Series<String, Number>();
for (int i = 0; i < extractedData.size(); i=i+2) {
if (extractedData.get(i)> MINSPECTROGRAMHZ) {
extractedTime.set(i, extractedTime.get(i)/1000);
series.getData().add(new XYChart.Data<String, Number>(df.format(extractedTime.get(i)), extractedData.get(i)));
}
}
Scene scene = new Scene(scatterChartSpectrogram, 1000, 600);
scatterChartSpectrogram.getData().add(series);
stage.setScene(scene);
stage.show();
extractedData.clear();
} catch (java.lang.Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This is the method (in other class)
public class SpectrogramExtractor {
static ArrayList<Double> pointTime = new ArrayList<>();
public static ArrayList<Double> pointTime(){
Double countTime = 0;
for(int i=0; i<100; i++){
countTime = countTime + 0.0196356952;
pointTime.add(countTime);
return pointTime;
}
public static ArrayList<Double>extractionSpectrum(){
//and you can try to populate extractedData whit 100 elements (what you want)
}
}
Related
I want to populate a line chart with data from the database. To achieve this, I created a class that returns an ObservableList<XYChart.Series>. But I struggle to merge the same XYChart.Series name (Like the example below).
MVCE
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Sample extends Application {
#Override public void start(Stage stage) {
//create the chart
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Year");
final LineChart<String,Number> lineChart =
new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Employment Monitoring, 2020");
for(XYChart.Series series : getData()){
lineChart.getData().add(series);
}
// show the scene.
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
/* How can I return the right value to the line chart ? */
private ObservableList<XYChart.Series> getData(){
var list = FXCollections.<XYChart.Series>observableArrayList();
// Supposed that this data where values retrieved from the database
ArrayList<List> arrayList = new ArrayList<>();
arrayList.add(Arrays.asList("Permanent", "2011", 5));
arrayList.add(Arrays.asList("Job Order", "2011", 16));
arrayList.add(Arrays.asList("Permanent", "2012", 10));
arrayList.add(Arrays.asList("Job Order", "2012", 19));
for (List obs : arrayList){
list.add(
new XYChart.Series(
(String) obs.get(0),
FXCollections.observableArrayList(
new XYChart.Data<>((String) obs.get(1), (Number) obs.get(2))
)
));
}
return list;
}
public static void main(String[] args) { launch(args); }
}
This will produce this output
As you have noticed, there are duplicate series for Permanent and Job Order
Question is
How will I merge that duplicate entry so that I can achieve the output below?
without using a model class
EDIT
As #kleopatra said, (Based from my current knowledge on java) I tried to filter the data from the list by :
for (XYChart.Series series : getData()){
XYChart.Data item = (XYChart.Data) series.getData().get(0);
if (lineChart.getData().size() > 0){
for (XYChart.Series duplicate : lineChart.getData())
{
if (duplicate.getName().equals(series.getName()))
{
duplicate.getData().add(item);
} else {
// lineChart.getData().add(series);
}
}
} else {
lineChart.getData().add(series);
}
}
instead of just :
for(XYChart.Series series : getData())
{
lineChart.getData().add(series);
}
though it gives me the concatenated output for the Permanent series (which is what I want to achieve). I can hardly add another series e.g. Job Order to the line chart. As when I uncomment the code under else condition. I got an error.
ConcurrentModificationException
Using #kleopatra's ideas, you can filter the list and create the Series using the filtered data. Your requirements complicate things. Arrays.asList("Permanent", "2011", 5) also complicates things. It's bad practice in Java to create a List of different types. In my example, I used a HashMap to filter the data.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class App extends Application
{
#Override
public void start(Stage stage)
{
//create the chart
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Year");
final LineChart<String, Number> lineChart
= new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Employment Monitoring, 2020");
lineChart.getData().addAll(getData());
// show the scene.
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
/* How can I return the right value to the line chart ? */
private List<XYChart.Series<String, Number>> getData()
{
List<XYChart.Series<String, Number>> series = new ArrayList();
// Supposed that this data where values retrieved from the database
List<List> items = new ArrayList<>();
items.add(Arrays.asList("Permanent", "2011", 5));
items.add(Arrays.asList("Job Order", "2011", 16));
items.add(Arrays.asList("Permanent", "2012", 10));
items.add(Arrays.asList("Job Order", "2012", 19));
Map<String, List> map = new HashMap();
for (int i = 0; i < items.size(); i++) {
if (map.get(items.get(i).get(0).toString()) == null) {
List newEntry = new ArrayList();
newEntry.add(items.get(i).get(1));
newEntry.add(items.get(i).get(2));
map.put(items.get(i).get(0).toString(), newEntry);
System.out.println("Createing array " + items.get(i).get(0).toString() + " Adding " + items.get(i).get(1) + ":" + items.get(i).get(2));
}
else {
List oldList = map.get(items.get(i).get(0).toString());
oldList.add(items.get(i).get(1));
oldList.add(items.get(i).get(2));
System.out.println("Adding to array " + items.get(i).get(0).toString() + " Adding " + items.get(i).get(1) + ":" + items.get(i).get(2));
}
}
for (Map.Entry<String, List> entry : map.entrySet()) {
XYChart.Series<String, Number> tempItemsSeries = new XYChart.Series();
tempItemsSeries.setName(entry.getKey());
//System.out.println(entry.getValue().size() + Arrays.toString(entry.getValue().toArray()));
for (int i = 0; i < entry.getValue().size(); i = i + 2) {
tempItemsSeries.getData().add(new XYChart.Data(entry.getValue().get(i), entry.getValue().get(i + 1)));
}
series.add(tempItemsSeries);
}
return series;
}
public static void main(String[] args)
{
launch(args);
}
}
How to obtain the (x; y) coordinate XYChart.Data(x, y) from a plotted
chart symbol by clicking on it or passing the mouse cursor above it?
A label has to receive the obtained coordinate if the mouse has selected it.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class GetChartCoord extends Application {
#Override
public void start(Stage stage) {
VBox vbox = new VBox();
// Creating a chart
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
XYChart.Series series = new XYChart.Series();
series.setName("Example 1");
for (int x = 0; x <= 100; x++) {
double y = Math.random()*100;
series.getData().add(new XYChart.Data(x, y));
}
lineChart.getData().add(series);
// This label should receive the coordinate (x; y) from the dot that is
// on the mouse cursor or very next to it
Label labelXY = new Label();
labelXY.setText("(x; y)");
vbox.getChildren().addAll(lineChart, labelXY);
Scene scene = new Scene(vbox, 800, 600);
stage.setScene(scene);
stage.show();
}
}
EDIT:
The answer for that question mentioned by Sedrick solved my problem, but I had to adapt to adapt the code. So I will answer my own question by posting my modified code
Chart.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class ChangeSymbolSize extends Application {
#Override
public void start(Stage stage) {
// Random chart
// Defining the Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
// Creating the chart
LineChart<Number, Number> lineChart = new LineChart(xAxis, yAxis);
// Preparing the series
XYChart.Series series = new XYChart.Series();
series.setName("Grafico");
for (double x = 0; x <= 10; x++) {
double y = Math.random() * 100;
XYChart.Data chartData;
chartData = new XYChart.Data(x, y);
chartData.setNode(new ShowCoordinatesNode(x, y));
series.getData().add(chartData);
}
// Adding series to chart
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
ShowCoordinatesNode.java
import java.text.DecimalFormat;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
public class ShowCoordinatesNode extends StackPane {
public ShowCoordinatesNode(double x, double y) {
final Label label = createDataThresholdLabel(x, y);
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
setScaleX(1);
setScaleY(1);
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
private Label createDataThresholdLabel(double x, double y) {
DecimalFormat df = new DecimalFormat("0.##");
final Label label = new Label("(" + df.format(x) + "; " + df.format(y) + ")");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 10; -fx-font-weight: bold;");
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
return label;
}
}
I have written a sample program that generates random number of series plots using JavaFX Charts, but I can't seem to figure out how to get the color of each graph and assign it to a Checkbox that will be used to display or not display the graph. Basically I want to use the Checkboxes as a legend so that I can disable the standard legend.
Below is the complete program:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package testlinechartgraphs;
import java.util.ArrayList;
import java.util.Random;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TestLineChartGraphs extends Application {
final static ObservableList<XYChart.Series<Number, Number>> lineChartData = FXCollections.observableArrayList();
#Override
public void start(Stage stage) {
stage.setTitle("Line Chart Sample");
//defining the axes
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
Random randomNumbers = new Random();
ArrayList<Integer> arrayList = new ArrayList<>();
//creating the chart
final LineChart<Number, Number> lineChart
= new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setTitle("Stock Monitoring, 2010");
lineChart.setLegendSide(Side.RIGHT);
int randomCount = randomNumbers.nextInt(14)+1;
//System.out.println("randomCount = " + randomCount);
for (int i = 0; i < randomCount; i++) {
XYChart.Series series = new XYChart.Series();
series.setName("series_" + i);
for (int k = 0; k < 20; k++) {
int x = randomNumbers.nextInt(50);
series.getData().add(new XYChart.Data(k, x));
}
//seriesList.add(series);
lineChartData.add(series);
}
lineChart.setData(lineChartData);
// final StackPane chartContainer = new StackPane();
//
// Zoom zoom = new Zoom(lineChart, chartContainer);
// chartContainer.getChildren()
// .add(lineChart);
BorderPane borderPane = new BorderPane();
//borderPane.setCenter(chartContainer);
borderPane.setCenter(lineChart);
borderPane.setBottom(getLegend());
////
//Scene scene = new Scene(lineChart, 800, 600);
Scene scene = new Scene(borderPane, 800, 600);
//lineChart.getData().addAll(series, series1);
stage.setScene(scene);
//scene.getStylesheets().addAll("file:///C:/Users/siphoh/Documents/NetBeansProjects/WiresharkSeqNum/src/fancychart.css");
//scene.getStylesheets().addAll(getClass().getResource("fancychart.css").toExternalForm());
stage.show();
}
public static Node getLegend() {
HBox hBox = new HBox();
for (final XYChart.Series<Number, Number> series : lineChartData) {
CheckBox checkBox = new CheckBox(series.getName());
checkBox.setSelected(true);
checkBox.setOnAction(event -> {
if (lineChartData.contains(series)) {
lineChartData.remove(series);
} else {
lineChartData.add(series);
}
});
hBox.getChildren().add(checkBox);
}
hBox.setAlignment(Pos.CENTER);
hBox.setSpacing(20);
hBox.setStyle("-fx-padding: 0 10 20 10");
return hBox;
}
public static void main(String[] args) {
launch(args);
}
}
How can I implement this in the getLegend() method? any help will be appreciated.
Thanks,
Fred
I'm working on this code with Barchart and Piechart.
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Scene scene = new Scene(initGeneralAgentsData(), 800, 800);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
private final StackPane stackPane = new StackPane();
private List<DownloadTrafficObj> obj = new LinkedList<>();
public StackPane initGeneralAgentsData() throws Exception
{
stackPane.setAlignment(Pos.TOP_RIGHT);
stackPane.setStyle("-fx-background-color: white;");
SQLSelect(30);
stackPane.getChildren().addAll(chartChoose());
return stackPane;
}
private List<DownloadTrafficObj> SQLSelect(int history_value)
{
for (int i = 0; i < history_value; i++)
{
obj.add(new DownloadTrafficObj(String.valueOf(randomDate()), Long.valueOf(randomNumber())));
}
return obj;
}
private Timestamp randomDate()
{
long offset = Timestamp.valueOf("2012-01-01 00:00:00").getTime();
long end = Timestamp.valueOf("2013-01-01 00:00:00").getTime();
long diff = end - offset + 1;
Timestamp rand = new Timestamp(offset + (long) (Math.random() * diff));
return rand;
}
private int randomNumber()
{
Random rand = new Random();
int n = rand.nextInt(50) + 1;
return n;
}
public StackPane chartChoose()
{
final ComboBox comboBox = new ComboBox();
comboBox.getItems().addAll("Bar Chart", "Pie Chart");
ComboBox cb = new ComboBox();
cb.getItems().addAll(10, 20, 30, 60);
cb.setValue(30);
final StackPane stack = new StackPane();
comboBox.getSelectionModel().selectedIndexProperty()
.addListener((ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
-> setVisibility(stack, comboBox)
);
cb.getSelectionModel().selectedIndexProperty()
.addListener((ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
->
{
SQLSelect((int) cb.getSelectionModel().getSelectedItem());
bc.getData().clear();
generateBarChartData();
}
);
stack.getChildren().add(generateBarChart());
stack.getChildren().add(generatePieChart());
// Placing it after adding rectangle to stack
// will trigger the changelistener to show default rectangle
comboBox.setValue("Bar Chart");
VBox vBox = new VBox();
vBox.setPadding(new Insets(10, 10, 10, 10));
vBox.setSpacing(5);
Label labelon = new Label("Chart type");
Label label = new Label("Days history");
HBox hBossx = new HBox(15, labelon, comboBox, label, cb);
hBossx.setAlignment(Pos.CENTER_RIGHT);
ProgressIndicator progress = new ProgressIndicator();
progress.setMaxSize(90, 90);
Task<ObservableList<DownloadTrafficObj>> task = new Task<ObservableList<DownloadTrafficObj>>()
{
#Override
protected ObservableList<DownloadTrafficObj> call() throws Exception
{
for (int i = 0; i < 99; i++)
{
Thread.sleep(20);
}
return (FXCollections.observableArrayList(obj));
}
};
progress.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(ev ->
{
});
new Thread(task).start();
BorderPane bp = new BorderPane();
bp.centerProperty().bind(
Bindings
.when(task.runningProperty())
.then(progress)
.otherwise((ObservableObjectValue<ProgressIndicator>) stack));
vBox.getChildren().addAll(hBossx, bp);
StackPane root = new StackPane();
root.getChildren().add(vBox);
return root;
}
public void setVisibility(Pane pane, ComboBox comboBox)
{
// Make all children invisible
pane.getChildren().stream().forEach((node) ->
{
node.setVisible(false);
});
// make the selected rectangle visible
int selectedIndex = comboBox.getSelectionModel()
.selectedIndexProperty().getValue();
pane.getChildren().get(selectedIndex).setVisible(true);
}
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart<String, Number> bc = new BarChart<>(xAxis, yAxis);
XYChart.Series series1 = new XYChart.Series();
public BarChart<String, Number> generateBarChart()
{
bc.setTitle("Network Download");
xAxis.setLabel("Groups");
yAxis.setLabel("Value");
series1.setName("Network Download");
generateBarChartData();
// TO DO... Very quick fix.
bc.widthProperty().addListener((obs, b, b1) ->
{
// Chart Bar column is not automatically resized. We need to wait for next JavaFX releases to fix this.
Platform.runLater(() -> setMaxBarWidth(bc, xAxis, 40, 10));
});
bc.getData().addAll(series1);
return bc;
}
private void generateBarChartData()
{
obj.stream().map((get) -> new XYChart.Data(get.getDate(), get.getDownloadTraffic())).map((data) ->
{
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);
}
}
});
return data;
}).forEach((data) ->
{
series1.getData().add(data);
});
}
private void setMaxBarWidth(BarChart<String, Number> bc, CategoryAxis xAxis, double maxBarWidth, double minCategoryGap)
{
double barWidth = 0;
do
{
double catSpace = xAxis.getCategorySpacing();
double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap());
barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap();
if (barWidth > maxBarWidth)
{
avilableBarSpace = (maxBarWidth + bc.getBarGap()) * bc.getData().size();
bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
}
}
while (barWidth > maxBarWidth);
do
{
double catSpace = xAxis.getCategorySpacing();
double avilableBarSpace = catSpace - (minCategoryGap + bc.getBarGap());
barWidth = Math.min(maxBarWidth, (avilableBarSpace / bc.getData().size()) - bc.getBarGap());
avilableBarSpace = (barWidth + bc.getBarGap()) * bc.getData().size();
bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
}
while (barWidth < maxBarWidth && bc.getCategoryGap() > minCategoryGap);
}
public PieChart generatePieChart()
{
ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
obj.stream().forEach((activeAgentGroup) ->
{
pieChartData.add(new PieChart.Data(activeAgentGroup.getDate(), activeAgentGroup.getDownloadTraffic()));
});
final PieChart chart = new PieChart(pieChartData);
chart.setTitle("Label");
return chart;
}
private void displayLabelForData(XYChart.Data<String, Number> data)
{
final Node node = data.getNode();
final Text dataText = new Text(data.getYValue().toString());
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
)
);
}
});
}
}
I ant to add circular progress bar during switch of the charts and loading of the data. Usually it takes 2-3 seconds to load data from the database, so I need a way to display progress bay because the charts are stacked.
Also is there any much easy way to implement the switching of the charts?
Short and sweet:
Use a BorderPane as parent container for your charts.
Use Bindings, Task.runningProperty() and BorderPane.centerProperty()
For example something like this:
myBorderPane.centerProperty().bind(
Bindings
.when(myLongTask.runningProperty())
.then(myProggressIndicator)
.otherwise(myChart));
package javafx;
import java.util.ArrayList;
import java.util.List;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ImageSlide extends Application {
// Width and height of image in pixels
private final double IMG_WIDTH = 600;
private final double IMG_HEIGHT = 300;
private final int NUM_OF_IMGS = 3;
private final int SLIDE_FREQ = 4; // in secs
#Override
public void start(Stage stage) throws Exception {
//root code
StackPane root = new StackPane();
Pane clipPane = new Pane();
// To center the slide show incase maximized
clipPane.setMaxSize(IMG_WIDTH, IMG_HEIGHT);
clipPane.setClip(new Rectangle(IMG_WIDTH, IMG_HEIGHT));
HBox imgContainer = new HBox();
//image view
ImageView imgGreen = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged1.pngg")));
ImageView imgBlue = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged2.png")));
ImageView imgRose = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged3.png")));
imgContainer.getChildren().addAll(imgGreen, imgBlue, imgRose);
clipPane.getChildren().add(imgContainer);
root.getChildren().add(clipPane);
Scene scene = new Scene(root, IMG_WIDTH, IMG_HEIGHT);
stage.setTitle("Image Slider");
stage.setScene(scene);
startAnimation(imgContainer);
stage.show();
}
//start animation
private void startAnimation(final HBox hbox) {
//error occured on (ActionEvent t) line
//slide action
EventHandler<ActionEvent> slideAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
//eventHandler
EventHandler<ActionEvent> resetAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1), hbox);
trans.setByX((NUM_OF_IMGS - 1) * IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
List<KeyFrame> keyFrames = new ArrayList<>();
for (int i = 1; i <= NUM_OF_IMGS; i++) {
if (i == NUM_OF_IMGS) {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), resetAction));
} else {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), slideAction));
}
}
//add timeLine
Timeline anim = new Timeline(keyFrames.toArray(new KeyFrame[NUM_OF_IMGS]));
anim.setCycleCount(Timeline.INDEFINITE);
anim.playFromStart();
}
//call main function
public static void main(String[] args) {
launch(args);
}
}
The lines
EventHandler<ActionEvent> slideAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
should be
EventHandler<ActionEvent> slideAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
Note the only addition ->. Which IDE are you using?