chart scrolling

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Cristi Buta

chart scrolling

Post by Cristi Buta » Wed Feb 19, 2003 12:33 pm

I am using a TimeSeriesChart (with XYPlot). How can I put only the plot area in a JScrollPane (I am interesed in scrolling only the plot area, not the entire chart)? If this is possible, could you help me with a small source code please ?

Thank you.

David Gilbert

Re: chart scrolling

Post by David Gilbert » Wed Feb 19, 2003 1:04 pm

Because JFreeChart draws the entire chart via a Graphics2D object, it isn't possible to put scrollbars around any sub-component of the chart. I guess it would be possible to hide the chart titles, legend, and axes and put just the plot inside scrollbars...and then somehow try to synchronise that will axes etc. drawn outside the scrollbars. But I think it wouldn't be easy to get it to work well.

Regards,

Dave Gilbert

Cristi Buta

Re: chart scrolling

Post by Cristi Buta » Wed Feb 19, 2003 1:47 pm

David Gilbert, thank you for your answer. I just looked over the source code and I saw that it is drawn via Graphics2D. I will have to think to a solution.

Cristi Buta

Re: chart scrolling

Post by Cristi Buta » Wed Feb 19, 2003 1:57 pm

For David Gilbert,

Could you tell me how to center the plot area to a certain point ? (a certain minute, because I am using a TimeSeriesChart, with Minute.class. I guess Calendar is used and getTime to return that "long" value. So I was thinking that if I can center the XYplot, I could use a scrollBar with which I could scroll it by centering the plot to a certain position.
You think this is possible ?

Regards,
Cristi Buta

Martin Goebel

Re: chart scrolling

Post by Martin Goebel » Tue Feb 25, 2003 12:05 pm

Hi Cristi,

have you had any success in solving this scrolling problem or are you still working on that?
I just came across the same problem that you had - - maybe you can already give me any hints.


Regards,
Martin

David Gilbert

Re: chart scrolling

Post by David Gilbert » Wed Feb 26, 2003 12:50 am

Cristi,

You can use the setRange(...) method in the DateAxis class to modify the axis range. The chart should automatically update.

Regards,

Dave Gilbert

Cristi Buta

Re: chart scrolling

Post by Cristi Buta » Wed Feb 26, 2003 12:08 pm

Here is the solution that I found:

Put a scrollbar under the chart, an on adjustmentValueChanged event for the scrollbar, call this method center. Here is the source code for this method:

public void center(double value){
long currentTime = (new GregorianCalendar()).getTime().getTime();
plot.getDomainAxis().setRange((double)currentTime-value*10.0*60000.0-3.0*60.0*60000.0, (double)currentTime-value*10.0*60000.0);
}

(where plot = chart.getXYPlot(); and value = scrollBar's value)

(new GregorianCalendar()).getTime ().getTime() returns the current time (in miliseconds). value represents the number of minutes for scrolling. 10.0*60000.0 = 10 minutes. So "value*10*60000" = scrolling by 10 minutes.

"-3*60*60000.0" means that I display the grafic with a range of 3 hours. You can modify it to respect your needs.

and code for adjustmentValueChanged:

void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
dataChart.centeraxis((double)((10.0-e.getValue())));
}

My ScrollBar has these caractheristics:

jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
jScrollBar1.setMaximum(11);
jScrollBar1.setVisibleAmount(1);
jScrollBar1.setBlockIncrement(1);
jScrollBar1.setValue(10);


Regards,

Cristi Buta

Martin Goebel

Re: chart scrolling

Post by Martin Goebel » Tue Mar 04, 2003 4:13 pm

Hi Cristian,

thanks for your answer!
Based on your solution I tried to find a more generic approach including the resize of the value and extent of the ScrollBar when the user has zoomed in the chart.
I had some problems with cyclic event firing (PlotChangeEvents and AdjustmentEvents - the ...Changed() methods generated one of the opposite events) resulting in an endless loop, but I fixed this with a "doAdjust" flag in my PlotListeningScrollBar (this solution does not seem very elegant to me, maybe you could think of a better one?).


Here is my code (currently only horizontal ScrollBar implemented):

in my chart-generating class:

int scrollMax = 400;
int scrollMin = 1;
int scrollExtent = 20;
double scrollWidth = (double)scrollExtent / (double)scrollMax;
PlotListeningScrollBar scrollBar = new PlotListeningScrollBar(JScrollBar.HORIZONTAL, scrollMax / 2,
scrollExtent, scrollMin, scrollMax, chartPanel);

scrollBar.setBlockIncrement(10);
plot.addChangeListener(scrollBar);

...

My subclassed ScrollBar:

class PlotListeningScrollBar extends JScrollBar implements PlotChangeListener, AdjustmentListener
{
// values will be used more frequently, so make them private members
private ChartPanel chartPanel;
private ValueAxis valueAxis;
private double displayMin;
private double displayMax;
private double rangeMin;
private double rangeMax;
private double dataMin;
private double dataMax;
private double displayRange;

// flag to inidicate if an adjustment has to be performed
private boolean doAdjust;


public PlotListeningScrollBar(int orientation, int value, int extent, int min, int max,
ChartPanel chartPanel)
{
super(orientation, value, extent, min, max);
this.chartPanel = chartPanel;
// TO DO: consider vertical orientation
this.valueAxis = chartPanel.getChart().getXYPlot().getDomainAxis();
this.doAdjust = true;

this.adjustScrollBar();
this.addAdjustmentListener(this);
}

public void plotChanged(PlotChangeEvent event)
{
this.adjustScrollBar();
}

public void adjustScrollBar()
{
if (orientation == this.VERTICAL)
{
//TO DO: implementation of vertical bars
}
else if (this.orientation == this.HORIZONTAL)
{
if (doAdjust)
{
getMinMaxValues();

// adjust value and extent of the scrollBar
double offsetPercentage = (rangeMin - displayMin) / displayRange;
double value = this.getMinimum() + offsetPercentage * (this.getMaximum() - this.getMinimum());
double ratio = (rangeMax - rangeMin) / displayRange;

//System.out.println("Try to set to: Value: " + (int)value + " Extent: " +
// (int)(ratio * (this.getMaximum() - this.getMinimum())));
//System.out.println("While maximum: " + this.getMaximum() + " minimum: " + this.getMinimum());
this.doAdjust = false;
this.model.setValue((int)value);
this.setVisibleAmount((int)(ratio * (this.getMaximum() - this.getMinimum())));

//System.out.println("Set values: Min: " + this.getMinimum() + " Max: " + this.getMaximum() + " Value: " + this.getValue() +
//" Extent: " + this.getVisibleAmount());
this.doAdjust = true;
}
}
}

public void adjustmentValueChanged(AdjustmentEvent e)
{
if (!e.getValueIsAdjusting())
{
if (doAdjust)
{
double value = ((double)(e.getValue()));
getMinMaxValues();

//System.out.println("AdjustmentEvent occured----------------, adjusting to actual value: " + value);
// adjust the range of the chart
double leftBound = displayMin + (displayRange) * value / this.getMaximum();
double rightBound = leftBound + (displayRange) * this.getVisibleAmount() / this.getMaximum();

doAdjust = false;
chart.getXYPlot().getDomainAxis().setRange(leftBound, rightBound);
doAdjust = true;
}
}
}

/**
* Convenient method to calculate the min/max values of the data and the chart.
*/
private void getMinMaxValues()
{
dataMin = DatasetUtilities.getMinimumDomainValue(chartPanel.getChart().getXYPlot().getXYDataset()).doubleValue();
rangeMin = valueAxis.getMinimumAxisValue();
dataMax = DatasetUtilities.getMaximumDomainValue(chartPanel.getChart().getXYPlot().getXYDataset()).doubleValue();
rangeMax = valueAxis.getMaximumAxisValue();
// valueAxis range may be outside DatasetExtent (e.g. the user has zoomed with the left/right bound
// as zoom reference point), so we have to get the complete display bounds
displayMin = Math.min(dataMin, rangeMin);
displayMax = Math.max(dataMax, rangeMax);
displayRange = displayMax - displayMin;
}
}


Greets,

Martin

Locked