Java Fx - 放大实时图表的功能

Java Fx - Zoom in functionality to a Real time Chart

我想通过鼠标拖动或缩放按钮实现对实时折线图(图表每 50 毫秒移动一次)的放大功能。我想放大特定区域..但是我遇到的问题是每次 (x,y) 坐标值在图形中发生变化。有什么办法可以放大这个图表吗??

JavaFx 示例代码在这里..

    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;

    }

}

并且我使用了 https://github.com/kerner1000/javafx-chart-zooming/blob/master/src/main/java/com/github/javafx/charts/zooming/ZoomManager.java 中的缩放管理器代码 但是鼠标释放功能没有调用。

提前致谢:)

问题是你没有调用事件处理程序(鼠标拖动和鼠标释放)

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());

            }
        }
    };

因为原生图表不提供缩放、平移等功能,我已经使用 plotly.js 图表实现了一个库。 你可以看看 github 是 open-source。也许这会有所帮助

https://github.com/jasrodis/javafx-dataviewer/