Javafx 2 Chart and Manual Control

This code displays XYChart and uses a combination of a right-click and a drag that performs a manual draw, and when you left-click and drag, zoom in on the selected area.

My problem is to zoom in on drawing, it always translates. For example, try to hold somewhere around the corner.

How can i solve this?

public class Zoom 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(); double initXLowerBound = 0, initXUpperBound = 0, initYLowerBound = 0, initYUpperBound = 0; @Override public void start(Stage stage) { stage.setTitle("Lines plot"); 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<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis); lineChart.setCreateSymbols(false); lineChart.setAlternativeRowFillVisible(false); lineChart.setAnimated(true); XYChart.Series series1 = new XYChart.Series(); 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(pane, 800, 600); lineChart.getData().addAll(series1); initXLowerBound = ((NumberAxis) lineChart.getXAxis()).getLowerBound(); initXUpperBound = ((NumberAxis) lineChart.getXAxis()).getUpperBound(); initYLowerBound = ((NumberAxis) lineChart.getYAxis()).getLowerBound(); initYUpperBound = ((NumberAxis) lineChart.getYAxis()).getUpperBound(); 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); 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.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()); } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) { rectX.set(mouseEvent.getX()); rectY.set(mouseEvent.getY()); } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) { if ((rectinitX.get() >= rectX.get())&&(rectinitY.get() >= rectY.get())) { LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter(); ((NumberAxis) lineChart.getXAxis()).setLowerBound(initXLowerBound); ((NumberAxis) lineChart.getXAxis()).setUpperBound(initXUpperBound); ((NumberAxis) lineChart.getYAxis()).setLowerBound(initYLowerBound); ((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound); ZoomFreeHand(path, 1.0, 1.0, 0, 0); } else { //Zoom In double Tgap = 0; double newLowerBound, newUpperBound, axisShift; double xScaleFactor, yScaleFactor; double xaxisShift, yaxisShift; LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter(); // Zoom in Y-axis by changing bound range. NumberAxis yAxis = (NumberAxis) lineChart.getYAxis(); Tgap = yAxis.getHeight()/(yAxis.getUpperBound() - yAxis.getLowerBound()); axisShift = getSceneShiftY(yAxis); yaxisShift = axisShift; 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); yAxis.setLowerBound(newLowerBound); yAxis.setUpperBound(newUpperBound); NumberAxis xAxis = (NumberAxis) lineChart.getXAxis(); Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound()); axisShift = getSceneShiftX(xAxis); xaxisShift = axisShift; newLowerBound = ((rectinitX.get() - axisShift) / Tgap) + xAxis.getLowerBound(); newUpperBound = ((rectX.get() - axisShift) / Tgap) + xAxis.getLowerBound(); if (newUpperBound > xAxis.getUpperBound()) newUpperBound = xAxis.getUpperBound(); xScaleFactor = (xAxis.getUpperBound() - xAxis.getLowerBound())/(newUpperBound - newLowerBound); xAxis.setLowerBound( newLowerBound ); xAxis.setUpperBound( newUpperBound ); ZoomFreeHand(path, xScaleFactor, yScaleFactor, xaxisShift, yaxisShift); } // Hide the rectangle rectX.set(0); rectY.set(0); } } else if (mouseEvent.getButton() == MouseButton.SECONDARY) //free hand graphics { if(mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED){ path.getElements().clear(); path.getElements().add(new MoveTo(mouseEvent.getX(), mouseEvent.getY())); } else if(mouseEvent.getEventType()==MouseEvent.MOUSE_DRAGGED){ path.getElements().add(new LineTo(mouseEvent.getX(), mouseEvent.getY())); } } } }; private static double getSceneShiftX(Node node) { double shift = 0; do { shift += node.getLayoutX(); node = node.getParent(); } while (node != null); return shift; } private static double getSceneShiftY(Node node) { double shift = 0; do { shift += node.getLayoutY(); node = node.getParent(); } while (node != null); return shift; } private static void ZoomFreeHand(Path path, double xScaleFactor, double yScaleFactor, double xaxisShift, double yaxisShift) { double layX, layY; layX = path.getLayoutX(); layY = path.getLayoutY(); path.setScaleX(xScaleFactor); path.setScaleY(yScaleFactor); path.setTranslateX(xaxisShift); path.setTranslateY(yaxisShift); } public static void main(String[] args) { launch(args); } } 

I think it's worth using something like this:

  ObservableList<PathElement> mypathElements = path.getElements(); for (int i = 0; i < mypathElements.size(); i++) { final PathElement element = mypathElements.get(i); if (element instanceof MoveTo) { final MoveTo move = (MoveTo)element; //change move coordinates } else if (element instanceof LineTo) { final LineTo line = (LineTo)element; //change line coordinates } } 
+7
source share
2 answers

Same problem as Resizing a Javafx 2 chart using free hand and same answer:

It seems your coordinates are based on incorrect anchors. You need to find a node that contains the graph itself and work only with these node coordinates, and not with the axis or scene.

I would even advise adding all mouse events to this node instead of a scene to avoid over-translation.

Another tip would be to use ScenicView to examine your application and see which nodes have which coordinates and check your math.

+3
source

I would recommend replacing those:

 private static double getSceneShiftX(Node node) { double shift = 0; do { shift += node.getLayoutX(); node = node.getParent(); } while (node != null); return shift; } private static double getSceneShiftY(Node node) { double shift = 0; do { shift += node.getLayoutY(); node = node.getParent(); } while (node != null); return shift; } 

with Node.localToScene , Node.sceneToLocal conversion methods that took points or Bounds as arguments.

+1
source

All Articles