2012-01-11 99 views
0

我负责维护一个可以使用JFreeChart绘制图形的应用程序。 该应用程序使用Eclipse-RCP和SWT编写,并使用ChartComposite来显示图表。JfreeChart限制显示的图例项数

的ChartComposite是为了定义取决于选择上下文菜单被部分覆盖:

@Override 
    public void createPartControl(Composite parent) { 
    super.createPartControl(parent); 

    chart = createChart(timeSeriesDataset); 

    chartComposite = new MyChartComposite(this, parent, SWT.NONE, chart, true); 
    chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); 

    selectionProvider = new GenericObjectSelectionProvider(); 
    getSite().setSelectionProvider(selectionProvider); 

    // add information to the status line: 
    selectionProvider.addSelectionChangedListener(statusLineListener); 

    addDropSupport();// add D'n D support for dropping TimeSeries 

} 


protected JFreeChart createChart(TimeSeriesCollection ptimeSeriesDataset) { 

     JFreeChart vChart = ChartFactory.createTimeSeriesChart(null, "time", "values", ptimeSeriesDataset, true, 
       false, false); 
     vChart.setBackgroundPaint(Color.white); 

     XYPlot plot = vChart.getXYPlot(); 
     plot.setBackgroundPaint(Color.lightGray); 
     plot.setDomainGridlinePaint(Color.white); 
     plot.setRangeGridlinePaint(Color.white); 
     // plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); 
     plot.setDomainCrosshairVisible(true); 
     plot.setRangeCrosshairVisible(true); 

     plot.setRenderer(new /*OptimisedXYLineAndShapeRenderer()*/ StandardXYItemRendererFast()); 
     XYItemRenderer renderer = plot.getRenderer(); 
     renderer.setBaseToolTipGenerator(new MyXYSeriesToolTipGenerator()); 
     renderer.setBaseItemLabelGenerator(new MyXYSeriesItemLabelGenerator()); 
     renderer.setLegendItemLabelGenerator(new MyXYSeriesLegendItemLabelGenerator()); 
     if (renderer instanceof XYLineAndShapeRenderer) { 
      XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) renderer; 
      r.setBaseShapesVisible(false); 
      r.setBaseShapesFilled(true); 
     } 

     SimpleDateFormat dateFormat = getDateFormatAbscissa(); 
     if (dateFormat != null){ 
      DateAxis axis = (DateAxis) plot.getDomainAxis(); 
      axis.setDateFormatOverride(dateFormat); 
     } 

     return vChart; 
    } 

我的问题是,当太多的变量添加到图表(一TimeSeriesChart)的标题太花

ChartComposite with 2 series

ChartComposite many series

:空间和图形从视图中消失

我试图创建一个ScrollComposite在ChartComposite中滚动,结果稍好一些;但它只能够在标题中添加更多项目前的图形再次消失:

ScrolledComposite scrollableChart = new ScrolledComposite(parent, SWT.BORDER|SWT.V_SCROLL); 

chartComposite = new MyChartComposite(this, scrollableChart, SWT.NONE, chart, true); 
//chartComposite = new MyChartComposite(this, parent, SWT.NONE, chart, true); 
//chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); 

scrollableChart.setContent(chartComposite); 
scrollableChart.setExpandVertical(true); 
scrollableChart.setExpandHorizontal(true); 
scrollableChart.setMinSize(ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH, ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH); 

我的问题是:如何提供一个真正的滚动条到ChartComposite为了保持图形时,多系列绘制在图上?

回答

2

我能够通过使用FormData使用ChartComosite和Slider对象将滑块同步到SWT中的XYSeries。每当我移动滑块时,我都会根据自己的需要捕获该事件并自行更新图表。

我的用例可能与您的用例不同,但值得看一下我的回答here

如果您对我的实现,在这个问题的答案描述的问题,随意询问详情

+0

谢谢,我只是找到了你的帖子在几个小时前,我会尽量解决方案适应我的需要。 – zeropouet 2012-01-12 14:56:57

1

几次不成功的尝试后,我决定限制在图表上显示的LegendItem数量。

要更改图例项目以显示在LegendTitle我使用了滑块。最难的部分是在使用滑块时重新创建一个新的LegendTitle;我不确定我的解决方案是最优的还是优雅的,但至少它工作正常。

Result

要做到这一点,我需要听系列创建(ChartChangeEventType.DATASET_UPDATED)刷新LegendTitle并设置滑块值。

所以这里是代码:

public class MyExampleChartComposite extends ChartComposite { 
    // snip 
    /** 
    * A slider to choose the legend items to display 
    */ 
    private Slider legendSlider; 
    /** 
    * Number of legend items to display on the chart 
    */ 
    private final static int NUMBER_OF_LEGENDITEMS_TO_DISPLAY = 10; 

