Windowing of data

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
knc
Posts: 19
Joined: Mon Aug 07, 2006 11:12 pm

Windowing of data

Post by knc » Tue Aug 08, 2006 4:36 pm

Hello

I'm evaluating JFreeChart for use in plotting several years of data on an XY plot. I would like to display the data in one year "chunks" - that is, I do not want to plot 50 years of data in one window. I want to present the data in smaller pieces, one year at a time, and then let the user scroll horizontally to see the next set of data. Does JFreeChart provide ways for windowing the data like this? I found one message posted that may provide a solution for what I'm trying to do - I can't post the URL because I'm a new user, though.

Please let me know if anyone else has dealt with this same issue.

Thanks,
knc

SeanMcCrohan
Posts: 18
Joined: Thu May 11, 2006 11:22 pm

Post by SeanMcCrohan » Tue Aug 08, 2006 5:25 pm

There are two ways I can think of right off the bat to do that.

1) Load all of the data up front. Disable the zoom controls. Zoom the chart (set the domain axis range) to cover a 1-year span. Provide forward and back buttons to move the range in either direction. The last part of that is quite easy - I've done it on my charts, to allow users to pan back and forth after zooming in.

2) Load one year of data up front. Provide forward and back buttons, each of which dumps the contents of the current dataset and updates the new chart. This one isn't very hard, either.

The big factor for deciding between them will be the lagtime - loading all of the data up front will incur the delay at the beginning, while paging through it will have a small delay each time they move to a new page. It mostly comes down to how many pages they're likely to be flipping through.

knc
Posts: 19
Joined: Mon Aug 07, 2006 11:12 pm

Post by knc » Tue Aug 22, 2006 3:18 pm

I like the idea of zooming/scrolling the chart to show more data. I am trying to add a scrollbar to my chart, so that I can view portions of the dataset in one window and scroll to see more, but I'm having a very difficult time with the scrollbar. To start I've modified the code for an example I found online - the ChartPanelShiftController, where you can push the left or right arrow to scroll horizontally. With the modifications I've made I can move the scrollbar to the right with the mouse and the x-axis changes to reflect the mouse move; however when I move the mouse to the left the x-axis continues to increase rather than decrease :( I've looked at several scrolling graph examples and am still not understanding what I need to do to make a scrollbar work correctly. I'll post the code for the classes that I'm using, if anyone has any advice I would appreciate it.

Thanks,
knc

package br.com.cpqd.chart.tools;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import org.jfree.chart.*;
import org.jfree.chart.event.*;
import org.jfree.chart.plot.*;
import org.jfree.data.Range;
import org.jfree.data.xy.*;
import org.jfree.ui.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.event.ChartChangeListener;

import br.com.cpqd.chart.tools.ChartPanelShiftController;

public class ScrollingChart extends JFrame implements ChangeListener, ChartChangeListener,
AdjustmentListener
{

/**
*
*/
private static final long serialVersionUID = 1L;
private ChartPanelShiftController controller;
private JScrollBar scrollbar;
private double scrollFactor = 1;
private ChartPanel panel;




public ScrollingChart() {
panel = new ChartPanel(createChart(createDataset(100)));

// set the max value for the x-axis to be 50, for the first data
// set displayed
ValueAxis axis = ((XYPlot)panel.getChart().getPlot()).getDomainAxis();

((XYPlot)panel.getChart().getPlot()).setDomainCrosshairLockedOnData(true);
((XYPlot)panel.getChart().getPlot()).setDomainCrosshairVisible(true);
axis.setAutoRange(false);
axis.setUpperBound(50);
axis.setUpperMargin(0);
axis.setLowerMargin(0);
controller = new ChartPanelShiftController(panel);
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
controller.keyPressed(e);
}
return false;
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel,BorderLayout.CENTER);
getContentPane().add(createOptionPanel(),BorderLayout.SOUTH);


