Has anyone done crosshairs that follow the mouse in JFreeChart? - java

We are using JFreeChart to make XY plots and we have a feature request to do a crosshair that moves along with the mouse and highlights the data point that most closely maps to the x-value of the mouse. You can see a similar example at Google Finance - http://www.google.com/finance?q=INDEXDJX:.DJI,INDEXSP:.INX,INDEXNASDAQ:.IXIC.
Those Google charts only highlight the current value (we want to do that and also show crosshairs), but they show the live mouse interaction we are looking for.
Anyone have any elegant suggestions?
Thanks.

I got this working using a mouse listener and the CrosshairOverlay class. After I get back from holiday travel, I will post my code. It ended up being not too difficult.
Sorry, I forgot about this!
First, you want to calculate the x, y values for where you want your crosshair. For me, I wanted it to move along the points of our line, so I calculated the closest x value and used that data pair for x, y.
Then I call this method:
protected void setCrosshairLocation(double x, Double y) {
Crosshair domainCrosshair;
List domainCrosshairs = crosshairOverlay.getDomainCrosshairs();
if (domainCrosshairs.isEmpty()) {
domainCrosshair = new Crosshair();
domainCrosshair.setPaint(BlueStripeColors.LIGHT_GRAY_C0);
crosshairOverlay.addDomainCrosshair(domainCrosshair);
}
else {
// We only have one at a time
domainCrosshair = (Crosshair) domainCrosshairs.get(0);
}
domainCrosshair.setValue(x);
if (y != null) {
Crosshair rangeCrosshair;
List rangeCrosshairs = crosshairOverlay.getRangeCrosshairs();
if (rangeCrosshairs.isEmpty()) {
rangeCrosshair = new Crosshair();
rangeCrosshair.setPaint(BlueStripeColors.LIGHT_GRAY_C0);
crosshairOverlay.addRangeCrosshair(rangeCrosshair);
}
else {
// We only have one at a time
rangeCrosshair = (Crosshair) rangeCrosshairs.get(0);
}
rangeCrosshair.setValue(y);
}
}
Note that crosshairOverlay is an instance of CrosshairOverlay.

JFreeChart can't render a sub-section of a chart, so you'll want to do something that doesn't require repainting the chart. You could write your chart to a BufferedImage and store that in memory, then have a custom component which uses the buffered chart as the background image, and draws crosshairs and other popup windows over it.
There are methods in JFreeChart to get the data point for a given coordinate on a rendered chart. Don't recall what these are off the top of my head. Depending on your needs, you might consider rendering your own chart data, it's not as hard as you'd think.

The first thing that comes to my mind would be to write a custom Cursor and set it on your chart. It can have a reference to the chart and highlight the x value that's consistent with the Cursor's x/y location.

