2014-06-15 3 views
3

JavaFX의 정의 된 위치에 선을 추가하는 데 문제가 있습니다. 이 줄은 다음과 같이 줄을 꾸며야합니다. How to add a value marker to JavaFX chart?JavaFX 차트에 행 추가하기

제 레이아웃의 정의가 좀 더 복잡합니다. 보라 :

chart

중요한 부분은 상단의 하나입니다. y = 60 행에 선이 있어야합니다. 라디오 박스가있는 왼쪽 부분은 VBox입니다. (Scatter-) Chart가있는 부분은 StackPane입니다 (너비의 나머지 부분을 채우기 때문에). 이 StackPane 내부에는 차트와 그룹이 있습니다. 그룹의 유일한 자녀가 그 선입니다.

StackPane이 차트 위의 줄에 그룹을 중앙에 배치한다는 것이 문제라고 생각합니다. 하지만 3. 내가 조합을 많이 시도

선을 중심으로하지 않습니다하지만 난 그냥 수 없습니다 1. 차트 위의 차트를 2 세트 라인을 뻗어 레이아웃의 조합을 얻을 수 없다 그것을 내가 원하는 방식으로 얻으십시오. 아무도 아이디어가 있니?!

+0

Hm 분산 형 차트에 선을 추가하는 방법은 실제로 쌓인 선에 꺾은 선형 차트와 분산 형 차트를 추가하는 것입니다. 아마 최선의 방법이 아니겠습니까 ... – Perneel

+0

나 역시이 방법을 사용해 보았습니다. 하지만 제목, 전설, 축의 제목 등으로 인해 그 일을 처리 할 수 ​​없었습니다. – JoeHut

답변

4

적절하게 수평선의 이름을하십시오 -) 상수 값을 가진 데이터를 사용하는 것은 일부 컨텍스트에서 허용되거나 가능할 수있는 해킹입니다.

이러한 마커를 지원하는 사용자 정의 차트가 더 깨끗하게 나옵니다. F.i. 사용자 지정 좋아 scatterchart에 :

// instantiate chart 
NumberAxis xAxis = new NumberAxis(0, 10, 1); 
NumberAxis yAxis = new NumberAxis(-100, 500, 100);   
ScatterXChart<Number,Number> sc = new ScatterXChart<>(xAxis,yAxis); 
// .. fill with some data 
... 
// ui to add/change/remove a value marker 
Data<Number, Number> horizontalMarker = new Data<>(0, 110); 
Button add = new Button("Add Marker"); 
add.setOnAction(e -> sc.addHorizontalValueMarker(horizontalMarker)); 
Slider move = new Slider(yAxis.getLowerBound(), yAxis.getUpperBound(), 0); 
move.setShowTickLabels(true); 
move.valueProperty().bindBidirectional(horizontalMarker.YValueProperty()); 
Button remove = new Button("Remove Marker"); 
remove.setOnAction(e -> sc.removeHorizontalValueMarker(horizontalMarker)); 

부록이 :

나는 approach in the related question 권하고 싶지 않다 동안

public class ScatterXChart<X, Y> extends ScatterChart<X, Y> { 

    // data defining horizontal markers, xValues are ignored 
    private ObservableList<Data<X, Y>> horizontalMarkers; 

    public ScatterXChart(Axis<X> xAxis, Axis<Y> yAxis) { 
     super(xAxis, yAxis); 
     // a list that notifies on change of the yValue property 
     horizontalMarkers = FXCollections.observableArrayList(d -> new Observable[] {d.YValueProperty()}); 
     // listen to list changes and re-plot 
     horizontalMarkers.addListener((InvalidationListener)observable -> layoutPlotChildren()); 
    } 

    /** 
    * Add horizontal value marker. The marker's Y value is used to plot a 
    * horizontal line across the plot area, its X value is ignored. 
    * 
    * @param marker must not be null. 
    */ 
    public void addHorizontalValueMarker(Data<X, Y> marker) { 
     Objects.requireNonNull(marker, "the marker must not be null"); 
     if (horizontalMarkers.contains(marker)) return; 
     Line line = new Line(); 
     marker.setNode(line); 
     getPlotChildren().add(line); 
     horizontalMarkers.add(marker); 
    } 

    /** 
    * Remove horizontal value marker. 
    * 
    * @param horizontalMarker must not be null 
    */ 
    public void removeHorizontalValueMarker(Data<X, Y> marker) { 
     Objects.requireNonNull(marker, "the marker must not be null"); 
     if (marker.getNode() != null) { 
      getPlotChildren().remove(marker.getNode()); 
      marker.setNode(null); 
     } 
     horizontalMarkers.remove(marker); 
    } 