// scrollbar stuff!
final BoundedRangeModel scrollBarModel = this.scrollbar.getModel();
scrollBarModel.addChangeListener(this);
//BoundedRangeModel scrollBarModel = scrollbar.getModel();
final ValueAxis xAxis = ((XYPlot)panel.getChart().getPlot()).getDomainAxis();
final Range xAxisRange = xAxis.getRange();
System.out.println("Range = " + xAxisRange);


//final int low = (int) (xAxisRange.getLowerBound() * this.scrollFactor);
final int low = (int) (xAxisRange.getLowerBound());
scrollBarModel.setValue(low);
//final int ext = (int) (xAxisRange.getUpperBound());
scrollBarModel.setExtent(10);
//scrollBarModel.setExtent(100);

scrollbar.addAdjustmentListener(this);

}

private JPanel createOptionPanel() {
JPanel optionPanel = new JPanel();
optionPanel.setLayout(new BorderLayout());

JPanel buttonPanel = new JPanel();
JPanel scrollBarPanel = new JPanel();


// add a scrollbar
scrollbar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 25, 0, 50);
scrollbar.setModel(new DefaultBoundedRangeModel());
scrollbar.setOrientation(SwingConstants.HORIZONTAL);
scrollbar.setEnabled(true);
scrollBarPanel.setLayout(new BorderLayout());
scrollBarPanel.add(scrollbar, BorderLayout.SOUTH);

ButtonGroup bg = new ButtonGroup();
//optionPanel.setLayout(new GridLayout(1,3));
buttonPanel.setLayout(new GridLayout(1,3));
JRadioButton btn = new JRadioButton("Percentual (1%)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_PERCENTUAL);
}});
bg.add(btn); buttonPanel.add(btn,null);
btn = new JRadioButton("Fixed (20u Domain, 50u Range)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_FIXED);
controller.setFixedDomainShiftUnits(20);
controller.setFixedRangeShiftUnits(50);
}});
bg.add(btn); buttonPanel.add(btn,null);
btn = new JRadioButton("Pixel (1px)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_PIXEL);
controller.setFixedDomainShiftUnits(20);
controller.setFixedRangeShiftUnits(50);
}});
btn.setSelected(true); bg.add(btn); buttonPanel.add(btn,null);

optionPanel.add(buttonPanel, BorderLayout.CENTER);
optionPanel.add(scrollBarPanel, BorderLayout.SOUTH);

return optionPanel;
}

/**
* Creates a sample dataset.
* @return a sample dataset.
*/
public XYDataset createDataset(int numPoints) {
final XYSeries series1 = new XYSeries("Test");
for(int i=0; i<numPoints; i++) {
series1.add(i, Math.random()*100);
}
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);
return dataset;
}

/**
* Creates a chart.
* @param dataset the data for the chart.
* @return a chart.
*/
public JFreeChart createChart(final XYDataset dataset) {
// create the chart...
final JFreeChart chart = ChartFactory.createXYLineChart(
"Pan Test - use arrow keys (Press SHIFT to pan 10x faster)", // chart title
"X", // x axis label
"Y", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
false, // include legend
false, // tooltips
false // urls
);
// get a reference to the plot for further customisation...
XYPlot plot = (XYPlot) chart.getPlot();
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));

return chart;
}

/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(final String[] args) {
final ScrollingChart demo = new ScrollingChart();
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}

public void stateChanged(ChangeEvent ce)
{
System.out.println("state changed");

try {
final Object src = ce.getSource();
final BoundedRangeModel scrollBarModel = this.scrollbar.getModel();
if (src == scrollBarModel) {
final int val = scrollBarModel.getValue();
final int ext = scrollBarModel.getExtent();
System.out.println("val = " + val);
System.out.println("ext = " + ext);


final Plot plot = this.panel.getChart().getPlot();
if (plot instanceof XYPlot) {
final XYPlot hvp = (XYPlot) plot;
final ValueAxis axis = hvp.getDomainAxis();

// avoid problems
this.panel.getChart().removeChangeListener(this);

double delta;
delta = (axis.getUpperBound()-axis.getLowerBound())/100.0;
System.out.println("delta = " + delta);
axis.setRange(axis.getLowerBound()+delta,axis.getUpperBound()+delta);


// restore chart listener
this.panel.getChart().addChangeListener(this);


}

}
}
catch (Exception e) {
e.printStackTrace();
}


}

