Javafx 2 chart zoom
javafx-2, zooming
Solution
You attached mouse event to Scene. So `mouseEvent.getX()` gives you coordinates relative to scene. But your formula uses them as coordinates relative to `xAxis` node. You need to take into account `xAxis` location on scene.
Introduce next method:
// summ layout shift against parent until we ascend to scene
private static double getSceneShift(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
and change your calculations accordingly:
double xAxisShift = getSceneShift(xAxis);
newXlower = ((rectinitX.get() - xAxisShift) / Tgap) + xAxis.getLowerBound();
newXupper = ((rectX.get() - xAxisShift) / Tgap) + xAxis.getLowerBound();
Problem
When I do select a chart region my zoom get a "little switch". In example if do select from tick 3 up to tick 6 I obtain as lower bound:3.67 and upper bound 6.74. How to fix it ? Any help really appreciated. ``` package testjavafxzoom; import javafx.application.Application; import javafx.beans.property.SimpleDoubleProperty; import javafx.event.EventHandler; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.chart.LineChart; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.paint.Color; import javafx.scene.shape.LineTo; import javafx.scene.shape.MoveTo; import javafx.scene.shape.Path; import javafx.scene.shape.Rectangle; public class Zoom01 extends Application { Path path;//Add path for freehand BorderPane pane; Rectangle rect; SimpleDoubleProperty rectinitX = new SimpleDoubleProperty(); SimpleDoubleProperty rectinitY = new SimpleDoubleProperty(); SimpleDoubleProperty rectX = new SimpleDoubleProperty(); SimpleDoubleProperty rectY = new SimpleDoubleProperty(); @Override public void start(Stage stage) { System.out.println("Java Version : " + com.sun.javafx.runtime.VersionInfo.getVersion()); System.out.println("Java getHudsonBuildNumber: " + com.sun.javafx.runtime.VersionInfo.getHudsonBuildNumber()); System.out.println("Java getReleaseMilestone : " + com.sun.javafx.runtime.VersionInfo.getReleaseMilestone()); System.out.println("Java getRuntimeVersion : " + com.sun.javafx.runtime.VersionInfo.getRuntimeVersion()); stage.setTitle("Lines plot"); //final CategoryAxis xAxis = new CategoryAxis(); final NumberAxis xAxis = new NumberAxis(1, 12, 1); final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005); yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { @Override public String toString(Number object) { return String.format("%7.5f", object); } }); //final LineChart<String, Number> lineChart = new LineChart<String, Number>(xAxis, yAxis); final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis); //lineChart.setTitle("Stock quotes"); lineChart.setCreateSymbols(false); lineChart.setAlternativeRowFillVisible(false); lineChart.setAnimated(true); XYChart.Series series1 = new XYChart.Series(); //series1.setName("Stock 1"); series1.getData().add(new XYChart.Data(1, 0.53185)); series1.getData().add(new XYChart.Data(2, 0.532235)); series1.getData().add(new XYChart.Data(3, 0.53234)); series1.getData().add(new XYChart.Data(4, 0.538765)); series1.getData().add(new XYChart.Data(5, 0.53442)); series1.getData().add(new XYChart.Data(6, 0.534658)); series1.getData().add(new XYChart.Data(7, 0.53023)); series1.getData().add(new XYChart.Data(8, 0.53001)); series1.getData().add(new XYChart.Data(9, 0.53589)); series1.getData().add(new XYChart.Data(10, 0.53476)); series1.getData().add(new XYChart.Data(11, 0.530123)); series1.getData().add(new XYChart.Data(12, 0.53035)); pane = new BorderPane(); pane.setCenter(lineChart); //Scene scene = new Scene(lineChart, 800, 600); Scene scene = new Scene(pane, 800, 600); lineChart.getData().addAll(series1); stage.setScene(scene); path = new Path(); path.setStrokeWidth(1); path.setStroke(Color.BLACK); scene.setOnMouseClicked(mouseHandler); scene.setOnMouseDragged(mouseHandler); scene.setOnMouseEntered(mouseHandler); scene.setOnMouseExited(mouseHandler); scene.setOnMouseMoved(mouseHandler); scene.setOnMousePressed(mouseHandler); scene.setOnMouseReleased(mouseHandler); //root.getChildren().add(lineChart); pane.getChildren().add(path); rect = new Rectangle(); rect.setFill(Color.web("blue", 0.1)); rect.setStroke(Color.BLUE); rect.setStrokeDashOffset(50); rect.widthProperty().bind(rectX.subtract(rectinitX)); rect.heightProperty().bind(rectY.subtract(rectinitY)); pane.getChildren().add(rect); stage.show(); } EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent mouseEvent) { if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) { rect.setX(mouseEvent.getX()); rect.setY(mouseEvent.getY()); rectinitX.set(mouseEvent.getX()); rectinitY.set(mouseEvent.getY()); } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) { rectX.set(mouseEvent.getX()); rectY.set(mouseEvent.getY()); } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) { System.out.println("Zoom bounds : [" + rectinitX.get()+", "+rectinitY.get()+"] ["+ rectX.get()+", "+rectY.get()+"]"); System.out.println("TODO: Determine bound ranges according these zoom coordinates.\n"); // TODO: Determine bound ranges according this zoom coordinates. //LineChart<String, Number> lineChart = (LineChart<String, Number>) pane.getCenter(); LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter(); // Zoom in Y-axis by changing bound range. NumberAxis yAxis = (NumberAxis) lineChart.getYAxis(); yAxis.setLowerBound(0.532); yAxis.setUpperBound(0.538); // Zoom in X-axis by removing first and last data values. // Note: Maybe better if categoryaxis is replaced by numberaxis then setting the // LowerBound and UpperBound will be avaliable. /* XYChart.Series series1 = lineChart.getData().get(0); if (!series1.getData().isEmpty()) { series1.getData().remove(0); series1.getData().remove(series1.getData().size() - 1); } */ NumberAxis xAxis = (NumberAxis) lineChart.getXAxis(); System.out.println("(a) xAxis.getLowerBound() "+xAxis.getLowerBound()+" "+xAxis.getUpperBound()); double Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound()); double newXlower, newXupper; newXlower = (rectinitX.get()/Tgap)+xAxis.getLowerBound(); newXupper = (rectX.get()/Tgap)+xAxis.getLowerBound(); if (newXupper > xAxis.getUpperBound()) newXupper = xAxis.getUpperBound(); xAxis.setLowerBound( newXlower ); xAxis.setUpperBound( newXupper ); System.out.println("(b) xAxis.getLowerBound() "+xAxis.getLowerBound()+" "+xAxis.getUpperBound()); // Hide the rectangle rectX.set(0); rectY.set(0); } } }; public static void main(String[] args) { launch(args); } } ```