2016-11-14 40 views
0

我一直在試圖用XYCharts做一些工作,特別是將事物放置在它們周圍。我一直需要使用座標軸相對於整個圖表定義的座標空間的座標。但是,我已經意識到.getBoundsInParent()方法沒有返回應用於座標軸時的預期結果。這似乎是因爲軸父母不是圖表,我不知道父母是什麼。例如下面的布爾爲false,這對我來說似乎是可怕的設計(假設圖表線型圖的一個實例):爲什麼XYChart中軸的父節點不是圖表本身? (JavaFX)

chart.getXAxis()的getParent()==圖

這到底是怎麼回事?謝謝。

+2

你爲什麼期望直接父母是圖表?如何管理圖表的內部佈局是您不應該關心的實現細節。這聽起來像是你正在使用錯誤的方法解決你正在嘗試解決的任何問題。 –

+0

我所需要的只是圖表區域在屏幕上出現的座標,即您知道如何獲取該座標軸的灰色空間? – Someguy

+0

在哪個座標系中? –

回答

1

沒有直接的API來獲取圖表區域的邊界。一種方法是使用查找,但這不是非常強大。

如果你想在圖表繪圖區,推薦的方法是覆蓋圖表的layoutPlotChildren方法,如this question附加內容

在圖表區域之外添加內容的最好方法是繼承Region並覆蓋layoutChildren方法來佈置圖表和所需的額外內容。您可以使用ValueAxis.getDisplayPosition(value)來獲取相對於座標軸的座標,然後使用一對變換來獲取相對於該區域的座標,從而確定特定「圖表值」的座標。

下面是一個簡單的例子:

import java.util.List; 
import java.util.Random; 
import java.util.stream.Collectors; 
import java.util.stream.Stream; 

import javafx.application.Application; 
import javafx.geometry.Point2D; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart.Data; 
import javafx.scene.chart.XYChart.Series; 
import javafx.scene.control.Tooltip; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.Region; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

public class LineChartWithRightPanel extends Application { 

    private final Color[] RECT_COLORS = 
      new Color[] {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE}; 
    private final double RECT_WIDTH = 20 ; 

    @Override 
    public void start(Stage primaryStage) { 

     NumberAxis xAxis = new NumberAxis(); 
     NumberAxis yAxis = new NumberAxis(0, 1, 0.2); 
     LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis); 

     Region chartWithPanel = new Region() { 

      private List<Rectangle> rectangles = 
        Stream.of(RECT_COLORS) 
        .map(c -> new Rectangle(RECT_WIDTH, 0, c)) 
        .collect(Collectors.toList()); 

      { 
       getChildren().add(chart); 
       getChildren().addAll(rectangles); 
      } 

      @Override 
      protected void layoutChildren() { 
       double w = getWidth(); 
       double h = getHeight(); 
       chart.resizeRelocate(0, 0, w-RECT_WIDTH, h); 
       chart.layout(); 

       double chartMinY = yAxis.getLowerBound(); 
       double chartMaxY = yAxis.getUpperBound(); 
       double chartYRange = chartMaxY - chartMinY ; 

       for (int i = 0 ; i < rectangles.size(); i++) { 

        // easier ways to do this in this example, 
        // but this technique shows how to map "chart coords" 
        // to coords in this pane: 

        double rectMinYInChart = chartMinY + i * chartYRange/rectangles.size(); 
        double rectMaxYInChart = chartMinY + (i+1) * chartYRange/rectangles.size(); 
        double rectMinYInAxis = yAxis.getDisplayPosition(rectMinYInChart); 
        double rectMaxYInAxis = yAxis.getDisplayPosition(rectMaxYInChart); 
        double rectMinY = sceneToLocal(yAxis.localToScene(new Point2D(0, rectMinYInAxis))).getY(); 
        double rectMaxY = sceneToLocal(yAxis.localToScene(new Point2D(0, rectMaxYInAxis))).getY(); 

        rectangles.get(i).setHeight(Math.abs(rectMaxY - rectMinY)); 
        rectangles.get(i).setX(w - RECT_WIDTH); 
        rectangles.get(i).setY(Math.min(rectMinY, rectMaxY)); 

        Tooltip.install(rectangles.get(i), 
          new Tooltip(String.format("%.2f - %.2f", rectMinYInChart, rectMaxYInChart))); 
       } 
      } 
     }; 

     Series<Number, Number> series = new Series<>(); 
     series.setName("Data"); 
     Random rng = new Random(); 
     for (int i = 0; i < 20; i++) { 
      series.getData().add(new Data<>(i, rng.nextDouble())); 
     } 
     chart.getData().add(series); 

     BorderPane root = new BorderPane(chartWithPanel); 
     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 


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

Screenshot of chart with colored bands on right

注意,您可以使用同樣的想法得到整個繪圖區的範圍:

double minXInAxis = xAxis.getDisplayPosition(xAxis.getLowerBound()); 
double maxXInAxis = xAxis.getDisplayPosition(xAxis.getUpperBound()); 
double minYInAxis = yAxis.getDisplayPosition(yAxis.getLowerBound()); 
double maxYInAxis = yAxis.getDisplayPosition(yAxis.getUpperBound()); 

double minX = sceneToLocal(xAxis.localToScene(new Point2D(minXInAxis,0))).getX(); 
double maxX = sceneToLocal(xAxis.localToScene(new Point2D(maxXInAxis,0))).getX(); 
double minY = sceneToLocal(yAxis.localToScene(new Point2D(0,minYInAxis))).getY(); 
double maxY = sceneToLocal(yAxis.localToScene(new Point2D(0,maxYInAxis))).getY(); 

然後minXmaxXminY,maxY定義了繪圖區域的邊界。

+0

我只想說再次感謝你,這絕對是做我想做的事的方式。我一直在努力實現它,並且我已經接近完成了。我的實現比較複雜一些,因爲圖表嵌入了大量的軟件中,並不是以這種簡單的方式生成的,而是這個想法是一樣的。 – Someguy