public void chartChanged(ChartChangeEvent ce)
{
System.out.println("chart change event");

}

public void adjustmentValueChanged(AdjustmentEvent ae)
{
}
}


package br.com.cpqd.chart.tools;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.ContourPlot;
import org.jfree.chart.plot.FastScatterPlot;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;

/**
* This class provides ways to shift (aka pan/scroll) a plot. The shift is done
* through the arrow keys and its step can be configured to be a fixed amount,
* a percentual of the current axis or a range in pixels.
* <p>
* This class only supports plots of type {@link org.jfree.chart.plot.XYPlot XYPlot},
* {@link org.jfree.chart.plot.ContourPlot ContourPlot} and
* {@link org.jfree.chart.plot.FastScatterPlot FastScatterPlot}.
* <p>
* Use &larr; and &rarr; to shift the plot left and right; <br>
* Use &uarr; and &darr; to shift the plot up and down; <br>
* Press the SHIFT key to increase the shift by a factor of 10.
*
* @author Gustavo H. Sberze Ribas (CPqD)
* @version 0.1
*/
public class ChartPanelShiftController implements KeyListener{

/** PAN plot by a fixed percentual of the range (eg. 1%) */
public static final int SHIFT_PERCENTUAL = 1;
/** PAN plot by a fixed number of pixels (eg. 1px) */
public static final int SHIFT_PIXEL = 2;
/** PAN plot by a fixed amout (eg. 5 range units) */
public static final int SHIFT_FIXED = 3;


/** The chart panel we're using */
protected ChartPanel chartPanel;

/** Does this plot supports shifting? Pie charts for example don't. */
protected boolean plotSupported = false;

/** The shift type. (default {@link #SHIFT_PIXEL} ) */
protected int shiftType = SHIFT_PIXEL;

/** Fixed shift amount for domain axis */
protected double fixedDomainShiftUnits;
/** Fixed shift amount for range axis */
protected double fixedRangeShiftUnits;

/** By default we assume that the range axis is the vertical one (ie,
* PlotOrientation.VERTICAL (axesSwaped=false). If the range axis is the
* horizontal one (ie, PlotOrientation.HORIZONTAL) this variable should
* be set to true. */
protected boolean axesSwaped = false;

/**
* Creates a new controller to handle plot shifts.
* @param chartPanel The panel displaying the plot.
*/
public ChartPanelShiftController(ChartPanel chartPanel) {
super();
this.chartPanel = chartPanel;

// Check to see if plot is shiftable
Plot plot = chartPanel.getChart().getPlot();
if ((plot instanceof XYPlot) ||
(plot instanceof FastScatterPlot) ||
(plot instanceof ContourPlot)
) {
plotSupported = true;
axesSwaped = isHorizontalPlot(plot);
}
}


/**
* Returns the plot orientation.
* @return True = {@link org.jfree.chart.plot.PlotOrientation#VERTICAL VERTICAL};
* False = {@link org.jfree.chart.plot.PlotOrientation#HORIZONTAL HORIZONTAL}
*/
protected boolean isHorizontalPlot(Plot plot) {
if (plot instanceof XYPlot) {
return ((XYPlot)plot).getOrientation()==PlotOrientation.HORIZONTAL;
}
if (plot instanceof FastScatterPlot) {
return ((FastScatterPlot)plot).getOrientation()==PlotOrientation.HORIZONTAL;
}
return false;
}


/**
* Returns the ValueAxis for the plot or <code>null</code> if the plot
* doesn't have one.
* @param chart The chart
* @param domain True = get Domain axis. False = get Range axis.
* @return The selected ValueAxis or <code>null</code> if the plot doesn't
* have one.
*/
protected ValueAxis getPlotAxis(JFreeChart chart, boolean domain) {
// Where's the Shiftable interface when we need it ?? ;)
Plot plot = chart.getPlot();
if (plot instanceof XYPlot) {
return domain?((XYPlot)plot).getDomainAxis():((XYPlot)plot).getRangeAxis();
}
if (plot instanceof FastScatterPlot) {
return domain?((FastScatterPlot)plot).getDomainAxis():((FastScatterPlot)plot).getRangeAxis();
}
if (plot instanceof ContourPlot) {
return domain?((ContourPlot)plot).getDomainAxis():((ContourPlot)plot).getRangeAxis();
}
return null;
}


/**
* Pan/Shifts a plot if the arrow keys are pressed.
* @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
*/
public void keyPressed(KeyEvent e)
{
System.out.println("keyPressed");
if (!plotSupported) return;

int keyCode = e.getKeyCode();

// we're only interested in arrows (code 37,38,39,40)
if ((keyCode < 37) || (keyCode > 40)) return;

// The axis we're gonna shift
ValueAxis axis = null;

// Delta is the amount we'll shift in axis units.
double delta;

boolean domainShift = false; // used for PAN_FIXED
// Calculations for the domain axis
if ((keyCode == KeyEvent.VK_LEFT) || (keyCode == KeyEvent.VK_RIGHT))
{
axis = getPlotAxis(chartPanel.getChart(),!axesSwaped);
domainShift = true;
}
// Calculations for the range axis
else {
axis = getPlotAxis(chartPanel.getChart(),axesSwaped);
}

// Let's calculate 'delta', the amount by which we'll shift the plot
switch (shiftType) {
case SHIFT_PERCENTUAL:
delta = (axis.getUpperBound()-axis.getLowerBound())/100.0;
break;
case SHIFT_FIXED:
delta = (domainShift ? fixedDomainShiftUnits : fixedRangeShiftUnits);
break;
case SHIFT_PIXEL: // also the default
default:
// Let's find out what's the range for 1 pixel.
final Rectangle2D scaledDataArea = chartPanel.getScreenDataArea();
delta = axis.getRange().getLength() / (scaledDataArea.getWidth());
break;
}

System.out.println("key pressed delta" + delta);
// Shift modifier multiplies delta by 10
if (e.isShiftDown()) {
delta *= 10;
}

switch (keyCode) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_DOWN:
axis.setRange(axis.getLowerBound()-delta,axis.getUpperBound()-delta);
break;
case KeyEvent.VK_UP:
case KeyEvent.VK_RIGHT:
axis.setRange(axis.getLowerBound()+delta,axis.getUpperBound()+delta);
break;
}
}

