google-site-verification: google61fe8ba583a51912.html
Real-Time Data Visualization in JavaFX

Overview

Real-time data visualization in JavaFX involves creating dynamic, interactive charts and dashboards that update in real-time. JavaFX provides powerful charting components and animation capabilities for building responsive data visualization applications.

1. Basic Real-Time Charts

Line Chart with Real-Time Updates

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; public class RealTimeLineChart extends Application { private ObservableList<XYChart.Data<Number, Number>> data; private Timeline animation; private double xValue = 0; private final int MAX_DATA_POINTS = 100; @Override public void start(Stage primaryStage) { // Create axes NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Time"); xAxis.setForceZeroInRange(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Value"); // Create line chart LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis); lineChart.setTitle("Real-Time Data Visualization"); lineChart.setAnimated(false); // Disable animation for better performance lineChart.setCreateSymbols(false); // Hide symbols for cleaner look // Create series XYChart.Series<Number, Number> series = new XYChart.Series<>(); series.setName("Sensor Data"); data = FXCollections.observableArrayList(); series.setData(data); lineChart.getData().add(series); // Setup animation setupAnimation(); BorderPane root = new BorderPane(lineChart); Scene scene = new Scene(root, 800, 600); primaryStage.setTitle("Real-Time Line Chart"); primaryStage.setScene(scene); primaryStage.show(); // Start animation animation.play(); } private void setupAnimation() { animation = new Timeline(new KeyFrame(Duration.millis(100), e -> { // Generate new data point double yValue = Math.sin(xValue * 0.1) * 50 + 50 + Math.random() * 10; // Add new data point data.add(new XYChart.Data<>(xValue, yValue)); // Remove old data points to prevent memory issues if (data.size() > MAX_DATA_POINTS) { data.remove(0); } xValue += 1; })); animation.setCycleCount(Animation.INDEFINITE); } public static void main(String[] args) { launch(args); } }

Multiple Real-Time Series

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; public class MultipleRealTimeSeries extends Application { private ObservableList<XYChart.Data<Number, Number>> series1Data; private ObservableList<XYChart.Data<Number, Number>> series2Data; private ObservableList<XYChart.Data<Number, Number>> series3Data; private Timeline animation; private double xValue = 0; private final int MAX_DATA_POINTS = 200; @Override public void start(Stage primaryStage) { // Create axes NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Time"); xAxis.setForceZeroInRange(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Value"); // Create line chart LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis); lineChart.setTitle("Multiple Real-Time Series"); lineChart.setAnimated(false); lineChart.setCreateSymbols(false); // Create multiple series XYChart.Series<Number, Number> series1 = createSeries("Temperature", "ff4444"); XYChart.Series<Number, Number> series2 = createSeries("Pressure", "44ff44"); XYChart.Series<Number, Number> series3 = createSeries("Humidity", "4444ff"); series1Data = FXCollections.observableArrayList(); series2Data = FXCollections.observableArrayList(); series3Data = FXCollections.observableArrayList(); series1.setData(series1Data); series2.setData(series2Data); series3.setData(series3Data); lineChart.getData().addAll(series1, series2, series3); // Setup animation setupAnimation(); BorderPane root = new BorderPane(lineChart); Scene scene = new Scene(root, 1000, 700); primaryStage.setTitle("Multiple Real-Time Series"); primaryStage.setScene(scene); primaryStage.show(); animation.play(); } private XYChart.Series<Number, Number> createSeries(String name, String color) { XYChart.Series<Number, Number> series = new XYChart.Series<>(); series.setName(name); // Apply CSS for color (would need additional CSS file) series.getNode().setStyle("-fx-stroke: #" + color + ";"); return series; } private void setupAnimation() { animation = new Timeline(new KeyFrame(Duration.millis(50), e -> { // Generate different patterns for each series double temp = 20 + 10 * Math.sin(xValue * 0.05) + Math.random() * 2; double pressure = 1000 + 50 * Math.cos(xValue * 0.03) + Math.random() * 5; double humidity = 50 + 30 * Math.sin(xValue * 0.02) + Math.random() * 3; // Add new data points addDataPoint(series1Data, xValue, temp); addDataPoint(series2Data, xValue, pressure); addDataPoint(series3Data, xValue, humidity); xValue += 0.5; })); animation.setCycleCount(Animation.INDEFINITE); } private void addDataPoint(ObservableList<XYChart.Data<Number, Number>> data, double x, double y) { data.add(new XYChart.Data<>(x, y)); // Remove old data points if (data.size() > MAX_DATA_POINTS) { data.remove(0); } } public static void main(String[] args) { launch(args); } }

2. Advanced Real-Time Dashboard

Comprehensive Dashboard with Multiple Charts

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.chart.*; import javafx.scene.control.Label; import javafx.scene.control.Tooltip; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Duration; import java.text.SimpleDateFormat; import java.util.Date; public class RealTimeDashboard extends Application { private Timeline animation; private double timeCounter = 0; // Data series private ObservableList<XYChart.Data<Number, Number>> cpuData; private ObservableList<XYChart.Data<Number, Number>> memoryData; private ObservableList<XYChart.Data<Number, Number>> networkData; private ObservableList<PieChart.Data> diskData; // UI Components private Label cpuLabel, memoryLabel, networkLabel, statusLabel; private LineChart<Number, Number> cpuChart, memoryChart, networkChart; private PieChart diskChart; @Override public void start(Stage primaryStage) { // Create main layout GridPane grid = new GridPane(); grid.setPadding(new Insets(10)); grid.setHgap(10); grid.setVgap(10); // Create charts cpuChart = createLineChart("CPU Usage", "%"); memoryChart = createLineChart("Memory Usage", "MB"); networkChart = createLineChart("Network I/O", "KB/s"); diskChart = createPieChart("Disk Usage"); // Create status labels VBox statusPanel = createStatusPanel(); // Add components to grid grid.add(cpuChart, 0, 0); grid.add(memoryChart, 1, 0); grid.add(networkChart, 0, 1); grid.add(diskChart, 1, 1); grid.add(statusPanel, 0, 2, 2, 1); // Initialize data initializeData(); // Setup animation setupAnimation(); Scene scene = new Scene(grid, 1200, 800); scene.getStylesheets().add(getClass().getResource("/dashboard.css").toExternalForm()); primaryStage.setTitle("Real-Time System Monitoring Dashboard"); primaryStage.setScene(scene); primaryStage.show(); animation.play(); } private LineChart<Number, Number> createLineChart(String title, String yLabel) { NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Time (s)"); xAxis.setForceZeroInRange(false); xAxis.setAutoRanging(false); xAxis.setLowerBound(0); xAxis.setUpperBound(60); xAxis.setTickUnit(10); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel(yLabel); LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis); chart.setTitle(title); chart.setAnimated(false); chart.setCreateSymbols(false); chart.setLegendVisible(false); return chart; } private PieChart createPieChart(String title) { PieChart chart = new PieChart(); chart.setTitle(title); chart.setLabelsVisible(true); chart.setLegendVisible(false); return chart; } private VBox createStatusPanel() { VBox statusPanel = new VBox(10); statusPanel.setPadding(new Insets(10)); statusPanel.setStyle("-fx-background-color: #f4f4f4; -fx-border-color: #cccccc; -fx-border-width: 1;"); Label title = new Label("System Status"); title.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;"); cpuLabel = createStatusLabel("CPU: --%"); memoryLabel = createStatusLabel("Memory: --/-- MB"); networkLabel = createStatusLabel("Network: -- KB/s"); statusLabel = createStatusLabel("Last Update: --"); statusPanel.getChildren().addAll(title, cpuLabel, memoryLabel, networkLabel, statusLabel); return statusPanel; } private Label createStatusLabel(String text) { Label label = new Label(text); label.setStyle("-fx-font-size: 14px;"); return label; } private void initializeData() { // Initialize CPU chart XYChart.Series<Number, Number> cpuSeries = new XYChart.Series<>(); cpuData = FXCollections.observableArrayList(); cpuSeries.setData(cpuData); cpuChart.getData().add(cpuSeries); // Initialize Memory chart XYChart.Series<Number, Number> memorySeries = new XYChart.Series<>(); memoryData = FXCollections.observableArrayList(); memorySeries.setData(memoryData); memoryChart.getData().add(memorySeries); // Initialize Network chart XYChart.Series<Number, Number> networkSeries = new XYChart.Series<>(); networkData = FXCollections.observableArrayList(); networkSeries.setData(networkData); networkChart.getData().add(networkSeries); // Initialize Disk chart diskData = FXCollections.observableArrayList( new PieChart.Data("Used", 40), new PieChart.Data("Free", 60) ); diskChart.setData(diskData); // Style pie chart slices stylePieChart(); } private void stylePieChart() { diskChart.getData().forEach(data -> { String color = data.getName().equals("Used") ? "#ff4444" : "#44ff44"; data.getNode().setStyle("-fx-pie-color: " + color + ";"); }); } private void setupAnimation() { animation = new Timeline(new KeyFrame(Duration.millis(500), e -> { updateCharts(); updateStatus(); })); animation.setCycleCount(Animation.INDEFINITE); } private void updateCharts() { // Simulate system metrics double cpuUsage = 20 + 30 * Math.sin(timeCounter * 0.1) + Math.random() * 10; double memoryUsage = 800 + 200 * Math.cos(timeCounter * 0.05) + Math.random() * 50; double networkUsage = 100 + 80 * Math.sin(timeCounter * 0.2) + Math.random() * 20; // Update line charts updateLineChart(cpuChart, cpuData, cpuUsage); updateLineChart(memoryChart, memoryData, memoryUsage); updateLineChart(networkChart, networkData, networkUsage); // Update pie chart with some variation double usedSpace = 40 + 10 * Math.sin(timeCounter * 0.05); double freeSpace = 100 - usedSpace; diskData.get(0).setPieValue(usedSpace); diskData.get(1).setPieValue(freeSpace); timeCounter += 0.5; } private void updateLineChart(LineChart<Number, Number> chart, ObservableList<XYChart.Data<Number, Number>> data, double value) { data.add(new XYChart.Data<>(timeCounter, value)); // Remove old data points if (data.size() > 120) { // 60 seconds at 0.5s intervals data.remove(0); } // Update X-axis range NumberAxis xAxis = (NumberAxis) chart.getXAxis(); xAxis.setLowerBound(Math.max(0, timeCounter - 60)); xAxis.setUpperBound(timeCounter); } private void updateStatus() { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); String timestamp = sdf.format(new Date()); if (!cpuData.isEmpty()) { double latestCpu = cpuData.get(cpuData.size() - 1).getYValue().doubleValue(); cpuLabel.setText(String.format("CPU: %.1f%%", latestCpu)); } if (!memoryData.isEmpty()) { double latestMemory = memoryData.get(memoryData.size() - 1).getYValue().doubleValue(); memoryLabel.setText(String.format("Memory: %.0f MB", latestMemory)); } if (!networkData.isEmpty()) { double latestNetwork = networkData.get(networkData.size() - 1).getYValue().doubleValue(); networkLabel.setText(String.format("Network: %.1f KB/s", latestNetwork)); } statusLabel.setText("Last Update: " + timestamp); } public static void main(String[] args) { launch(args); } }

3. Stock Market Real-Time Visualization

Real-Time Stock Ticker

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; 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.scene.control.Label; import javafx.scene.control.Tooltip; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Duration; import java.text.DecimalFormat; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.Random; public class StockMarketVisualization extends Application { private Timeline animation; private ObservableList<XYChart.Data<String, Number>> stockData; private ObservableList<XYChart.Data<String, Number>> volumeData; private double lastPrice = 100.0; // Initial price private Random random = new Random(); private DecimalFormat priceFormat = new DecimalFormat("$#0.00"); private DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HH:mm:ss"); @Override public void start(Stage primaryStage) { // Create main layout VBox root = new VBox(10); root.setPadding(new Insets(10)); // Create header with stock info HBox header = createHeader(); // Create charts LineChart<String, Number> priceChart = createPriceChart(); LineChart<String, Number> volumeChart = createVolumeChart(); root.getChildren().addAll(header, priceChart, volumeChart); // Initialize data initializeData(priceChart, volumeChart); // Setup animation setupAnimation(); Scene scene = new Scene(root, 1000, 700); primaryStage.setTitle("Real-Time Stock Market Visualization"); primaryStage.setScene(scene); primaryStage.show(); animation.play(); } private HBox createHeader() { HBox header = new HBox(20); header.setPadding(new Insets(10)); header.setStyle("-fx-background-color: #2c3e50; -fx-border-color: #34495e; -fx-border-width: 2;"); Label stockLabel = new Label("AAPL - Apple Inc."); stockLabel.setStyle("-fx-text-fill: white; -fx-font-size: 24px; -fx-font-weight: bold;"); Label priceLabel = new Label(priceFormat.format(lastPrice)); priceLabel.setStyle("-fx-text-fill: #2ecc71; -fx-font-size: 24px; -fx-font-weight: bold;"); priceLabel.setId("current-price"); Label changeLabel = new Label("+0.00 (0.00%)"); changeLabel.setStyle("-fx-text-fill: #2ecc71; -fx-font-size: 16px;"); changeLabel.setId("price-change"); header.getChildren().addAll(stockLabel, priceLabel, changeLabel); return header; } private LineChart<String, Number> createPriceChart() { CategoryAxis xAxis = new CategoryAxis(); xAxis.setLabel("Time"); xAxis.setAnimated(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Price ($)"); yAxis.setAutoRanging(true); LineChart<String, Number> chart = new LineChart<>(xAxis, yAxis); chart.setTitle("Stock Price"); chart.setAnimated(false); chart.setCreateSymbols(false); chart.setLegendVisible(false); return chart; } private LineChart<String, Number> createVolumeChart() { CategoryAxis xAxis = new CategoryAxis(); xAxis.setLabel("Time"); xAxis.setAnimated(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Volume"); yAxis.setAutoRanging(true); LineChart<String, Number> chart = new LineChart<>(xAxis, yAxis); chart.setTitle("Trading Volume"); chart.setAnimated(false); chart.setCreateSymbols(false); chart.setLegendVisible(false); return chart; } private void initializeData(LineChart<String, Number> priceChart, LineChart<String, Number> volumeChart) { // Initialize price data XYChart.Series<String, Number> priceSeries = new XYChart.Series<>(); stockData = FXCollections.observableArrayList(); priceSeries.setData(stockData); priceChart.getData().add(priceSeries); // Initialize volume data XYChart.Series<String, Number> volumeSeries = new XYChart.Series<>(); volumeData = FXCollections.observableArrayList(); volumeSeries.setData(volumeData); volumeChart.getData().add(volumeSeries); // Add some initial data points LocalTime time = LocalTime.now().minusSeconds(60); for (int i = 0; i < 10; i++) { String timeStr = time.plusSeconds(i * 6).format(timeFormat); stockData.add(new XYChart.Data<>(timeStr, lastPrice)); volumeData.add(new XYChart.Data<>(timeStr, 1000000 + random.nextInt(500000))); } } private void setupAnimation() { animation = new Timeline(new KeyFrame(Duration.millis(1000), e -> { updateStockData(); })); animation.setCycleCount(Animation.INDEFINITE); } private void updateStockData() { // Simulate stock price movement (geometric Brownian motion) double volatility = 0.02; double drift = 0.001; double randomFactor = random.nextGaussian(); double change = lastPrice * (drift + volatility * randomFactor); double newPrice = lastPrice + change; // Ensure price doesn't go negative newPrice = Math.max(newPrice, 0.1); // Generate volume int volume = 1000000 + random.nextInt(1000000); // Get current time String currentTime = LocalTime.now().format(timeFormat); // Add new data points stockData.add(new XYChart.Data<>(currentTime, newPrice)); volumeData.add(new XYChart.Data<>(currentTime, volume)); // Remove old data points (keep last 30 points) if (stockData.size() > 30) { stockData.remove(0); volumeData.remove(0); } // Update header updateHeader(newPrice, lastPrice); lastPrice = newPrice; } private void updateHeader(double newPrice, double oldPrice) { double change = newPrice - oldPrice; double changePercent = (change / oldPrice) * 100; // Find the price label and update it Scene scene = ((Label) scene.lookup("#current-price")).getScene(); Label priceLabel = (Label) scene.lookup("#current-price"); Label changeLabel = (Label) scene.lookup("#price-change"); if (priceLabel != null) { priceLabel.setText(priceFormat.format(newPrice)); // Set color based on price change String color = change >= 0 ? "#2ecc71" : "#e74c3c"; priceLabel.setStyle("-fx-text-fill: " + color + "; -fx-font-size: 24px; -fx-font-weight: bold;"); } if (changeLabel != null) { String sign = change >= 0 ? "+" : ""; changeLabel.setText(String.format("%s%.2f (%.2f%%)", sign, change, changePercent)); changeLabel.setStyle("-fx-text-fill: " + color + "; -fx-font-size: 16px;"); } } public static void main(String[] args) { launch(args); } }

4. Real-Time Data Streaming with WebSocket

WebSocket Data Source with JavaFX

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Duration; import javax.websocket.*; import java.io.IOException; import java.net.URI; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @ClientEndpoint public class WebSocketRealTimeChart extends Application { private Session session; private BlockingQueue<Double> dataQueue = new LinkedBlockingQueue<>(); private ObservableList<XYChart.Data<Number, Number>> data; private Timeline animation; private double xValue = 0; private Label connectionStatus; private Button connectButton; @Override public void start(Stage primaryStage) { // Create UI components LineChart<Number, Number> chart = createChart(); HBox controlPanel = createControlPanel(); // Initialize data initializeData(chart); // Setup animation for processing queued data setupAnimation(); BorderPane root = new BorderPane(); root.setTop(controlPanel); root.setCenter(chart); Scene scene = new Scene(root, 800, 600); primaryStage.setTitle("WebSocket Real-Time Data Visualization"); primaryStage.setScene(scene); primaryStage.show(); } private LineChart<Number, Number> createChart() { NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Time"); xAxis.setForceZeroInRange(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Value"); LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis); chart.setTitle("Real-Time WebSocket Data"); chart.setAnimated(false); chart.setCreateSymbols(false); return chart; } private HBox createControlPanel() { HBox controlPanel = new HBox(10); controlPanel.setStyle("-fx-padding: 10; -fx-background-color: #f0f0f0;"); connectionStatus = new Label("Disconnected"); connectionStatus.setStyle("-fx-text-fill: red; -fx-font-weight: bold;"); connectButton = new Button("Connect"); connectButton.setOnAction(e -> toggleConnection()); Button clearButton = new Button("Clear"); clearButton.setOnAction(e -> clearData()); controlPanel.getChildren().addAll(connectButton, connectionStatus, clearButton); return controlPanel; } private void initializeData(LineChart<Number, Number> chart) { XYChart.Series<Number, Number> series = new XYChart.Series<>(); series.setName("Live Data"); data = FXCollections.observableArrayList(); series.setData(data); chart.getData().add(series); } private void setupAnimation() { animation = new Timeline(new KeyFrame(Duration.millis(100), e -> { processQueuedData(); })); animation.setCycleCount(Animation.INDEFINITE); animation.play(); } private void processQueuedData() { // Process all available data in the queue while (!dataQueue.isEmpty()) { Double value = dataQueue.poll(); if (value != null) { Platform.runLater(() -> { data.add(new XYChart.Data<>(xValue, value)); xValue += 1; // Keep only last 100 points if (data.size() > 100) { data.remove(0); } }); } } } private void toggleConnection() { if (session == null || !session.isOpen()) { connectToWebSocket(); } else { disconnectFromWebSocket(); } } private void connectToWebSocket() { try { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); session = container.connectToServer(this, URI.create("ws://localhost:8080/websocket/data")); Platform.runLater(() -> { connectionStatus.setText("Connected"); connectionStatus.setStyle("-fx-text-fill: green; -fx-font-weight: bold;"); connectButton.setText("Disconnect"); }); } catch (Exception e) { Platform.runLater(() -> { connectionStatus.setText("Connection Failed"); connectionStatus.setStyle("-fx-text-fill: red; -fx-font-weight: bold;"); }); e.printStackTrace(); } } private void disconnectFromWebSocket() { if (session != null && session.isOpen()) { try { session.close(); } catch (IOException e) { e.printStackTrace(); } } Platform.runLater(() -> { connectionStatus.setText("Disconnected"); connectionStatus.setStyle("-fx-text-fill: red; -fx-font-weight: bold;"); connectButton.setText("Connect"); }); session = null; } private void clearData() { Platform.runLater(() -> { data.clear(); xValue = 0; }); } @OnOpen public void onOpen(Session session) { System.out.println("WebSocket connected: " + session.getId()); } @OnMessage public void onMessage(String message) { try { // Parse the incoming message (assuming it's a number) double value = Double.parseDouble(message); dataQueue.offer(value); } catch (NumberFormatException e) { System.err.println("Invalid data format: " + message); } } @OnClose public void onClose(Session session, CloseReason closeReason) { System.out.println("WebSocket closed: " + closeReason.getReasonPhrase()); Platform.runLater(() -> { connectionStatus.setText("Disconnected"); connectionStatus.setStyle("-fx-text-fill: red; -fx-font-weight: bold;"); connectButton.setText("Connect"); }); } @OnError public void onError(Session session, Throwable throwable) { System.err.println("WebSocket error: " + throwable.getMessage()); throwable.printStackTrace(); } public static void main(String[] args) { launch(args); } }

5. Performance Optimization Techniques

Efficient Real-Time Chart Updates

import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import java.util.concurrent.atomic.AtomicLong; public class OptimizedRealTimeChart extends Application { private static final int MAX_POINTS = 1000; private static final int UPDATE_INTERVAL_MS = 16; // ~60 FPS private ObservableList<XYChart.Data<Number, Number>> data; private AtomicLong dataPointsAdded = new AtomicLong(0); private long startTime; @Override public void start(Stage primaryStage) { // Create optimized chart LineChart<Number, Number> chart = createOptimizedChart(); // Initialize data initializeData(chart); // Setup high-performance animation setupHighPerformanceAnimation(); BorderPane root = new BorderPane(chart); Scene scene = new Scene(root, 1000, 600); primaryStage.setTitle("Optimized Real-Time Chart"); primaryStage.setScene(scene); primaryStage.show(); startTime = System.currentTimeMillis(); } private LineChart<Number, Number> createOptimizedChart() { NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Time"); xAxis.setForceZeroInRange(false); xAxis.setAutoRanging(false); xAxis.setAnimated(false); NumberAxis yAxis = new NumberAxis(); yAxis.setLabel("Value"); yAxis.setAutoRanging(true); yAxis.setAnimated(false); LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis); chart.setTitle("High-Performance Real-Time Data"); chart.setAnimated(false); // Critical for performance chart.setCreateSymbols(false); // Improves performance chart.setLegendVisible(false); return chart; } private void initializeData(LineChart<Number, Number> chart) { XYChart.Series<Number, Number> series = new XYChart.Series<>(); data = FXCollections.observableArrayList(); series.setData(data); chart.getData().add(series); } private void setupHighPerformanceAnimation() { Timeline animation = new Timeline(new KeyFrame( Duration.millis(UPDATE_INTERVAL_MS), e -> updateData() )); animation.setCycleCount(Animation.INDEFINITE); animation.play(); } private void updateData() { long currentTime = System.currentTimeMillis() - startTime; double value = generateDataValue(currentTime); // Add new data point data.add(new XYChart.Data<>(currentTime / 1000.0, value)); dataPointsAdded.incrementAndGet(); // Efficiently manage data size if (data.size() > MAX_POINTS) { // Remove in chunks for better performance int pointsToRemove = data.size() - MAX_POINTS; if (pointsToRemove > 0) { data.remove(0, pointsToRemove); } } // Update X-axis range to show recent data if (!data.isEmpty()) { double latestX = data.get(data.size() - 1).getXValue().doubleValue(); double windowSize = 60.0; // Show last 60 seconds NumberAxis xAxis = (NumberAxis) ((LineChart<Number, Number>) data.get(0).getChart()).getXAxis(); xAxis.setLowerBound(Math.max(0, latestX - windowSize)); xAxis.setUpperBound(latestX); } } private double generateDataValue(double time) { // Simulate multiple frequency components double baseFreq = 0.1; double highFreq = 1.0; double noise = Math.random() * 2 - 1; return 50 + 20 * Math.sin(time * 0.001 * baseFreq) + 10 * Math.sin(time * 0.001 * highFreq) + noise; } // Method to get performance statistics public void printPerformanceStats() { long totalTime = System.currentTimeMillis() - startTime; double pointsPerSecond = (dataPointsAdded.get() * 1000.0) / totalTime; System.out.printf("Performance Stats:%n"); System.out.printf("Total data points: %d%n", dataPointsAdded.get()); System.out.printf("Total time: %.2f seconds%n", totalTime / 1000.0); System.out.printf("Points per second: %.2f%n", pointsPerSecond); System.out.printf("Current data size: %d%n", data.size()); } public static void main(String[] args) { launch(args); } }

Key Features Covered:

  1. Basic Real-Time Charts - Simple line charts with live updates
  2. Multiple Series - Handling multiple data streams
  3. Dashboard Layout - Comprehensive monitoring interface
  4. Stock Market Visualization - Financial data with real-time updates
  5. WebSocket Integration - Real-time data streaming
  6. Performance Optimization - Efficient data handling and rendering

These examples demonstrate how to create responsive, real-time data visualizations in JavaFX with proper performance considerations and modern UI patterns.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper