XYChart Crosshair click bug?

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
m3stevep
Posts: 13
Joined: Sun Oct 22, 2006 2:42 am
Location: UTAH, USA
Contact:

XYChart Crosshair click bug?

Post by m3stevep » Mon Oct 23, 2006 8:45 am

I'm using an XYChart with use of the crosshair functionality which matches closely to CrosshairDemo4.java. This example states that the crosshairs will lock on the nearest data point. The Crosshairs visibly migrate to a valid point, but the

double x = plot.getDomainCrosshairValue();
double y = plot.getRangeCrosshairValue();

don't update unless you double-click.

Is there a reason for this?

I am capturing this information in the chartMouseClicked(ChartMouseEvent chartMouseEvent)

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Post by david.gilbert » Mon Oct 23, 2006 4:17 pm

The reason for this is that the mouse click updates the anchor point for the crosshairs, but the crosshair values themselves are not updated until the chart has repainted. In your event handler, you'll end up reading the old crosshair values.

One way to get the revised values is to use a ChartProgressListener to get notified when the chart painting is done...see, for example, CrosshairDemo1.java.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

m3stevep
Posts: 13
Joined: Sun Oct 22, 2006 2:42 am
Location: UTAH, USA
Contact:

Post by m3stevep » Mon Oct 23, 2006 4:46 pm

Is there a way to force the crosshair value to update?

I'm plotting 2,000 points. I was using the ChartProgressListener, but it seems to bog down the CPU with this many data points.

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Post by david.gilbert » Mon Oct 23, 2006 5:00 pm

m3stevep wrote:Is there a way to force the crosshair value to update?
Unfortunately, no. The code that updates the crosshair point is entwined with the rendering code. I guess it would be possible to refactor the code to scan once through the dataset to determine the "closest" data point for the crosshairs, update to that point, then start the drawing process after that is done. Overall, it would be slower (because you end up scanning through the data twice), but the crosshair point would be updated fairly quickly (because the slowest part of chart rendering is typically the calls to the Java2D drawing code).

I don't think that's something I'd want to take on right now, though...
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

m3stevep
Posts: 13
Joined: Sun Oct 22, 2006 2:42 am
Location: UTAH, USA
Contact:

Post by m3stevep » Mon Oct 23, 2006 6:02 pm

Can I disable single click response for the crosshairs?

The crosshair values don't mean anything when the chart is single clicked ( it's all over the board ).

DarkMark
Posts: 2
Joined: Thu Jun 14, 2007 10:26 am

Post by DarkMark » Thu Jun 14, 2007 10:39 am

I had the same problem and found a workaround with a combination of ChartMouseListener and ChartProgressListener. I can't see a significant performance impact, it was slow before and still is.

Here is my code, maybe it helps:

Code: Select all

public class CrosshairListener implements ChartMouseListener,
		ChartProgressListener {

	private XYPlot currentPlot = null;

	public void chartMouseClicked(ChartMouseEvent event) {
		currentPlot = (XYPlot) event.getChart().getPlot();
		
		/* it is not possible to update the displayed data right now, due to
		 * the fact that the crosshair is not updated before the drawing
		 * process. It is therefor necessary to wait for the chart to
		 * be redrawn, see the chartProgress method */
	}

	public void chartMouseMoved(ChartMouseEvent event) {
		// no interrest in this event: no op
	}

	public void chartProgress(ChartProgressEvent event) {
		if(event.getType() != ChartProgressEvent.DRAWING_FINISHED
			|| currentPlot == null)
		{
			return;
		}
		
		if(currentPlot.equals(event.getChart().getPlot()))
		{
 			/* currentPlot.getDomainCrosshairValue() and currentPlot.getRangeCrosshairValue() now contain the correct values! */
			currentPlot = null;
		}
	}

}
The listener has to be added twice, as ChartMouseListener and as ChartProgressListener. The "currentPlot" stuff might not be necessary, I used it since I have multiple plots.

Locked