/*
* @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
*/
public void keyTyped(KeyEvent e) {}
/*
* @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
*/
public void keyReleased(KeyEvent e) {}


/**
* Returns the fixed shift step for the domain axis.
* @return the fixed shift step for the domain axis.
*/
public double getFixedDomainShiftUnits() {
return fixedDomainShiftUnits;
}
/**
* Sets the fixed shift step for the domain axis.
* @param fixedDomainShiftUnits the fixed shift step for the domain axis.
*/
public void setFixedDomainShiftUnits(double fixedDomainShiftUnits) {
this.fixedDomainShiftUnits = fixedDomainShiftUnits;
}
/**
* Returns the fixed shift step for the range axis.
* @return the fixed shift step for the range axis.
*/
public double getFixedRangeShiftUnits() {
return fixedRangeShiftUnits;
}
/**
* Sets the fixed shift step for the range axis.
* @param fixedRangeShiftUnits the fixed shift step for the range axis.
*/
public void setFixedRangeShiftUnits(double fixedRangeShiftUnits) {
this.fixedRangeShiftUnits = fixedRangeShiftUnits;
}
/**
* Returns the current shift type.
* @return the current shift type.
* @see #SHIFT_FIXED
* @see #SHIFT_PERCENTUAL
* @see #SHIFT_PIXEL
*/
public int getShiftType() {
return shiftType;
}
/**
* Sets the shift type.
* @param the new shift type.
* @see #SHIFT_FIXED
* @see #SHIFT_PERCENTUAL
* @see #SHIFT_PIXEL
*/
public void setShiftType(int shiftType) {
this.shiftType = shiftType;
}
/**
* Returns whether or not the plot supports shifting.
* @return True if plot can be shifted.
*/
public boolean isPlotSupported() {
return plotSupported;
}
}

