Search code examples
javajavafxnetbeans-8javafx-css

Java Fx - Zoom in functionality to a Real time Chart


I want to implement zoom in functionality to a real time line chart(chart will move every 50ms) with mouse drag or with zoom button. i want to zoom in the particular area..but whats the problem i faced is every time the (x,y) co-ordinate values are changing in graph. is there any way to zoom in this chart ??

the JavaFx sample code is here..

    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javafx.animation.AnimationTimer;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import static javafx.application.Application.launch;
    import javafx.scene.Scene;
    import javafx.scene.chart.LineChart;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.chart.XYChart.Data;
    import javafx.scene.chart.XYChart.Series;
    import javafx.stage.Stage;



    public class MainApp extends Application {

    private static final int MAX_DATA_POINTS = 100;

    private Series series;
    private int xSeriesData = 100;
    private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
    private ExecutorService executor;
    private AddToQueue addToQueue;
    private Timeline timeline2;
    private NumberAxis xAxis;

    private void init(Stage primaryStage) throws Exception {

        xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 100);
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);

        NumberAxis yAxis = new NumberAxis();
        yAxis.setAutoRanging(true);

        //-- Chart
        final LineChart<Number, Number> sc = new LineChart<Number, Number>(xAxis, yAxis) {
            // Override to remove symbols on each data point            
            @Override
            protected void dataItemAdded(Series<Number, Number> series, int itemIndex, Data<Number, Number> item) {

            }
        };
        sc.setAnimated(false);
        sc.setId("liveAreaChart");
        sc.setTitle("RealTime Area Chart");

        //-- Chart Series
        series = new LineChart.Series<Number, Number>();
        series.setName("Area Chart Series");
        sc.getData().add(series);

        primaryStage.setScene(new Scene(sc));
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        init(primaryStage);
        primaryStage.show();

        executor = Executors.newCachedThreadPool();

        addToQueue = new AddToQueue();

        executor.execute(addToQueue);

        //-- Prepare Timeline
        prepareTimeline();

    }

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

    private class AddToQueue implements Runnable {

        public void run() {
            try {

                dataQ.add(Math.random());

                Thread.sleep(50);

                executor.execute(this);

            } catch (InterruptedException ex) {

                Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    //-- Timeline gets called in the JavaFX Main thread
    private void prepareTimeline() {
        // Every frame to take any data from queue and add to chart

        new AnimationTimer() {

            @Override
            public void handle(long now) {

                addDataToSeries();

            }
        }.start();

    }

    private void addDataToSeries() {

        for (int i = 0; i < 20; i++) {

            if (dataQ.isEmpty()) {

                break;
            }

            series.getData().add(new LineChart.Data(xSeriesData++, dataQ.remove()));

        }
        // remove points to keep us at no more than MAX_DATA_POINTS
        if (series.getData().size() > MAX_DATA_POINTS) {
            series.getData().remove(0, series.getData().size() - MAX_DATA_POINTS);
        }

        // update 
        xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
        int m = xSeriesData - MAX_DATA_POINTS;

        xAxis.setUpperBound(xSeriesData - 1);
        int j = xSeriesData - 1;

    }

}

and i have used the zoom manager code from https://github.com/kerner1000/javafx-chart-zooming/blob/master/src/main/java/com/github/javafx/charts/zooming/ZoomManager.java but Mouse released fuction is not calling.

Thanks in Advance :)


Solution

  • Here the thing is your not calling the Eventhandler(Mouse Drag and mouse Release)

    public void start(Stage stage) {
                    (do your stuff)
          pane.setOnMouseClicked(mouseHandler);
            pane.setOnMouseDragged(mouseHandler);
            pane.setOnMouseEntered(mouseHandler);
            pane.setOnMouseExited(mouseHandler);
            pane.setOnMouseMoved(mouseHandler);
            pane.setOnMousePressed(mouseHandler);
            pane.setOnMouseReleased(mouseHandler);
    }
    
    
    1. In mouseDrag Event you take Xaxiz and Yaxis  
    
    2.In mouseRelease Event you can Change in
    Lowerbound and upperbound value in to the chart
    
    
     EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() {
            //Tooltip tooltip = new Tooltip();
            final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
    
            @Override
            public void handle(MouseEvent mouseEvent) {
                if (mouseEvent.getButton() == MouseButton.PRIMARY) {
                    if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
                        rect.setX(mouseEvent.getX());
                        rect.setY(mouseEvent.getY());
                        rectinitX.set(mouseEvent.getX());
                        rectinitY.set(mouseEvent.getY());
                        System.out.println("rect:" + rect);
                        mouseAnchor.set(new Point2D(mouseEvent.getX(), mouseEvent.getY()));
                        System.out.println("mouseEvent X: " + mouseEvent.getSceneX());
                        System.out.println("mouseEvent y: " + mouseEvent.getSceneY());
                        System.out.println("mouseAnchor : " + mouseAnchor);
                        //  MAX_DATA_POINTS = 100;
                        //  MAX_DATA_POINTS_LOWER = 1;
                        //  tooltip();
                    } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
                        rectX.set(mouseEvent.getX());
                        rectY.set(mouseEvent.getY());
                        rect.setX(Math.min(mouseEvent.getX(), mouseAnchor.get().getX()));
                        rect.setY(Math.min(mouseEvent.getY(), mouseAnchor.get().getY()));
    //            rect.setWidth(Math.abs(mouseEvent.getX() - mouseAnchor.get().getX()));
    //            rect.setHeight(Math.abs(mouseEvent.getY() - mouseAnchor.get().getY()));
                        System.out.println("  MOUSE_DRAGGED ");
                    } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) {
                        System.out.println("  MOUSE_RELEASED ");
                        if ((rectinitX.get() >= rectX.get()) && (rectinitY.get() >= rectY.get())) {
                            //Condizioni Iniziali
                            LineChart lineChart = lineChart2;
    
                            // ((CategoryAxis) lineChart.getXAxis()).setLowerBound(initXLowerBound);
                            //((CategoryAxis) lineChart.getXAxis()).setUpperBound(initXUpperBound);
                            ((NumberAxis) lineChart.getYAxis()).setLowerBound(initYLowerBound);
                            ((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound);
                            System.out.println("  Inside IF ");
    
                        } else {
                            //Zoom In
                            System.out.println("  Inside else ");
    
                            double Tgap = 0, Tgap1 = 0;
                            double newLowerBound, newUpperBound, axisShift, axisShifX, newXlower, newXupper;
                            double xScaleFactor, yScaleFactor;
                            double xaxisShift, yaxisShift;
                            LineChart lineChart = lineChart2;
    
                            // Zoom in Y-axis by changing bound range.            
                            NumberAxis yAxis = (NumberAxis) lineChart.getYAxis();
                            NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();
                            System.out.println("X " + xAxis + " Y " + yAxis);
                            Tgap = yAxis.getHeight() / (yAxis.getUpperBound() - yAxis.getLowerBound());
    
                            // Tgap1 = xAxis.getHeight()/(xAxis.getUpperBound() - xAxis.getLowerBound());
                            axisShift = getSceneShiftY(yAxis);
                            yaxisShift = axisShift;
                            xaxisShift = getSceneShiftX(xAxis);
                            System.out.println("yAxisUPPER:" + yAxis.getUpperBound() + "yAxisLOWER:" + yAxis.getLowerBound());
                            newUpperBound = yAxis.getUpperBound() - ((rectinitY.get() - axisShift) / Tgap);
                            newLowerBound = yAxis.getUpperBound() - ((rectY.get() - axisShift) / Tgap);
    
                            if (newUpperBound > yAxis.getUpperBound()) {
                                newUpperBound = yAxis.getUpperBound();
                            }
    
                            yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound()) / (newUpperBound - newLowerBound);
    
                            System.out.println("newLowerBound " + newLowerBound + "newUpperBound " + newUpperBound);
                            yAxis.setLowerBound(newLowerBound);
                            yAxis.setUpperBound(newUpperBound);
    
                            Tgap1 = xAxis.getWidth() / (xAxis.getUpperBound() - xAxis.getLowerBound());
    
                            newXlower = ((rectinitX.get() - xaxisShift) / Tgap1) + xAxis.getLowerBound();
                            newXupper = ((rectX.get() - xaxisShift) / Tgap1) + xAxis.getLowerBound();
                            System.out.println("newLowerBoundX " + newXlower + "newUpperBoundX " + newXupper);
                            if (newXupper > xAxis.getUpperBound()) {
                                newXupper = xAxis.getUpperBound();
                            }
    
                            xAxis.setLowerBound(newXlower);
                            MAX_DATA_POINTS_LOWER = (int) newXlower;
                            MAX_DATA_POINTS = (int) newXupper;
                            xAxis.setUpperBound(newXupper);
    
                        }
                        // Hide the rectangle
                        rectX.set(0);
                        rectY.set(0);
                    } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_MOVED) {
                        System.out.println(" MOUSE_MOVED " + mouseEvent.getX() + " " + mouseEvent.getY());
    //              Tooltip.install(series.getNode(), new Tooltip(
    //                        mouseEvent.getX() + "\n" +
    //                                "Number Of Events : " + mouseEvent.getY())); 
                    }
                } else if (mouseEvent.getButton() == MouseButton.SECONDARY) {
                    System.out.println("  SECONDARY ");
                    MAX_DATA_POINTS = 100;
                    MAX_DATA_POINTS_LOWER = 1;
                }// end if (mouseEvent.getButton() == MouseButton.PRIMARY)
                else if (mouseEvent.getButton() == MouseButton.NONE) {
                    System.out.println(" NONE " + mouseEvent.getX() + " " + mouseEvent.getY());
    
                }
            }
        };