2015-01-16 3 views
4

작업Gantt 차트

내가 처음부터 자바 FX와 간트 차트를 만들 싶습니다.

이의 말을하자 나는이 기계 기계 A와 컴퓨터 B를 가지고 있고 온라인 (녹색) 및 오프라인 (적색)이 개 상태를 가지고있다. 주어진 시간 간격으로 상태를 수평 막대로 표시하고 싶습니다. X 축은 날짜 축이고, Y 축은 기계 축입니다.

질문

어디서부터 시작 할까? 어떤 수업을 사용해야합니까? 누군가가 최소한의 예를 가지고 그것을 공유 할 수 있다면 좋을 것입니다.

대단히 감사합니다.

+0

자바 FX를위한 상업적 gannt 차트 LIB있다. 최소한의 Gantt 차트에 대해서도 코드를 제공하는 것은 StackOverflow 응답에 적합한 범위를 벗어납니다. – jewelsea

+0

내가 필요한 것은 시간이 지남에 따라 색상이 바뀌는 2 개의 가로 막대입니다. 나는 너무 복잡해야한다고 생각하지 않는다. 예를 들어 색깔을 변경하는 수평선이있는 XY 차트가 있으면 충분합니다. 아니면 modofied 스택 막대 차트가 해결책이 될 수 있습니다. 캔슬 바 사용자 차트를 앙상블에서 보았습니다. 나는 그것이 지금 최선의 선택이라고 생각합니다. – Roland

+0

시간이 지남에 따라 색상이 변하는 두 개의 수평 막대는 Gantt 차트와 완전히 다릅니다. 솔루션을 코드화하고 솔루션을 구현하는 동안 추가 질문을하는 경우 특정 문제 (해결하려는 문제를 복제하는 실행 코드 포함)를 게시하십시오. – jewelsea

답변

11

BubbleChart 소스가 좋은 예라고 밝혀졌습니다.

기본적으로 수정 된 버전의 XYChart와 해당 데이터를 사용할 수 있습니다. 당신이해야 할 일은 값이 유효한 기간과 착색을위한 어떤 스타일과 같은 extradata를 추가하는 것입니다.

남은 것은 숫자 축 대신 날짜 축과 날짜 값을 사용하는 것입니다.

enter image description here 또 다른 예 :

enter image description here

소스 :

GanttChart.java 여기

나는 경우 사람이 주위에 장난감 그것 원에 마련 사용해보세요 :

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

import javafx.beans.NamedArg; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Node; 
import javafx.scene.chart.Axis; 
import javafx.scene.chart.CategoryAxis; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.ValueAxis; 
import javafx.scene.chart.XYChart; 
import javafx.scene.layout.StackPane; 
import javafx.scene.shape.Rectangle; 

public class GanttChart<X,Y> extends XYChart<X,Y> { 

    public static class ExtraData { 

     public long length; 
     public String styleClass; 


     public ExtraData(long lengthMs, String styleClass) { 
      super(); 
      this.length = lengthMs; 
      this.styleClass = styleClass; 
     } 
     public long getLength() { 
      return length; 
     } 
     public void setLength(long length) { 
      this.length = length; 
     } 
     public String getStyleClass() { 
      return styleClass; 
     } 
     public void setStyleClass(String styleClass) { 
      this.styleClass = styleClass; 
     } 


    } 

    private double blockHeight = 10; 