knc
Posts: 19
Joined: Mon Aug 07, 2006 11:12 pm

Post by knc » Tue Aug 22, 2006 3:18 pm

I like the idea of zooming/scrolling the chart to show more data. I am trying to add a scrollbar to my chart, so that I can view portions of the dataset in one window and scroll to see more, but I'm having a very difficult time with the scrollbar. To start I've modified the code for an example I found online - the ChartPanelShiftController, where you can push the left or right arrow to scroll horizontally. With the modifications I've made I can move the scrollbar to the right with the mouse and the x-axis changes to reflect the mouse move; however when I move the mouse to the left the x-axis continues to increase rather than decrease :( I've looked at several scrolling graph examples and am still not understanding what I need to do to make a scrollbar work correctly. I'll post the code for the classes that I'm using, if anyone has any advice I would appreciate it.

Thanks,
knc

package br.com.cpqd.chart.tools;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import org.jfree.chart.*;
import org.jfree.chart.event.*;
import org.jfree.chart.plot.*;
import org.jfree.data.Range;
import org.jfree.data.xy.*;
import org.jfree.ui.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.event.ChartChangeListener;

import br.com.cpqd.chart.tools.ChartPanelShiftController;

public class ScrollingChart extends JFrame implements ChangeListener, ChartChangeListener,
AdjustmentListener
{

/**
*
*/
private static final long serialVersionUID = 1L;
private ChartPanelShiftController controller;
private JScrollBar scrollbar;
private double scrollFactor = 1;
private ChartPanel panel;




public ScrollingChart() {
panel = new ChartPanel(createChart(createDataset(100)));

// set the max value for the x-axis to be 50, for the first data
// set displayed
ValueAxis axis = ((XYPlot)panel.getChart().getPlot()).getDomainAxis();

((XYPlot)panel.getChart().getPlot()).setDomainCrosshairLockedOnData(true);
((XYPlot)panel.getChart().getPlot()).setDomainCrosshairVisible(true);
axis.setAutoRange(false);
axis.setUpperBound(50);
axis.setUpperMargin(0);
axis.setLowerMargin(0);
controller = new ChartPanelShiftController(panel);
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
controller.keyPressed(e);
}
return false;
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel,BorderLayout.CENTER);
getContentPane().add(createOptionPanel(),BorderLayout.SOUTH);


// scrollbar stuff!
final BoundedRangeModel scrollBarModel = this.scrollbar.getModel();
scrollBarModel.addChangeListener(this);
//BoundedRangeModel scrollBarModel = scrollbar.getModel();
final ValueAxis xAxis = ((XYPlot)panel.getChart().getPlot()).getDomainAxis();
final Range xAxisRange = xAxis.getRange();
System.out.println("Range = " + xAxisRange);


//final int low = (int) (xAxisRange.getLowerBound() * this.scrollFactor);
final int low = (int) (xAxisRange.getLowerBound());
scrollBarModel.setValue(low);
//final int ext = (int) (xAxisRange.getUpperBound());
scrollBarModel.setExtent(10);
//scrollBarModel.setExtent(100);

scrollbar.addAdjustmentListener(this);

}

