Search code examples
chartsjavafx-2splitpanel

JavaFX 2.x : how to move both panes?


My class below plots two charts in a splitpane.

By left mouse click and drag the upper line chart moves left/right (and up/down).

I would like to move both panes together left/right when I click and drag with left mouse on the upper graph: how to accomplish this?

Thanks

public class XyChartInSplitMove extends Application { 
SplitPane               splitPane1 = null; 
BorderPane              pane; 
BorderPane              pane2; 
XYChart.Series          series1 = new XYChart.Series(); 
XYChart.Series          series2 = new XYChart.Series(); 

SimpleDoubleProperty rectinitX = new SimpleDoubleProperty(); 
SimpleDoubleProperty rectinitY = new SimpleDoubleProperty();  

@Override 
public void start(Stage stage) { 

final NumberAxis xAxis = new NumberAxis(1, 12, 1); 
final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005); 

xAxis.setAnimated(false);
yAxis.setAnimated(false);

yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { 

    @Override 
    public String toString(Number object) { 
        return String.format("%7.5f", object); 
    } 
});   
final LineChart<Number, Number> lineChart1 = new LineChart<Number, Number>(xAxis, yAxis); 

lineChart1.setCreateSymbols(false); 
lineChart1.setAlternativeRowFillVisible(false); 
lineChart1.setAnimated(false);
lineChart1.setLegendVisible(false);

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.531035)); 

lineChart1.getData().addAll(series1); 

pane = new BorderPane(); 
pane.setCenter(lineChart1); 

splitPane1 = new SplitPane();                                
splitPane1.setOrientation(Orientation.VERTICAL);
splitPane1.getItems().addAll(pane);
splitPane1.setDividerPosition(0, 1);

Platform.runLater(new Runnable() {
     @Override
     public void run() {
         double percSplit;

        ObservableList<SplitPane.Divider> splitDiv =  splitPane1.getDividers();

        percSplit = 1/(double)(splitDiv.size()+1);
        for (int i = 0; i< splitDiv.size(); i++) {                        
            splitPane1.setDividerPosition(i, percSplit);
            percSplit += 1/(double)(splitDiv.size()+1);
        }
     }
 });
//BarChart
final CategoryAxis xAxis2 = new CategoryAxis();
final NumberAxis   yAxis2 = new NumberAxis();

yAxis2.setTickUnit(1);
yAxis2.setPrefWidth(35);
yAxis2.setMinorTickCount(10);

yAxis2.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis2){
    @Override
public String toString(Number object){
        String label;
        label = String.format("%7.2f", object.floatValue());
        return label;
}
});
final BarChart<String, Number>BarChart2 = new BarChart<String, Number>(xAxis2, yAxis2);

BarChart2.setAlternativeRowFillVisible(false);
BarChart2.setLegendVisible(false);
BarChart2.setAnimated(false);

XYChart.Series series2 = new XYChart.Series();

series2.getData().add(new XYChart.Data("Jan", 1));
series2.getData().add(new XYChart.Data("Feb", 3));
series2.getData().add(new XYChart.Data("Mar", 1.5));
series2.getData().add(new XYChart.Data("Apr", 3));
series2.getData().add(new XYChart.Data("May", 4.5));
series2.getData().add(new XYChart.Data("Jun", 5));
series2.getData().add(new XYChart.Data("Jul", 4));
series2.getData().add(new XYChart.Data("Aug", 8));
series2.getData().add(new XYChart.Data("Sep", 16.5));
series2.getData().add(new XYChart.Data("Oct", 13.9));
series2.getData().add(new XYChart.Data("Nov", 17));
series2.getData().add(new XYChart.Data("Dec", 20));

BarChart2.getData().addAll(series2);

Platform.runLater(new Runnable() {
     @Override
     public void run() {
         double percSplit;
         splitPane1.getItems().addAll(BarChart2);

        ObservableList<SplitPane.Divider> splitDiv =  splitPane1.getDividers();

        percSplit = 1/(double)(splitDiv.size()+1);
        for (int i = 0; i< splitDiv.size(); i++) {                        
            splitPane1.setDividerPosition(i, percSplit);
            percSplit += 1/(double)(splitDiv.size()+1);
            }
     }
 });
Scene scene = new Scene(splitPane1, 800, 600); 

stage.setScene(scene);         