This worked for me. I set the
chartPanel.addChartMouseListener(new ChartMouseListener() {
public void chartMouseMoved(ChartMouseEvent event)
{
try
{
double[] values = getCrossHairValue(event);
plot.clearRangeMarkers();
plot.clearDomainMarkers();
Marker yMarker = new ValueMarker(values[1]);
yMarker.setPaint(Color.darkGray);
plot.addRangeMarker(yMarker);
Marker xMarker = new ValueMarker(values[0]);
xMarker.setPaint(Color.darkGray);
plot.addDomainMarker(xMarker);
chartPanel.repaint();
} catch (Exception e)
{
}
}
}

Related

LibGDX — How to detect if 3d object was clicked on?

I'm trying to make a simple bit of code that will detect whether a model was clicked on. So far the best method I've seen is to create some sort of rectangle around the mesh and detect with Gdx.input.justTouched() to get the x,y coordinates, and then check if the rectangle contains the coordinates returned by justTouched().
I have no idea if there's a better way to do this, some kind of mesh onClick listener or something that LibGDX has in place that I'm unaware of (I've been scouring Google and the javadocs but I can't seem to find anything). I don't really need to deal with the z-axis coordinate, at least I don't think so. I only have the one PerspectiveCamera and it's not going to be moving around that much (not sure if this matters?)
Anyways, in my render() method I have:
if (Gdx.input.justTouched()) {
//this returns the correct values relative to the screen size
Vector2 pos = new Vector2(Gdx.input.getX(), Gdx.input.getY());
//I'm not sure how to get the correct rectangle to see what the
//width and height are for the model relative to the screen?
Rectangle modelBounds = new Rectangle(<<not sure what to put here>>);
if (modelBounds.contains(pos.x, pos.y) {
System.out.println("Model is being touched at: " + pos.x + ", " + pos.y);
}
}
I'm really not sure if this is the correct way to do this. I can get the position of the model with:
modelInstance.getNode("Node1").globalTransform.getTranslation(new Vector3());
but I'm not sure how to get the width and height as a rectangle relative to the screen size, if it's even possible.
I'm also unsure if this would cause massive lag, as I'm going to have about 7 nodes total that I need to detect if they're clicked on or not.
Is there a better way to do this? If not, is there a way to get the model width & height relative to the screensize (or camera, maybe)?
EDIT: Read about using Bounding Boxes, seems like what I need. Not quite sure how to implement it properly, however. I've changed my code to such:
public ModelInstance modelInstance;
public BoundingBox modelBounds;
#Override
public void create() {
...
//omitted irrelevant bits of code
modelInstance = new ModelInstance(heatExchangerModel);
modelBounds = modelInstance.calculateBoundingBox(new BoundingBox());
}
#Override
public void render() {
...
if (Gdx.input.justTouched()) {
Vector3 pos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
System.out.println(pos);
if (modelBounds.contains(pos)) {
System.out.println("Touching the model");
}
}
}
I'm not really sure what the output of BoundingBox is supposed to be, or how the numbers it gives me correlates to the position in a 2d space. Hmm..
EDIT2: Think I'm getting closer.. Read about Rays and the .getPickRay method for my PerspectiveCamera. .getPickRay seems to return completely unusable numbers though, like really tiny numbers. I think I need to do something like:
if (Gdx.input.justTouched()) {
Vector3 intersection = new Vector3();
Ray pickRay = perspectiveCamera.getPickRay(Gdx.input.getX(), Gdx.input.getY());
Intersector.intersectRayBounds(pickRay, modelBounds, intersection);
}
and then intersection should give me the point where they overlap. It appears to be not working, however, giving me really small numbers like (4.8066642E-5, 2.9180354E-5, 1.0) .. hmmm..

JavaFx Charts and getting values for Y Values from XYChart.Series knowing the X values

I'm attempting to replicate something I've hand crafted in the past but I'm keen to move this to JavaFX Charts so I know longer need to maintain it myself. I can get the XAxis and YAxis values from a chart relatively easily based on the location of the mouse pointer. But I now need to know what the series value (and I might have many) is. I then plan to display this in a box that floats over the charts as shown in my hand crafted chart.
I'd post an example image but sadly my reputation is currently too low.
I know I can do this by manually recording very value add to the chart in a Tree Map and then polling it as the mouse moves to determine the values... But I'm curious if there's a simpler approach that doesn't require me to repeat code from my existing non JavaFX chart.
I can't find anything in XYChart.Series or Observable List that would simplify this process so I'm just trying a sanity check before I hand crank it myself.
You can do something like this:
But your X must be a Number value
private Data<X, Y> getNearestDataForXValue(X xValue, Series<X, Y> series) {
Data<X, Y> nearsetData = null;
double distance = Double.MAX_VALUE;
for (Data<X, Y> data : series.getData()) {
double xData = data.getXValue().doubleValue();
double dataDistance = Math.abs(xValue.doubleValue() - xData);
if (dataDistance < distance) {
distance = dataDistance;
nearsetData = data;
}
}
return nearsetData;
}

Mouse position of JDialog relative to JTable

This is my code:
JTable1.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1)
{
JTable target = (JTable)e.getSource();
Point pMouse = new Point();
pMouse = target.getMousePosition();
}
}
}
So I am retrieving the point (coordinates) relative to the JTable. So let's say the user clicks somewhere in a cell and the returned Point is X=272 and Y=50. So now I want to position a JDialog exactly by those coordinates. I tried:
jDialog1.setLocation(pMouse);
jDialog1.setVisible(true);
But this positions the Dialog somewhere else (the coordinates of the screen instead of the Table). Does somebody have a suggestion on how I can position the JDialog relative to the cell?
You are using the co-ordinates in relation to the client area of the JTable content. You want the global co-ordinates in relation to the entire window. For this you can use:
Point location = MouseInfo.getPointerInfo().getLocation();
jDialog1.setLocation(location);
In general, a user should be able to use your application either by mouse or keyboard. What happens if the user tabs to that cell? Should they not be able to see the same dialog? So for a more general solution that works whether you use a mouse or not:
SwingUtilities.convertPointToScreen(point, table);
Check out the other convertXXX methods in SwingUtilities for future reference.
Or, you can always use:
Component.getLocationOnScreen();
and then add on the mouse point.