private JPanel createOptionPanel() {
JPanel optionPanel = new JPanel();
optionPanel.setLayout(new BorderLayout());

JPanel buttonPanel = new JPanel();
JPanel scrollBarPanel = new JPanel();


// add a scrollbar
scrollbar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 25, 0, 50);
scrollbar.setModel(new DefaultBoundedRangeModel());
scrollbar.setOrientation(SwingConstants.HORIZONTAL);
scrollbar.setEnabled(true);
scrollBarPanel.setLayout(new BorderLayout());
scrollBarPanel.add(scrollbar, BorderLayout.SOUTH);

ButtonGroup bg = new ButtonGroup();
//optionPanel.setLayout(new GridLayout(1,3));
buttonPanel.setLayout(new GridLayout(1,3));
JRadioButton btn = new JRadioButton("Percentual (1%)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_PERCENTUAL);
}});
bg.add(btn); buttonPanel.add(btn,null);
btn = new JRadioButton("Fixed (20u Domain, 50u Range)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_FIXED);
controller.setFixedDomainShiftUnits(20);
controller.setFixedRangeShiftUnits(50);
}});
bg.add(btn); buttonPanel.add(btn,null);
btn = new JRadioButton("Pixel (1px)");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
controller.setShiftType(ChartPanelShiftController.SHIFT_PIXEL);
controller.setFixedDomainShiftUnits(20);
controller.setFixedRangeShiftUnits(50);
}});
btn.setSelected(true); bg.add(btn); buttonPanel.add(btn,null);

optionPanel.add(buttonPanel, BorderLayout.CENTER);
optionPanel.add(scrollBarPanel, BorderLayout.SOUTH);

return optionPanel;
}

/**
* Creates a sample dataset.
* @return a sample dataset.
*/
public XYDataset createDataset(int numPoints) {
final XYSeries series1 = new XYSeries("Test");
for(int i=0; i<numPoints; i++) {
series1.add(i, Math.random()*100);
}
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);
return dataset;
}

/**
* Creates a chart.
* @param dataset the data for the chart.
* @return a chart.
*/
public JFreeChart createChart(final XYDataset dataset) {
// create the chart...
final JFreeChart chart = ChartFactory.createXYLineChart(
"Pan Test - use arrow keys (Press SHIFT to pan 10x faster)", // chart title
"X", // x axis label
"Y", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
false, // include legend
false, // tooltips
false // urls
);
// get a reference to the plot for further customisation...
XYPlot plot = (XYPlot) chart.getPlot();
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));

return chart;
}

/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(final String[] args) {
final ScrollingChart demo = new ScrollingChart();
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}

public void stateChanged(ChangeEvent ce)
{
System.out.println("state changed");

try {
final Object src = ce.getSource();
final BoundedRangeModel scrollBarModel = this.scrollbar.getModel();
if (src == scrollBarModel) {
final int val = scrollBarModel.getValue();
final int ext = scrollBarModel.getExtent();
System.out.println("val = " + val);
System.out.println("ext = " + ext);


final Plot plot = this.panel.getChart().getPlot();
if (plot instanceof XYPlot) {
final XYPlot hvp = (XYPlot) plot;
final ValueAxis axis = hvp.getDomainAxis();

// avoid problems
this.panel.getChart().removeChangeListener(this);

double delta;
delta = (axis.getUpperBound()-axis.getLowerBound())/100.0;
System.out.println("delta = " + delta);
axis.setRange(axis.getLowerBound()+delta,axis.getUpperBound()+delta);


// restore chart listener
this.panel.getChart().addChangeListener(this);


}

}
}
catch (Exception e) {
e.printStackTrace();
}


}

public void chartChanged(ChartChangeEvent ce)
{
System.out.println("chart change event");

}

public void adjustmentValueChanged(AdjustmentEvent ae)
{
}
}


package br.com.cpqd.chart.tools;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.ContourPlot;
import org.jfree.chart.plot.FastScatterPlot;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;