    private void createPartControl(Composite parent, int style) { 
     JFreeChart chart = createChart(); 
     setChart(chart); 
     legendSlider = new Slider(parent, SWT.NONE|SWT.H_SCROLL); 
     legendSlider.addSelectionListener(new SelectionListener() { 
      @Override 
      public void widgetSelected(SelectionEvent arg0) { 
         refreshLegend(); 
      } 
     }); 

    private JFreeChart createChart() { 
     chart.addChangeListener(new ChartChangeListener() {  
      @Override 
      public void chartChanged(ChartChangeEvent e) { 
        if (e.getType().equals(ChartChangeEventType.DATASET_UPDATED)) { 
         refreshLegend(); 
        } 
      } 
     }); 
    } 

    /** 
    * Refresh the the LegendItems and the slider, 
    * according to slider selection. 
    */ 
    public void refreshLegend() { 
     // Display LegendItems according to the selection 
     // display the 10 nearest legend item (current selected element included) 
     int begin = legendSlider.getSelection() - (NUMBER_OF_LEGENDITEMS_TO_DISPLAY/2); 
     int end = legendSlider.getSelection() + (NUMBER_OF_LEGENDITEMS_TO_DISPLAY/2 -1); 
     int seriesEndIndex = Math.max(getSeriesCount()-1, 0); 
     // if begin is less than 0 
     // set it to 0, and increase end to display 10 items 
     if (begin < 0) { 
      begin = 0; 
      end = NUMBER_OF_LEGENDITEMS_TO_DISPLAY - 1; 
     } 
     // if end is greater than the number of series plotted 
     // set it to the max possible value and increase begin to 
     // display 10 items 
     if (end > seriesEndIndex) { 
      end = seriesEndIndex; 
      begin = seriesEndIndex - (NUMBER_OF_LEGENDITEMS_TO_DISPLAY - 1); 
     } 
     end = Math.min(seriesEndIndex, end); 
     begin = Math.max(begin, 0); 
     // Refresh only if begin != end 
     if (end != begin) { 
      refreshLegendItems(begin, end); 
      refreshLegendSlider(); 
     } else { 
      // in this case no more series are plotted on the chart 
      // clear legend 
      getChart().clearSubtitles(); 
     } 
    } 
    /** 
    * Refresh the LegendTitle. 
    * Display only LegendItems between beginIndex and toIndex, 
    * to preserve space for the chart. 
    * @param beginIndex index of the {@link LegendItemCollection} used as the beginning of the new {@link LegendTitle} 
    * @param endIndex index of the {@link LegendItemCollection} used as the end of the new {@link LegendTitle} 
    */ 
    private void refreshLegendItems(int beginIndex, int endIndex) { 
     // Last 10 items 
     final LegendItemCollection result = new LegendItemCollection(); 
     // get the renderer to retrieve legend items 
     XYPlot plot = getChart().getXYPlot(); 
     XYItemRenderer renderer = plot.getRenderer(); 
     // Number of series displayed on the chart 
     // Construct the legend 
     for (int i = beginIndex; i <= endIndex; i++) { 
      LegendItem item = renderer.getLegendItem(0, i); 
      result.add(item); 
     } 
     // Because the only way to create a new LegendTitle is to 
     // create a LegendItemSource first 
     LegendItemSource source = new LegendItemSource() { 
      LegendItemCollection lic = new LegendItemCollection(); 
      {lic.addAll(result);} 
      public LegendItemCollection getLegendItems() { 
       return lic; 
      } 
     }; 
     // clear previous legend title 
     getChart().clearSubtitles(); 
     // Create the new LegendTitle and set its position 
     LegendTitle legend = new LegendTitle(source); 
     legend.setHorizontalAlignment(HorizontalAlignment.CENTER); 
     legend.setVerticalAlignment(VerticalAlignment.CENTER); 
     legend.setPosition(RectangleEdge.BOTTOM); 
     legend.setBorder(1.0, 1.0, 1.0, 1.0); 
     legend.setVisible(true); 
     // Add the LegendTitle to the graph 
     getChart().addLegend(legend); 
    } 

    /** 
    * Set values of the slider according to the number of series 
    * plotted on the graph 
    */ 
    private void refreshLegendSlider() { 
     int max = getSeriesCount() -1; 
     int selection = Math.min(legendSlider.getSelection(), max); 
     legendSlider.setValues(selection, 0, max, 1, 1, 1); 
    } 
} 
+0

我的问题与你的完全不同,但我能够使用你分享的有关这些JFree类(尤其是'LegendTitle'和'LegendItemSource')的见解。非常感谢! – 2012-09-04 14:45:38