Java Application : mouseDragged Event isn't Executed Often Enough

Is there a way to make the mouseDragged Event be called more Often ( In my Case, Drawing a Color? I need it for Smooth Drawing, because right now, if you move too fast, it doesn't Draw All my Path. Also, I have an 2D Array Storing the Color of the Pixel, so that's also Problematic if I try to solve by problem by another Way, that's why I thought Increasing the mouseDragged Frequency would be the Best thing to Do
Thanks
If you want smooth drawing, you'd likely have to interpolate the data yourself. If you get an event at (3,3) and another at (10,10) you can figure the slope between the two, and iterate through the logical points that the mouse must have been dragged to get from (3,3) to (10,10)
I don't know of a way to force mouseDragged to update faster, and if, for instance the system was under high load, or someone used a touch screen, you might get huge jumps anyhow.
If you are drawing ovals to as color lines, change to lines:
ArrayList<> colors;
mousepressed(Event e) {
startPoint = e.getPoint();
}
mousedragged(Event e) {
colors.add(new Color(startPoint, e.getPoint);
startPoint = e.getPoint();
}
class Color() {
Color(Point start, Point end) {
// ...
}
paint(Graphics g) {
g.drawLine(start, end);
}
}

Java: Really simple scatter plot utility

I know there are many comparisons of java plotting libraries out there, but I'm not finding what I need. I just want a mind-numbingly simple toolkit that creates images of scatterplots from a set of coordinates. No GUI, no interaction, no fancy display, just a basic XY coordinate system with points.
It wouldn't be the end of the world to use something that offers a lot more functionality than I need, but I'd rather not. Do you know of anything like what I'm looking for?
Have you looked at JFreeChart? While it can do some very advanced things, it also does the simple as well. Shown below is a screenshot of its scatter plot capability.
(source: jfree.org)
I looked around at what existed, and realized that jcckit is technically pretty good, but just lacks a simple wrapper around it to make it easy to use.
So I forked it and made a really simple wrapper. Here's how to use:
import static easyjcckit.QuickPlot.*;
double[] xaxis = new double[]{0,1,2,3,4,5};
double[] yvalues = new double[]{0,1,4,9,16,25};
scatter( xaxis, yvalues ); // create a plot using xaxis and yvalues
double[] yvalues2 = new double[]{0,1,2,3,4,5};
addScatter( xaxis, yvalues2 ); // create a second plot on top of first
System.out.println("Press enter to exit");
System.in.read();
As well as scatter plots, you can freely add lines to the same axes if you wish using 'addPlot' and 'plot'.
Here is the code: https://bitbucket.org/hughperkins/easyjcckit
You an use a custom JPanel to draw your data(not tested, but you get the idea...)
private List<Point2D> data=(...);
JPanel pane=new JPanel()
{
protected paintComponent(Graphics2D g)
{
super.paintComponent(g);
int minx=(...),miny=(...),maxx=(...),maxy=(...);
for(Point2D p: data)
{
int x=((p.getX()-minx)/(maxx-minx))*this.getWidth();
int y=((p.getY()-miny)/(maxy-miny))*this.getHeight();
g.drawLine(x-5,y,x+5,y);
g.drawLine(x,y-5,x,y+5);
}
}
pane.setOpaque(true);
(...)
anotherComponent.add(pane);
(...)
}
Also you could check Simple Java Plot. Minimal example (no options):
Plot plot = Plot.plot(null).
// setting data
series(null, Plot.data().
xy(1, 2).
xy(3, 4), null);
// saving sample_minimal.png
plot.save("sample_minimal", "png");

Categories