/**
* This class provides ways to shift (aka pan/scroll) a plot. The shift is done
* through the arrow keys and its step can be configured to be a fixed amount,
* a percentual of the current axis or a range in pixels.
* <p>
* This class only supports plots of type {@link org.jfree.chart.plot.XYPlot XYPlot},
* {@link org.jfree.chart.plot.ContourPlot ContourPlot} and
* {@link org.jfree.chart.plot.FastScatterPlot FastScatterPlot}.
* <p>
* Use &larr; and &rarr; to shift the plot left and right; <br>
* Use &uarr; and &darr; to shift the plot up and down; <br>
* Press the SHIFT key to increase the shift by a factor of 10.
*
* @author Gustavo H. Sberze Ribas (CPqD)
* @version 0.1
*/
public class ChartPanelShiftController implements KeyListener{

/** PAN plot by a fixed percentual of the range (eg. 1%) */
public static final int SHIFT_PERCENTUAL = 1;
/** PAN plot by a fixed number of pixels (eg. 1px) */
public static final int SHIFT_PIXEL = 2;
/** PAN plot by a fixed amout (eg. 5 range units) */
public static final int SHIFT_FIXED = 3;


/** The chart panel we're using */
protected ChartPanel chartPanel;

/** Does this plot supports shifting? Pie charts for example don't. */
protected boolean plotSupported = false;

/** The shift type. (default {@link #SHIFT_PIXEL} ) */
protected int shiftType = SHIFT_PIXEL;

/** Fixed shift amount for domain axis */
protected double fixedDomainShiftUnits;
/** Fixed shift amount for range axis */
protected double fixedRangeShiftUnits;

/** By default we assume that the range axis is the vertical one (ie,
* PlotOrientation.VERTICAL (axesSwaped=false). If the range axis is the
* horizontal one (ie, PlotOrientation.HORIZONTAL) this variable should
* be set to true. */
protected boolean axesSwaped = false;

/**
* Creates a new controller to handle plot shifts.
* @param chartPanel The panel displaying the plot.
*/
public ChartPanelShiftController(ChartPanel chartPanel) {
super();
this.chartPanel = chartPanel;

// Check to see if plot is shiftable
Plot plot = chartPanel.getChart().getPlot();
if ((plot instanceof XYPlot) ||
(plot instanceof FastScatterPlot) ||
(plot instanceof ContourPlot)
) {
plotSupported = true;
axesSwaped = isHorizontalPlot(plot);
}
}


/**
* Returns the plot orientation.
* @return True = {@link org.jfree.chart.plot.PlotOrientation#VERTICAL VERTICAL};
* False = {@link org.jfree.chart.plot.PlotOrientation#HORIZONTAL HORIZONTAL}
*/
protected boolean isHorizontalPlot(Plot plot) {
if (plot instanceof XYPlot) {
return ((XYPlot)plot).getOrientation()==PlotOrientation.HORIZONTAL;
}
if (plot instanceof FastScatterPlot) {
return ((FastScatterPlot)plot).getOrientation()==PlotOrientation.HORIZONTAL;
}
return false;
}


/**
* Returns the ValueAxis for the plot or <code>null</code> if the plot
* doesn't have one.
* @param chart The chart
* @param domain True = get Domain axis. False = get Range axis.
* @return The selected ValueAxis or <code>null</code> if the plot doesn't
* have one.
*/
protected ValueAxis getPlotAxis(JFreeChart chart, boolean domain) {
// Where's the Shiftable interface when we need it ?? ;)
Plot plot = chart.getPlot();
if (plot instanceof XYPlot) {
return domain?((XYPlot)plot).getDomainAxis():((XYPlot)plot).getRangeAxis();
}
if (plot instanceof FastScatterPlot) {
return domain?((FastScatterPlot)plot).getDomainAxis():((FastScatterPlot)plot).getRangeAxis();
}
if (plot instanceof ContourPlot) {
return domain?((ContourPlot)plot).getDomainAxis():((ContourPlot)plot).getRangeAxis();
}
return null;
}


/**
* Pan/Shifts a plot if the arrow keys are pressed.
* @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
*/
public void keyPressed(KeyEvent e)
{
System.out.println("keyPressed");
if (!plotSupported) return;

int keyCode = e.getKeyCode();

// we're only interested in arrows (code 37,38,39,40)
if ((keyCode < 37) || (keyCode > 40)) return;

// The axis we're gonna shift
ValueAxis axis = null;

// Delta is the amount we'll shift in axis units.
double delta;

boolean domainShift = false; // used for PAN_FIXED
// Calculations for the domain axis
if ((keyCode == KeyEvent.VK_LEFT) || (keyCode == KeyEvent.VK_RIGHT))
{
axis = getPlotAxis(chartPanel.getChart(),!axesSwaped);
domainShift = true;
}
// Calculations for the range axis
else {
axis = getPlotAxis(chartPanel.getChart(),axesSwaped);
}

// Let's calculate 'delta', the amount by which we'll shift the plot
switch (shiftType) {
case SHIFT_PERCENTUAL:
delta = (axis.getUpperBound()-axis.getLowerBound())/100.0;
break;
case SHIFT_FIXED:
delta = (domainShift ? fixedDomainShiftUnits : fixedRangeShiftUnits);
break;
case SHIFT_PIXEL: // also the default
default:
// Let's find out what's the range for 1 pixel.
final Rectangle2D scaledDataArea = chartPanel.getScreenDataArea();
delta = axis.getRange().getLength() / (scaledDataArea.getWidth());
break;
}

System.out.println("key pressed delta" + delta);
// Shift modifier multiplies delta by 10
if (e.isShiftDown()) {
delta *= 10;
}

switch (keyCode) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_DOWN:
axis.setRange(axis.getLowerBound()-delta,axis.getUpperBound()-delta);
break;
case KeyEvent.VK_UP:
case KeyEvent.VK_RIGHT:
axis.setRange(axis.getLowerBound()+delta,axis.getUpperBound()+delta);
break;
}
}

