2013-03-25 60 views
7

我正在嘗試使用JavaFX構建一個系列圖表,其中數據是動態插入的。如何向JavaFX圖表添加值標記?

每次插入一個新值時,我想檢查這是否是迄今爲止的最高值,如果是這樣,我想繪製一條水平線以顯示這是最大值。

在JFree圖表中,我會使用ValueMarker,但我試圖用JavaFX做同樣的事情。

我試過使用Line對象,但它絕對不一樣,因爲我無法提供Chart值,它需要在窗口中的相對像素位置。

這裏是我想達到圖表的截圖:

http://postimg.org/image/s5fkupsuz/

有什麼建議? 謝謝。

回答

14

要將圖表值轉換爲像素,您可以使用方法NumberAxis#getDisplayPosition(),它返回圖表節點的實際座標。

雖然這些座標是相對於圖表區域,您可以通過下面的代碼找出:

Node chartArea = chart.lookup(".chart-plot-background"); 
Bounds chartAreaBounds = chartArea.localToScene(chartArea.getBoundsInLocal()); 

注意localToScene()方法,它允許你任意座標轉換爲場景的。因此,您可以使用它們來更新值標記座標。確保您在場景顯示後撥打localToScene。低於該

看樣程序產生下圖:

enter image description here

public class LineChartValueMarker extends Application { 

    private Line valueMarker = new Line(); 
    private XYChart.Series<Number, Number> series = new XYChart.Series<>(); 
    private NumberAxis yAxis; 
    private double yShift; 

    private void updateMarker() { 
     // find maximal y value 
     double max = 0; 
     for (Data<Number, Number> value : series.getData()) { 
      double y = value.getYValue().doubleValue(); 
      if (y > max) { 
       max = y; 
      } 
     } 
     // find pixel position of that value 
     double displayPosition = yAxis.getDisplayPosition(max); 
     // update marker 
     valueMarker.setStartY(yShift + displayPosition); 
     valueMarker.setEndY(yShift + displayPosition); 
    } 

    @Override 
    public void start(Stage stage) { 
     LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(0, 100, 10), yAxis = new NumberAxis(0, 100, 10)); 

     series.getData().add(new XYChart.Data(0, 0)); 
     series.getData().add(new XYChart.Data(10, 20)); 

     chart.getData().addAll(series); 
     Pane pane = new Pane(); 
     pane.getChildren().addAll(chart, valueMarker); 
     Scene scene = new Scene(pane); 

     // add new value on mouseclick for testing 
     chart.setOnMouseClicked(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent t) { 
       series.getData().add(new XYChart.Data(series.getData().size() * 10, 30 + 50 * new Random().nextDouble())); 
       updateMarker(); 
      } 
     }); 

     stage.setScene(scene); 
     stage.show(); 

     // find chart area Node 
     Node chartArea = chart.lookup(".chart-plot-background"); 
     Bounds chartAreaBounds = chartArea.localToScene(chartArea.getBoundsInLocal()); 
     // remember scene position of chart area 
     yShift = chartAreaBounds.getMinY(); 
     // set x parameters of the valueMarker to chart area bounds 
     valueMarker.setStartX(chartAreaBounds.getMinX()); 
     valueMarker.setEndX(chartAreaBounds.getMaxX()); 
     updateMarker(); 
    } 

    public static void main(String[] args) { 
     launch(); 
    } 
} 
+0

+1不錯dirtyness :-) – kleopatra 2014-06-25 08:45:20

+0

順便說一句,改變你的代碼有點應付可調整大小的父母的http://計算器。 com/a/24403761/203657 – kleopatra 2014-06-25 09:28:24

+0

@kleopatra,謝謝!但爲什麼髒? :) – 2014-06-25 09:31:48