chart scrolling
chart scrolling
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.
Thank you.
Re: chart scrolling
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
Regards,
Dave Gilbert
Re: chart scrolling
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.
Re: chart scrolling
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
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
Re: chart scrolling
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
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
Re: chart scrolling
Cristi,
You can use the setRange(...) method in the DateAxis class to modify the axis range. The chart should automatically update.
Regards,
Dave Gilbert
You can use the setRange(...) method in the DateAxis class to modify the axis range. The chart should automatically update.
Regards,
Dave Gilbert
Re: chart scrolling
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
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
Re: chart scrolling
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
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