/*
* @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
*/
public void keyTyped(KeyEvent e) {}
/*
* @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
*/
public void keyReleased(KeyEvent e) {}


/**
* Returns the fixed shift step for the domain axis.
* @return the fixed shift step for the domain axis.
*/
public double getFixedDomainShiftUnits() {
return fixedDomainShiftUnits;
}
/**
* Sets the fixed shift step for the domain axis.
* @param fixedDomainShiftUnits the fixed shift step for the domain axis.
*/
public void setFixedDomainShiftUnits(double fixedDomainShiftUnits) {
this.fixedDomainShiftUnits = fixedDomainShiftUnits;
}
/**
* Returns the fixed shift step for the range axis.
* @return the fixed shift step for the range axis.
*/
public double getFixedRangeShiftUnits() {
return fixedRangeShiftUnits;
}
/**
* Sets the fixed shift step for the range axis.
* @param fixedRangeShiftUnits the fixed shift step for the range axis.
*/
public void setFixedRangeShiftUnits(double fixedRangeShiftUnits) {
this.fixedRangeShiftUnits = fixedRangeShiftUnits;
}
/**
* Returns the current shift type.
* @return the current shift type.
* @see #SHIFT_FIXED
* @see #SHIFT_PERCENTUAL
* @see #SHIFT_PIXEL
*/
public int getShiftType() {
return shiftType;
}
/**
* Sets the shift type.
* @param the new shift type.
* @see #SHIFT_FIXED
* @see #SHIFT_PERCENTUAL
* @see #SHIFT_PIXEL
*/
public void setShiftType(int shiftType) {
this.shiftType = shiftType;
}
/**
* Returns whether or not the plot supports shifting.
* @return True if plot can be shifted.
*/
public boolean isPlotSupported() {
return plotSupported;
}
}

Locked