    public GanttChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis) { 
     this(xAxis, yAxis, FXCollections.<Series<X, Y>>observableArrayList()); 
    } 

    public GanttChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis, @NamedArg("data") ObservableList<Series<X,Y>> data) { 
     super(xAxis, yAxis); 
     if (!(xAxis instanceof ValueAxis && yAxis instanceof CategoryAxis)) { 
      throw new IllegalArgumentException("Axis type incorrect, X and Y should both be NumberAxis"); 
     } 
     setData(data); 
    } 

    private static String getStyleClass(Object obj) { 
     return ((ExtraData) obj).getStyleClass(); 
    } 

    private static double getLength(Object obj) { 
     return ((ExtraData) obj).getLength(); 
    } 

    @Override protected void layoutPlotChildren() { 

     for (int seriesIndex=0; seriesIndex < getData().size(); seriesIndex++) { 

      Series<X,Y> series = getData().get(seriesIndex); 

      Iterator<Data<X,Y>> iter = getDisplayedDataIterator(series); 
      while(iter.hasNext()) { 
       Data<X,Y> item = iter.next(); 
       double x = getXAxis().getDisplayPosition(item.getXValue()); 
       double y = getYAxis().getDisplayPosition(item.getYValue()); 
       if (Double.isNaN(x) || Double.isNaN(y)) { 
        continue; 
       } 
       Node block = item.getNode(); 
       Rectangle ellipse; 
       if (block != null) { 
        if (block instanceof StackPane) { 
         StackPane region = (StackPane)item.getNode(); 
         if (region.getShape() == null) { 
          ellipse = new Rectangle(getLength(item.getExtraValue()), getBlockHeight()); 
         } else if (region.getShape() instanceof Rectangle) { 
          ellipse = (Rectangle)region.getShape(); 
         } else { 
          return; 
         } 
         ellipse.setWidth(getLength(item.getExtraValue()) * ((getXAxis() instanceof NumberAxis) ? Math.abs(((NumberAxis)getXAxis()).getScale()) : 1)); 
         ellipse.setHeight(getBlockHeight() * ((getYAxis() instanceof NumberAxis) ? Math.abs(((NumberAxis)getYAxis()).getScale()) : 1)); 
         y -= getBlockHeight()/2.0; 

         // Note: workaround for RT-7689 - saw this in ProgressControlSkin 
         // The region doesn't update itself when the shape is mutated in place, so we 
         // null out and then restore the shape in order to force invalidation. 
         region.setShape(null); 
         region.setShape(ellipse); 
         region.setScaleShape(false); 
         region.setCenterShape(false); 
         region.setCacheShape(false); 

         block.setLayoutX(x); 
         block.setLayoutY(y); 
        } 
       } 
      } 
     } 
    } 

    public double getBlockHeight() { 
     return blockHeight; 
    } 

    public void setBlockHeight(double blockHeight) { 
     this.blockHeight = blockHeight; 
    } 

    @Override protected void dataItemAdded(Series<X,Y> series, int itemIndex, Data<X,Y> item) { 
     Node block = createContainer(series, getData().indexOf(series), item, itemIndex); 
     getPlotChildren().add(block); 
    } 

    @Override protected void dataItemRemoved(final Data<X,Y> item, final Series<X,Y> series) { 
     final Node block = item.getNode(); 
      getPlotChildren().remove(block); 
      removeDataItemFromDisplay(series, item); 
    } 

    @Override protected void dataItemChanged(Data<X, Y> item) { 
    } 

    @Override protected void seriesAdded(Series<X,Y> series, int seriesIndex) { 
     for (int j=0; j<series.getData().size(); j++) { 
      Data<X,Y> item = series.getData().get(j); 
      Node container = createContainer(series, seriesIndex, item, j); 
      getPlotChildren().add(container); 
     } 
    } 

    @Override protected void seriesRemoved(final Series<X,Y> series) { 
     for (XYChart.Data<X,Y> d : series.getData()) { 
      final Node container = d.getNode(); 
      getPlotChildren().remove(container); 
     } 
     removeSeriesFromDisplay(series); 

    } 


    private Node createContainer(Series<X, Y> series, int seriesIndex, final Data<X,Y> item, int itemIndex) { 

     Node container = item.getNode(); 

     if (container == null) { 
      container = new StackPane(); 
      item.setNode(container); 
     } 

     container.getStyleClass().add(getStyleClass(item.getExtraValue())); 

     return container; 
    } 

    @Override protected void updateAxisRange() { 
     final Axis<X> xa = getXAxis(); 
     final Axis<Y> ya = getYAxis(); 
     List<X> xData = null; 
     List<Y> yData = null; 
     if(xa.isAutoRanging()) xData = new ArrayList<X>(); 
     if(ya.isAutoRanging()) yData = new ArrayList<Y>(); 
     if(xData != null || yData != null) { 
      for(Series<X,Y> series : getData()) { 
       for(Data<X,Y> data: series.getData()) { 
        if(xData != null) { 
         xData.add(data.getXValue()); 
         xData.add(xa.toRealValue(xa.toNumericValue(data.getXValue()) + getLength(data.getExtraValue()))); 
        } 
        if(yData != null){ 
         yData.add(data.getYValue()); 
        } 
       } 
      } 
      if(xData != null) xa.invalidateRange(xData); 
      if(yData != null) ya.invalidateRange(yData); 
     } 
    } 

} 
,363,210

