JFreeChart: Add and sync a srollbar when zooming a chart (Eclipse plugin / SWT)

后端 未结 2 1916
忘了有多久
忘了有多久 2021-01-25 19:06

I am using JFreeChart library to plot something in an Eclipse view and currently my code for view initialization looks as follows:

@Override
public void createPa         


        
2条回答
  •  孤城傲影
    2021-01-25 19:54

    In addition to the accepted answer I'd like to post an answer myself, because I ran into a couple of issues regarding to SlidingXYDataset:

    1. The implementation allows to specify the number of points in the dataset that can be shown at any given time and that is OK for most use cases. But in the case where the data points are sparsed very uniformly in the dataset sliding thorugh data will cause the domain axis to change its range.
      For example if the window size is 5 datapoints and first 5 are 2 units appart and the next 5 are 20 units appart the X axis visible range size will change when your are sliding.
      So you can see what the behaviour will look like when all the points are ploted at arbitrary locations. This may or may not be a desired behaviour. In my case I needed to have a fixed visible range of the X axis (for example 200 units) and to keep it as such all the time.

    2. For some reason I was not able to create a SlidingXYDataset by giving it an empty XYSeriesCollection/TimeSeriesCollection. I needed to start with an empty dataset and update it in real time and I had to add useless data to start with. But that's maybe because I was doing something wrong.


    Having said that above, there might be workarounds for it, but I went and implemented the zooming and scrollbar in a different than the accepted answer's way.

    Also this example shows how to sync the slider when user performs a zoom action on the graph.


    First: you need to create an XYLineChart and set the desired range (The example is elaborated for X axis only, but can be applied for Y axis as well)

    XYSeries dataset = new XYSeries("my dataset");
    XYSeriesCollection datasetCollection = new XYSeriesCollection(dataset);
    JFreeChart chart = ChartFactory.createXYLineChart("title", 
                       "x label", 
                       "y label", 
                       datasetCollection, 
                       PlotOrientation.VERTICAL, 
                       true, false, false);
    
    XYPlot plot = chart.getXYPlot();
    ValueAxis domainAxis = plot.getDomainAxis();
    ValueAxis rangeAxis  = plot.getRangeAxis();
    
    domainAxis.setAutoRange(false);
    domainAxis.setFixedAutoRange(300); // 300 units visible at anytime on X axis
    domainAxis.setLowerBound(0); // start from 0
    


    Second: you need to put both the chart and a scroll bar inside the parent layout. In SWT you can do this for example through the user of FormLayout

    // Given that composite is the parent Composite
    FormLayout layout = new FormLayout();
    composite.setLayout(layout);
    
    chartComposite = new ChartComposite(composite, SWT.NONE, chart, true);
    Slider slider = new Slider(composite, SWT.NONE);
    sldier.setValues(/* depends on your needs */);
    
    // add the slider to the bottom of the form
    FormData sliderLayoutData = new FormData();
    sliderLayoutData.left = new FormAttachment(0,0);
    sliderLayoutData.bottom = new FormAttachment(100,0);
    sliderLayoutData.right = new FormAttachment(100,0);
    slider.setLayoutData(sliderLayoutData);
    
    // now add the graphComposite to the form above the slider
    FormData graphLayoutData = new FormData();
    graphLayoutData.left = new FormAttachment(0,0);
    graphLayoutData.right = new FormAttachment(100,0);
    graphLayoutData.top = new FormAttachment(0,0);
    graphLayoutData.bottom = new FormAttachment(slider);      
    chartComposite.setLayoutData(graphLayoutData);    
    
    // refresh the layout
    composite.layout(true);
    

    Now every time you move the slider, you need to capture that event and change the chart's domain range with the to methods according to you slider data:

      domainAxis.setLowerBound(minimum visible);
      domainAxis.setUpperBound(maximum visible);
    


    Third: Finaly you need to override the zoom method of the ChartComposite either by extending this object or right above when you create a new one

    @Override 
    public void zoom(Rectangle selection)
    {
      XYPlot plot = (XYPlot) getChart().getPlot();
      Rectangle2D plotArea = new Rectangle2D.Double( getScreenDataArea().x,
              getScreenDataArea().y,
              getScreenDataArea().width,
              getScreenDataArea().height);
    
      float x1 = (float) plot.getDomainAxis().
                           java2DToValue(selection.x, 
                                         plotArea, 
                                         plot.getDomainAxisEdge());
    
      float x2 = (float) plot.getDomainAxis().
                           java2DToValue(selection.x + selection.width, 
                                         plotArea, 
                                         plot.getDomainAxisEdge());
    
      // x1 and x2 will have the points transalted into chart coordinates
        // of the selection the user made for zooming the X axis  
      // you can adjust your chart to show only the selected (zoomed) 
        // information as such
      domainAxis.setLowerBound(x1);
      domainAxis.setUpperBound(x2);
    
      // and now adjust the slider information so it's 
        // synced to your graph's current view
      sldier.setValues(/* depends on your needs */);
    }
    

    Hope this implementation can find it's use in other people's use cases.

提交回复
热议问题