1 Reply Latest reply: Sep 2, 2012 4:56 AM by famedoro RSS

    Zoom on XYChart with draw freehand

    famedoro
      I've posted the same request on
      http://www.java-forums.org/javafx/59247-zoom-xychart-draw-freehand.html#post299473

      http://www.java-forums.org/javafx/62641-refining-zooming-javafx.html#post299473

      but I think this is the best place as it refers to javafx.

      Hi,
      I have the same problem that has posted "susieferrari"
      tried to find a solution, see the method ZoomFreeHand, but must be refined.
      I've attached a program that lets you overlay a graph with a plot.

      1) The plot is plotted using the right mouse button;
      2) you can zoom in by selecting a region using the left button;

      The problem is that I can not do a zoom of the plot that is consistent
      with the zoom of the graph.

      Can someone help me ?
      package testjavafxzoom;
      
      import javafx.application.Application;
      import javafx.beans.property.SimpleDoubleProperty;
      import javafx.collections.ObservableList;
      import javafx.event.EventHandler;
      import javafx.geometry.Bounds;
      import javafx.scene.Node;
      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.MouseButton;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.*;
      
      
      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) {
      
          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<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);
          
          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);
      
          //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();
      }
      // summ layout shift against parent until we ascend to scene
      
      
      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()))
                          {
                              //Condizioni Iniziali
                              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;
                              double xNewLowerBound, xNewUpperBound;
                              double yNewLowerBound, yNewUpperBound;
                              //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();
                              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);
      
      
                              //System.out.println("(a) rectinitY.get() "+rectinitY.get()+" rectY.get() "+rectY.get());
                              //System.out.println("(a) Tgap "+Tgap+" axisShift "+axisShift+" yAxis.getLowerBound() " + yAxis.getLowerBound()+ " " + yAxis.getUpperBound());
      
                              if (newUpperBound > yAxis.getUpperBound())
                                  newUpperBound = yAxis.getUpperBound();
      
                              //yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound())/(newUpperBound - newLowerBound);                        
                              yScaleFactor = (initYUpperBound - initYLowerBound)/(newUpperBound - newLowerBound);
                              yNewLowerBound = newLowerBound;
                              yNewUpperBound = newUpperBound;
                              //yAxis.setLowerBound(newLowerBound);
                              //yAxis.setUpperBound(newUpperBound);
      
                              //System.out.println("(b) yAxis.getLowerBound() " + yAxis.getLowerBound()+ " " + yAxis.getUpperBound());
      
                              // 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());            
      
                              Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound());            
                  //            newXlower = (rectinitX.get()/Tgap) + xAxis.getLowerBound();
                  //            newXupper = (rectX.get()/Tgap)+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);
                              xScaleFactor = (initXUpperBound - initXLowerBound)/(newUpperBound - newLowerBound);                        
                              xNewLowerBound = newLowerBound;
                              xNewUpperBound = newUpperBound;                                                
                              
                              yAxis.setLowerBound(yNewLowerBound);
                              yAxis.setUpperBound(yNewUpperBound);
                              
                              xAxis.setLowerBound( xNewLowerBound );
                              xAxis.setUpperBound( xNewUpperBound );
      
            /*                  
                               public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            Bounds y_axisBounds = yAxis.getBoundsInLocal();
            double xOffset = y_axisBounds.getMaxX();
            
            Bounds x_axisBounds = xAxis.getBoundsInLocal();
            double yOffset = x_axisBounds.getMaxY();
            
            translate.setX(xOffset);
            translate.setY(yOffset);
            
            
            Bounds chartBounds = lineChart.getBoundsInLocal();
            scale.setX((chartBounds.getWidth() - xOffset) / initialWidth);
            scale.setY((chartBounds.getHeight() - xAxis.getBoundsInLocal().getHeight()) / initialheight);
          }
        };
              */
                              ZoomFreeHand(path, xScaleFactor, yScaleFactor, xNewLowerBound, yNewUpperBound);//xNewLowerBound-xAxis.getLowerBound(), yAxis.getLowerBound()-yNewLowerBound);//xaxisShift, yaxisShift);
      
      
                              //System.out.println("(b) xAxis.getLowerBound() "+xAxis.getLowerBound()+" "+xAxis.getUpperBound());
                              
                              
                          }
                          // Hide the rectangle
                          rectX.set(0);
                          rectY.set(0);
                      }
              }// end if (mouseEvent.getButton() == MouseButton.PRIMARY)
              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()));
                  }
              } //end if (mouseEvent.getButton() == MouseButton.SECONDARY)
          }
         };
      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 void ZoomFreeHand(Path path, double xScaleFactor, double yScaleFactor, double xaxisShift, double yaxisShift) {
         
          //    
          path.setScaleY(yScaleFactor);
          path.setScaleX(xScaleFactor);
          path.setTranslateX(xaxisShift);
          path.setTranslateY(yaxisShift);        
          System.out.println("xScaleFactor "+xScaleFactor);
          
          //bounds.
      }
      
          public static void main(String[] args) {
              launch(args);
          }
          
          
      }
      Edited by: famedoro on 1-set-2012 2.26

      Edited by: famedoro on 1-set-2012 2.28
        • 1. Re: Zoom on XYChart with draw freehand
          famedoro
          I think it 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
             }
           }