    /** 
    * Overridden to layout the value markers. 
    */ 
    @Override 
    protected void layoutPlotChildren() { 
     super.layoutPlotChildren(); 
     for (Data<X, Y> horizontalMarker : horizontalMarkers) { 
      double lower = ((ValueAxis) getXAxis()).getLowerBound(); 
      X lowerX = getXAxis().toRealValue(lower); 
      double upper = ((ValueAxis) getXAxis()).getUpperBound(); 
      X upperX = getXAxis().toRealValue(upper); 
      Line line = (Line) horizontalMarker.getNode(); 
      line.setStartX(getXAxis().getDisplayPosition(lowerX)); 
      line.setEndX(getXAxis().getDisplayPosition(upperX)); 
      line.setStartY(getYAxis().getDisplayPosition(horizontalMarker.getYValue())); 
      line.setEndY(line.getStartY()); 

     } 
    } 
} 

A는 (오라클의 튜토리얼의 온라인 예에 과학 삽입) 차트를 테스트 니펫을 (차트의 부모에 마커 선을 추가하고 위치/길이를 외부에서 관리) 은 크기 조정이 가능한 컨테이너에서입니다.결정적인 thingies는 그것이 작동되도록하기 :

  • 차트의 크기/위치 변경을 듣고 라인을 업데이트 적절하게
  • 코드의 거짓

에 마커의 관리 속성은 (updateShift가있는 부분 설정

Pane pane = new StackPane(chart); 
chart.widthProperty().addListener(o -> updateShift(chart)); 
chart.heightProperty().addListener(o -> updateShift(chart)); 
valueMarker.setManaged(false); 
pane.getChildren().add(valueMarker); 
+0

멋지고 깨끗한 객체 지향 솔루션. 그러나 큰 성능 문제를 발견했습니다. 마커가 업데이트 될 때마다 전체 차트가 다시 그려집니다. 따라서 큰 차트가 있고 마커 위치 (예 : 차트 위로 커서가 이동하는 경우)를 변경하려면 마커 업데이트가 매우 오래 걸릴 수 있습니다 (제 경우에는 거의 1 초). 이 특별한 문제에 대한보다 효율적인 해결책이 있습니까? StackPane과 어쩌면? –

+0

@StefanEndrullis 좋은 점 (성능에 신경 쓰지 않았다 :-) - StackPane이 성능을 향상 시켰습니까? 왜 마커를 자주 업데이트하는 것입니까? – kleopatra

+0

마커를 사용하여 차트 값과 관련된 비디오의 현재 위치를 나타냅니다. 비디오가 재생되면 커서 (마커)를 업데이트해야합니다. 그러나 StackPane을 사용하고 차트의 캐시 특성을 true로 설정하여 성능을 해결했습니다. http://stackoverflow.com/questions/30482139/efficiently-updating-lines-markers-on-top-of-a-javafx-chart –

0

왜 차트에 그 라인을 추가하지 않습니까? 100, 99, 95 및 50 백분위 수를 표시하는 차트가 있는데이 문제를 해결하는 방법은 각 백분위 수에 맞는 y 값으로 한 줄을 추가하는 것입니다.

이렇게하려면 y = 60 x = 70 (가장 왼쪽의 x 축 값)과 y = 60 및 x = 120 (오른쪽 상단의 x 축 값) 대부분의 x 축 값).

위의 장점은 수동으로 수평선을 정렬 할 필요가 없다는 것입니다. 단점은이 수평선이 범례의 일부가된다는 것입니다. 그러나 전설이 없으므로 확인해야합니다. 당신은 전설을 추가하기로 결정하는 경우

((즉, 아마이 수행해야했다 계층 구조에서 장소) L, M은 불행하게도, ValueMarkers이 XYCharts에서 지원되지 않습니다

+0

답변 해 주셔서 감사합니다. 내가 올바르게하면, 당신이하는 방식은 LineChart에서 작동합니다. 내 차트는 ScatterChart입니다. 예제가 ScatterChart에서도 작동하는 경우 코드를 제공 할 수 있습니까? – JoeHut

+0

차트에 선을 추가 할 수 있어야합니다. 에어 라인 차트에서 이러한 백분위 수선을 사용하지만, AFAIK에서는 계열 데이터를 차트 유형에 추가 할 수 있습니다. –

+0

Series Data의 포인트가 연결되기 때문에 AreaChart에서 가능하다고 생각합니다. 그러나 Series Data를 ScatterChart에 추가하면 두 데이터간에 연결이 없습니다. 그러나 어쩌면 나는 당신의 대답의 요점을 얻지 못한다. 당신은 당신의 차트의 코드 또는 스크린 샷을 제공 할 수 있습니까? – JoeHut