GanttChartSample.java - [FlexGanttFX (http://flexganttfx.com)

import java.util.Arrays; 

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.scene.Scene; 
import javafx.scene.chart.CategoryAxis; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 
import chart.gantt_04.GanttChart.ExtraData; 

// TODO: use date for x-axis 
public class GanttChartSample extends Application { 

    @Override public void start(Stage stage) { 

     stage.setTitle("Gantt Chart Sample"); 

     String[] machines = new String[] { "Machine 1", "Machine 2", "Machine 3" }; 

     final NumberAxis xAxis = new NumberAxis(); 
     final CategoryAxis yAxis = new CategoryAxis(); 

     final GanttChart<Number,String> chart = new GanttChart<Number,String>(xAxis,yAxis); 
     xAxis.setLabel(""); 
     xAxis.setTickLabelFill(Color.CHOCOLATE); 
     xAxis.setMinorTickCount(4); 

     yAxis.setLabel(""); 
     yAxis.setTickLabelFill(Color.CHOCOLATE); 
     yAxis.setTickLabelGap(10); 
     yAxis.setCategories(FXCollections.<String>observableArrayList(Arrays.asList(machines))); 

     chart.setTitle("Machine Monitoring"); 
     chart.setLegendVisible(false); 
     chart.setBlockHeight(50); 
     String machine; 

     machine = machines[0]; 
     XYChart.Series series1 = new XYChart.Series(); 
     series1.getData().add(new XYChart.Data(0, machine, new ExtraData(1, "status-red"))); 
     series1.getData().add(new XYChart.Data(1, machine, new ExtraData(1, "status-green"))); 
     series1.getData().add(new XYChart.Data(2, machine, new ExtraData(1, "status-red"))); 
     series1.getData().add(new XYChart.Data(3, machine, new ExtraData(1, "status-green"))); 

     machine = machines[1]; 
     XYChart.Series series2 = new XYChart.Series(); 
     series2.getData().add(new XYChart.Data(0, machine, new ExtraData(1, "status-green"))); 
     series2.getData().add(new XYChart.Data(1, machine, new ExtraData(1, "status-green"))); 
     series2.getData().add(new XYChart.Data(2, machine, new ExtraData(2, "status-red"))); 

     machine = machines[2]; 
     XYChart.Series series3 = new XYChart.Series(); 
     series3.getData().add(new XYChart.Data(0, machine, new ExtraData(1, "status-blue"))); 
     series3.getData().add(new XYChart.Data(1, machine, new ExtraData(2, "status-red"))); 
     series3.getData().add(new XYChart.Data(3, machine, new ExtraData(1, "status-green"))); 

     chart.getData().addAll(series1, series2, series3);   

     chart.getStylesheets().add(getClass().getResource("ganttchart.css").toExternalForm()); 

     Scene scene = new Scene(chart,620,350); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

ganttchart.css

.status-red { 
    -fx-background-color:rgba(128,0,0,0.7); 
} 
.status-green { 
    -fx-background-color:rgba(0,128,0,0.7); 
} 
.status-blue { 
    -fx-background-color:rgba(0,0,128,0.7); 
} 
+0

위대한 작품! 한편 TODO에서 언급 한 것처럼 "Date for x-Achsis"솔루션을 제안 했습니까? –

+0

예, 기존 오픈 소스 날짜 축 구현 중 하나만 사용하십시오. – Roland

+0

감사합니다. 그러나 데이터의 올바른 너비는 어떻게 계산합니까? 당신이 "새로운 Extradata (100, ...) "와 100은 100 초를 의미합니까? –