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。也许这会有所帮助
我想通过鼠标拖动或缩放按钮实现对实时折线图(图表每 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。也许这会有所帮助