pane.setOnMouseClicked(mouseHandler); 
pane.setOnMouseDragged(mouseHandler); 
pane.setOnMouseEntered(mouseHandler); 
pane.setOnMouseExited(mouseHandler); 
pane.setOnMouseMoved(mouseHandler);  
pane.setOnMouseReleased(mouseHandler); 

stage.show(); 
} 

EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>(){ 

@Override 
public void handle(MouseEvent mouseEvent) { 

    if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED ||    mouseEvent.getEventType() == MouseEvent.MOUSE_MOVED){ 
        LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter(); 

        NumberAxis yAxis = (NumberAxis) lineChart.getYAxis(); 
        NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();  
        double Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound()); 
        double newXlower=xAxis.getLowerBound(), newXupper=xAxis.getUpperBound(); 
        double newYlower=yAxis.getLowerBound(), newYupper=yAxis.getUpperBound(); 

        double xAxisShift = getSceneShift(xAxis);
        double yAxisShift = getSceneShift(yAxis);

        double yAxisStep=yAxis.getHeight()/(yAxis.getUpperBound()-yAxis.getLowerBound());
        double CurrentPrice=yAxis.getUpperBound()-((mouseEvent.getY()-yAxisShift)/yAxisStep);

        double Delta=0.3;

        if(mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED){
            if(rectinitX.get() < mouseEvent.getX()){    
            newXlower=xAxis.getLowerBound()-Delta;
            newXupper=xAxis.getUpperBound()-Delta;
        }
        else if(rectinitX.get() > mouseEvent.getX()){    
            newXlower=xAxis.getLowerBound()+Delta;
            newXupper=xAxis.getUpperBound()+Delta;
        }    
        xAxis.setLowerBound( newXlower ); 
        xAxis.setUpperBound( newXupper ); 

        //========== Y-Axis Moving ============================

        if(rectinitY.get() < mouseEvent.getY()){    
            newYlower=yAxis.getLowerBound()+Delta/1000;
            newYupper=yAxis.getUpperBound()+Delta/1000;
        }
        else if(rectinitY.get() > mouseEvent.getY()){    
            newYlower=yAxis.getLowerBound()-Delta/1000;
            newYupper=yAxis.getUpperBound()-Delta/1000;
        }
        yAxis.setLowerBound(newYlower);
        yAxis.setUpperBound(newYupper);
        }
        rectinitX.set(mouseEvent.getX()); 
        rectinitY.set(mouseEvent.getY()); 

        if(mouseEvent.getEventType() == MouseEvent.MOUSE_MOVED && mouseEvent.getY()>yAxisShift && mouseEvent.getY()<yAxisShift+yAxis.getHeight() && mouseEvent.getX()>xAxisShift && mouseEvent.getX()<xAxisShift+xAxis.getWidth()){

        double XX=((mouseEvent.getX() - xAxisShift) / Tgap) + xAxis.getLowerBound();
        double YY=CurrentPrice;

        int XLB=(int) xAxis.getLowerBound();
        int XUB=(int) xAxis.getUpperBound();
        }
     } 
} 
}; 
private static double getSceneShift(Node node) { 
double shift = 0; 
do {  
    shift += node.getLayoutX();  
    node = node.getParent(); 
} while (node != null); 
return shift; 
}
private static String getHIstLOstY(XYChart.Series S,int XLowerBound,int XUpperBound) { 
double ValLOst=1000000;
double ValHIst=-1000000;
for(int i=XLowerBound; i<XUpperBound; i++){  
    double P=GetPrice(S,i);
    if(ValHIst<P){
        ValHIst=P;
    }
    if(ValLOst>P){
        ValLOst=P;
    }
}
return Double.toString(ValLOst) + "," + Double.toString(ValHIst);
} 
private static double GetPrice(XYChart.Series S,int IX) { 
Object SVal=S.getData().get(IX);
String Temp=SVal.toString().replaceAll("Data", "");
Temp=Temp.replace("[", "");
Temp=Temp.replace("]", "");
String[] TempArray=Temp.split(",");
return Double.parseDouble(TempArray[1]);     
}   
public static void main(String[] args) { 
launch(args);  
} 
}

Solution

  • Option 1 (simple):

    Imagine you have the same mouse handlers in both charts, then you can drag both charts separately. In this circumstances you need to update mouse handlers in top chart to call same events in bottom chart (minus y coordinate difference)

    Option 2 (good):

    Bind bottom chart axis ranges to top chart ones (yes, it may involve some complex math) as you did it for chart's starting states. So on update of top chart bottom chart will get updated automatically.