Dragging a complete series and point of series.

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
vimal
Posts: 8
Joined: Sat Jul 24, 2010 3:38 pm
antibot: No, of course not.

Dragging a complete series and point of series.

Post by vimal » Sat Sep 18, 2010 12:22 pm

Hi All,

I am using JFreeChart in my application to implement data editing using chart in an interactive way.
I am very thankful to ‘David Gilbert’ for providing such a reach charting API and JFreeChart forum ‘phpBB2’ for supporting during development.
I have implemented many prototypes for my application using JFreeChart. And here I want to share one of them. In this prototype user can drag a selected series point vertically or can drag complete series vertically by selecting any point of series.
(My requirement was vertical dragging only but in future if I found some time then I’ll try to update it for horizontal dragging also.)
This may also help to people who are looking to a ChartEntity with MouseEvent.
If you need any help related to this implementation feel free to ask me.
And of course any suggestion is also welcome for improvement point of view or for any other (better) approach which can be followed to implement same.

Happy coding!!!

Thanks & Regards,
Vimal Goyal
(NEC HCL ST, INDIA)

Code: Select all

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.labels.StandardXYSeriesLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
 * @author Vimal Goyal
 * 
 */

@SuppressWarnings("serial")
public class SeriesAndPointDragAndMove extends ApplicationFrame implements
		ChartMouseListener, MouseListener, MouseMotionListener {

	public static void main(String[] paramArrayOfString) {
		SeriesAndPointDragAndMove seriesAndPointDragAndMove = new SeriesAndPointDragAndMove(
				"Series & Point Dragging Demo");
		seriesAndPointDragAndMove.pack();
		RefineryUtilities.centerFrameOnScreen(seriesAndPointDragAndMove);
		seriesAndPointDragAndMove.setVisible(true);
	}

	boolean canMove = false;
	double finalMovePointY = 0;
	ChartRenderingInfo info = null;;
	double initialMovePointY = 0;
	JFreeChart jfreechart = null;
	ChartPanel localChartPanel = null;
	TimeSeries localTimeSeries = new TimeSeries("Series");
	TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
	XYItemEntity xyItemEntity = null;

	public SeriesAndPointDragAndMove(String paramString) {
		super(paramString);
		jfreechart = ChartFactory.createTimeSeriesChart(
				"Series & Point Dragging Demo", "Date", "Price Per Unit",
				createDataset(), true, true, false);
		localChartPanel = new ChartPanel(jfreechart);
		localChartPanel.addChartMouseListener(this);
		localChartPanel.addMouseMotionListener(this);
		localChartPanel.addMouseListener(this);
		localChartPanel.setPreferredSize(new Dimension(750, 500));
		localChartPanel.setAutoscrolls(false);
		localChartPanel.setMouseZoomable(false);
		this.info = localChartPanel.getChartRenderingInfo();
		XYPlot localXYPlot = (XYPlot) jfreechart.getPlot();
		XYItemRenderer localXYItemRenderer = localXYPlot.getRenderer();

		localXYItemRenderer.setSeriesStroke(0, new BasicStroke(2.0F));

		XYLineAndShapeRenderer localXYLineAndShapeRenderer = (XYLineAndShapeRenderer) localXYPlot
				.getRenderer();
		localXYLineAndShapeRenderer.setBaseShapesVisible(true);

		localXYLineAndShapeRenderer.setSeriesFillPaint(0, Color.white);
		localXYLineAndShapeRenderer.setUseFillPaint(true);
		localXYLineAndShapeRenderer
				.setLegendItemToolTipGenerator(new StandardXYSeriesLabelGenerator(
						"Tooltip {0}"));
		ValueAxis range = localXYPlot.getRangeAxis();
		range.setLowerBound(0); // set lower limit so that can't move in -ve
								// range
		range.setUpperBound(10000); // set upper limit as per app. needs
		setContentPane(localChartPanel);
	}

	public void chartMouseClicked(ChartMouseEvent paramChartMouseEvent) {
	}

	public void chartMouseMoved(ChartMouseEvent paramChartMouseEvent) {
	}

	public XYDataset createDataset() {
		localTimeSeries.add(new Month(1, 2002), 500.19999999999999D);
		localTimeSeries.add(new Month(2, 2002), 694.10000000000002D);
		localTimeSeries.add(new Month(3, 2002), 734.39999999999998D);
		localTimeSeries.add(new Month(4, 2002), 453.19999999999999D);
		localTimeSeries.add(new Month(5, 2002), 200.19999999999999D);
		localTimeSeries.add(new Month(6, 2002), 345.60000000000002D);
		localTimeSeries.add(new Month(7, 2002), 500.19999999999999D);
		localTimeSeries.add(new Month(8, 2002), 694.10000000000002D);
		localTimeSeries.add(new Month(9, 2002), 734.39999999999998D);
		localTimeSeries.add(new Month(10, 2002), 453.19999999999999D);
		localTimeSeries.add(new Month(11, 2002), 500.19999999999999D);
		localTimeSeries.add(new Month(12, 2002), 345.60000000000002D);
		timeseriescollection.addSeries(localTimeSeries);
		return timeseriescollection;
	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseDragged(MouseEvent e) {
		// at a time use one of them. 
		//moveTimeSeries(e); // comment or uncomment to enable or disable series
							// movement
		movePoint(e); // comment or uncomment to enable or disable selected
						// point movement
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
		canMove = false; // stop movement if cursor is moved out from the chart
							// area
		initialMovePointY = 0;
		localChartPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}

	public void mouseMoved(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
		int x = e.getX(); // initialized point whenenver mouse is pressed
		int y = e.getY();
		EntityCollection entities = this.info.getEntityCollection();
		ChartMouseEvent cme = new ChartMouseEvent(jfreechart, e, entities
				.getEntity(x, y));
		ChartEntity entity = cme.getEntity();
		if ((entity != null) && (entity instanceof XYItemEntity)) {
			xyItemEntity = (XYItemEntity) entity;
		} else if (!(entity instanceof XYItemEntity)) {
			xyItemEntity = null;
			return;
		}
		if (xyItemEntity == null) {
			return; // return if not pressed on any series point
		}
		Point pt = e.getPoint();
		XYPlot xy = jfreechart.getXYPlot();
		Rectangle2D dataArea = localChartPanel.getChartRenderingInfo()
				.getPlotInfo().getDataArea();
		Point2D p = localChartPanel.translateScreenToJava2D(pt);
		initialMovePointY = xy.getRangeAxis().java2DToValue(p.getY(), dataArea,
				xy.getRangeAxisEdge());
		canMove = true;
		localChartPanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
	}

	public void mouseReleased(MouseEvent e) {
		// stop dragging on mouse released
		canMove = false;
		initialMovePointY = 0;
		localChartPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}

	public void movePoint(MouseEvent me) {
		try {
			if (canMove) {
				int itemIndex = xyItemEntity.getItem();
				Point pt = me.getPoint();
				XYPlot xy = jfreechart.getXYPlot();
				Rectangle2D dataArea = localChartPanel.getChartRenderingInfo()
						.getPlotInfo().getDataArea();
				Point2D p = localChartPanel.translateScreenToJava2D(pt);
				finalMovePointY = xy.getRangeAxis().java2DToValue(p.getY(),
						dataArea, xy.getRangeAxisEdge());
				double difference = finalMovePointY - initialMovePointY;
				if (localTimeSeries.getValue(itemIndex).doubleValue()
						+ difference > xy.getRangeAxis().getRange().getLength()
						|| localTimeSeries.getValue(itemIndex).doubleValue()
								+ difference < 0.0D) {
					initialMovePointY = finalMovePointY;
				}
				// retrict movement for upper and lower limit (upper limit
				// should be as per application needs)
				double targetPoint = localTimeSeries.getValue(itemIndex)
						.doubleValue()
						+ difference;
				if (targetPoint > 10000 || targetPoint < 0) {
					return;
				} else
					localTimeSeries.update(itemIndex, targetPoint);

				jfreechart.fireChartChanged();
				localChartPanel.updateUI();
				initialMovePointY = finalMovePointY;
			}
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	public void moveTimeSeries(MouseEvent me) {
		try {
			if (canMove) {
				Point pt = me.getPoint();
				XYPlot xy = jfreechart.getXYPlot();
				Rectangle2D dataArea = localChartPanel.getChartRenderingInfo()
						.getPlotInfo().getDataArea();
				Point2D p = localChartPanel.translateScreenToJava2D(pt);
				finalMovePointY = xy.getRangeAxis().java2DToValue(p.getY(),
						dataArea, xy.getRangeAxisEdge());
				double difference = finalMovePointY - initialMovePointY;
				for (int i = 0; i < localTimeSeries.getItemCount(); i++) {
					if (localTimeSeries.getValue(i).doubleValue() + difference > xy
							.getRangeAxis().getRange().getLength()
							|| localTimeSeries.getValue(i).doubleValue()
									+ difference < 0.0D) {
						initialMovePointY = finalMovePointY;
					}
				}

				// retrict movement for upper and lower limit (upper limit
				// should be as per application needs)
				for (int i = 0; i < localTimeSeries.getItemCount(); i++) {
					double targetPoint = localTimeSeries.getValue(i)
							.doubleValue()
							+ difference;
					if (targetPoint > 10000 || targetPoint < 0) {
						return;
					}
				}
				for (int i = 0; i < localTimeSeries.getItemCount(); i++) {
					double targetPoint = localTimeSeries.getValue(i)
							.doubleValue()
							+ difference;
					localTimeSeries.update(i, targetPoint);
				}
				jfreechart.fireChartChanged();
				localChartPanel.updateUI();
				initialMovePointY = finalMovePointY;
			}
		} catch (Exception e) {
			System.out.println(e);
		}
	}
}

vimal
Posts: 8
Joined: Sat Jul 24, 2010 3:38 pm
antibot: No, of course not.

Re: Dragging a complete series and point of series.

Post by vimal » Sun Sep 19, 2010 2:30 pm

Found a bug.
on screen maximize window(JFrame) getting PlotEntity on series point.

ChartEntity entity = cme.getEntity(); <-- here


Any suggestion?

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Dragging a complete series and point of series.

Post by paradoxoff » Sun Sep 19, 2010 6:02 pm

vimal wrote:

Code: Select all

	public void mousePressed(MouseEvent e) {
		int x = e.getX(); // initialized point whenenver mouse is pressed
		int y = e.getY();
		EntityCollection entities = this.info.getEntityCollection();
		ChartMouseEvent cme = new ChartMouseEvent(jfreechart, e, entities
				.getEntity(x, y));
		ChartEntity entity = cme.getEntity();
		if ((entity != null) && (entity instanceof XYItemEntity)) {
			xyItemEntity = (XYItemEntity) entity;
		} else if (!(entity instanceof XYItemEntity)) {
			xyItemEntity = null;
			return;
		}
		if (xyItemEntity == null) {
			return; // return if not pressed on any series point
		}
		Point pt = e.getPoint();
		XYPlot xy = jfreechart.getXYPlot();
		Rectangle2D dataArea = localChartPanel.getChartRenderingInfo()
				.getPlotInfo().getDataArea();
		Point2D p = localChartPanel.translateScreenToJava2D(pt);
		initialMovePointY = xy.getRangeAxis().java2DToValue(p.getY(), dataArea,
				xy.getRangeAxisEdge());
		canMove = true;
		localChartPanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
	}
}
You are using coordinates which are relative to the size of the entire ChartPanel. You need to correct that by taking the insets and the zooming factor of the ChartPanel into account.
Compare for example the mouseClicked(MouseEvent me) method of ChartPanel

Code: Select all

public void mouseClicked(MouseEvent event) {
    Insets insets = getInsets();
    int x = (int) ((event.getX() - insets.left) / this.scaleX);
    int y = (int) ((event.getY() - insets.top) / this.scaleY);

    this.anchor = new Point2D.Double(x, y);
    ChartEntity entity = null;
     if (this.info != null) {
        EntityCollection entities = this.info.getEntityCollection();
        if (entities != null) {
            entity = entities.getEntity(x, y);
        }
    }
}

Locked