This discussion is archived
1 Reply Latest reply: Sep 2, 2012 2:56 AM by famedoro RSS

Zoom on XYChart with draw freehand

famedoro Newbie
Currently Being Moderated
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 Newbie
    Currently Being Moderated
    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
       }
     }

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points