I know there could be a delay if the chart has not been updated but the value is always 0.0.
Now this is just a test piece of code that I will take concepts going forward with. Its a collection of stuff that I've found and stuff I've added.
The data is rendered to a XYItemRenderer using XY points, placing shapes at those points on a chart. Ultimately, what I want to do is that when
the mouseclicked event occurs I want to display on the chart at that location the XY values (start or end point) and indicate its matched pair (either start or end point). There will be a unique symbol (shape) that will identify (on the legend) whether it is a stop or end point. I've copied the entire code so you
could quickly ingest into Eclipse or Netbeans and see the results.
Thanks
Fred
Code: Select all
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.GridArrangement;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.CrosshairState;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRendererState;
import org.jfree.ui.RectangleEdge;
import org.jfree.util.ShapeUtilities;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.chart.title.LegendTitle;
public class MultipleShapesDemo extends JFrame implements ChartMouseListener{
/**
*
*/
private static final long serialVersionUID = 1L;
public MultipleShapesDemo(String s) {
super(s);
//final ChartPanel chartPanel = createGraphPanel();
JFrame frame = new JFrame(s);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
double[] xValues = {1, 2, 3, 4, 5, 6, 7, 8};
double[] yValues = {20, 1, 18, 8, 11, 17, 14, 17};
double[] zValues = {0, 1, 2, 3, 4, 5, 6, 7};
DefaultXYZDataset dataset = new DefaultXYZDataset();
double[][] data = new double[3][];
data[0] = xValues;
data[1] = yValues;
data[2] = zValues;
dataset.addSeries("Series 1", data);
XYItemRenderer r = (XYItemRenderer) new XYZShapeRenderer();
NumberAxis xAxis = new NumberAxis("x");
NumberAxis yAxis = new NumberAxis("y");
final XYPlot plot = new XYPlot(dataset, xAxis, yAxis, r);
plot.setDomainCrosshairVisible(true);
plot.setDomainCrosshairLockedOnData(true);
plot.setRangeCrosshairVisible(true);
plot.setRangeCrosshairLockedOnData(true);
NumberAxis domain = (NumberAxis) plot.getDomainAxis();
domain.setRange(0.0, 10.0);
domain.setTickUnit(new NumberTickUnit(0.5));
//domain.setVerticalTickLabels(true);
NumberAxis range = (NumberAxis) plot.getRangeAxis();
range.setRange(0.0, 25.0);
range.setTickUnit(new NumberTickUnit(2.0));
final JFreeChart chart = new JFreeChart(s, new Font("Tahoma",0,18), plot, false);
LegendTitle legendTitle = new LegendTitle(plot, new GridArrangement(4, 2), new GridArrangement(4, 2));
legendTitle.setPosition(RectangleEdge.BOTTOM);
chart.addLegend(legendTitle);
final ChartPanel chartPanel = new ChartPanel(chart);
this.add(chartPanel, BorderLayout.CENTER);
// add click event
chartPanel.addChartMouseListener(new ChartMouseListener() {
@Override
public void chartMouseClicked(ChartMouseEvent e) {
System.out.println("Click event!");
XYPlot xyPlot3 = chart.getXYPlot();
System.out.println(xyPlot3.getDomainCrosshairValue() + " " +
xyPlot3.getRangeCrosshairValue());
XYPlot xyPlot2 = chartPanel.getChart().getXYPlot();
// Problem: the coordinates displayed are the one of the previously selected point !
System.out.println(xyPlot2.getDomainCrosshairValue() + " "
+ xyPlot2.getRangeCrosshairValue());
}
@Override
public void chartMouseMoved(ChartMouseEvent e) {
System.out.println("Mouse Moved Event!");
}
});
//frame.setContentPane(new ChartPanel(chart));
//frame.pack();
//frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
MultipleShapesDemo newChart = new MultipleShapesDemo("ChartMouseListener test");
newChart.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
newChart.pack();
newChart.setLocationRelativeTo(null);
newChart.setVisible(true);
//frame.setContentPane(new ChartPanel(newChart));
}
});
}
static class XYZShapeRenderer extends AbstractXYItemRenderer{
/**
*
*/
private static final long serialVersionUID = 1L;
Shape [] shapes = createStandardSeriesShapes();
public void drawItem(Graphics2D g2, XYItemRendererState state,
Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot,
ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
int series, int item, CrosshairState crosshairState, int pass) {
Color[] sColors = {Color.blue,Color.green,Color.red,Color.black,Color.orange};
Shape hotspot = null;
EntityCollection entities = null;
if (info != null) {
entities = info.getOwner().getEntityCollection();
}
double x = dataset.getXValue(series, item);
double y = dataset.getYValue(series, item);
//System.out.println("series="+series+" item="+item);
if (Double.isNaN(x) || Double.isNaN(y)) {
// can't draw anything
return;
}
double transX = domainAxis.valueToJava2D(x, dataArea,
plot.getDomainAxisEdge());
double transY = rangeAxis.valueToJava2D(y, dataArea,
plot.getRangeAxisEdge());
PlotOrientation orientation = plot.getOrientation();
boolean useDefaultShape = true;
Shape shape = null;
Color color = Color.cyan;
if(dataset instanceof XYZDataset){
XYZDataset xyz = (XYZDataset)dataset;
double z = xyz.getZValue(series, item);
if(z == 0){
shape = shapes[7];
color = sColors[0];
useDefaultShape = false;
}
if(z == 1){
shape = shapes[1];
color = sColors[1];
useDefaultShape = false;
}
if(z == 2){
shape = shapes[2];
color = sColors[2];
useDefaultShape = false;
}
if(z == 3){
shape = shapes[3];
color = sColors[3];
useDefaultShape = false;
}
if(z == 4){
shape = shapes[4];
color = sColors[4];
useDefaultShape = false;
}
if(z == 5){
shape = shapes[5];
color = sColors[0];
useDefaultShape = false;
}
if(z == 6){
shape = shapes[6];
color = sColors[1];
useDefaultShape = false;
}
}
if(useDefaultShape){
shape = getItemShape(series, item);
}
if (orientation == PlotOrientation.HORIZONTAL) {
shape = ShapeUtilities.createTranslatedShape(shape, transY,
transX);
}
else if (orientation == PlotOrientation.VERTICAL) {
shape = ShapeUtilities.createTranslatedShape(shape, transX,
transY);
}
hotspot = shape;
if (shape.intersects(dataArea)) {
//if (getItemShapeFilled(series, item)) {
g2.setPaint(lookupSeriesPaint(series));
g2.fill(shape);
//}
g2.setPaint(getItemOutlinePaint(series, item));
g2.setStroke(getItemOutlineStroke(series, item));
g2.draw(shape);
}
// add an entity for the item...
if (entities != null) {
LegendItemCollection oldLegend = plot.getLegendItems();
//System.out.println("color="+color);
plot.getRenderer().setSeriesPaint(0, color);
LegendItem legenditem0 = new LegendItem("", "-", "place holder"+series, null, shapes[0], Color.white);
LegendItem legenditem1 = new LegendItem("Start", "-", "start point series="+series, null, shapes[7], color);
LegendItem legenditem2 = new LegendItem("Stop", "-", "end point series="+series, null, shapes[3], color);
LegendItem legenditem3 = new LegendItem("Start", "-", "start point series="+series, null, shapes[0], Color.red);
LegendItem legenditem4 = new LegendItem("Stop", "-", "end point series="+series, null, shapes[4], Color.red);
boolean check4Legend = IsLegendDefined(oldLegend,legenditem1);
if (!check4Legend){
System.out.println("legenditem1..NOT found..");
oldLegend.add(legenditem0);
oldLegend.add(legenditem1);
oldLegend.add(legenditem2);
oldLegend.add(legenditem3);
oldLegend.add(legenditem4);
plot.setFixedLegendItems(oldLegend);
}
addEntity(entities, hotspot, dataset, series, item, transX,transY);
}
}
}
private static boolean IsLegendDefined(LegendItemCollection oldLegend, LegendItem newLegend){
boolean rtnVal = false;
int oldLegendCnt = oldLegend.getItemCount();
String newTT = newLegend.getToolTipText();
//System.out.println("legendCount="+oldLegendCnt);
for (int j = 0; j < oldLegendCnt; j++) {
LegendItem testLI = oldLegend.get(j);
String oldTT = testLI.getToolTipText();
//System.out.println("oldTT="+oldTT);
//System.out.println("newTT="+newTT);
if (oldTT == null){
continue;
} else if (oldTT.compareTo(newTT) == 0){
rtnVal = true;
//System.out.println("exiting loop...");
break;
}
}
return rtnVal;
}
/**
* Creates an array of standard shapes to display for the items in series
* on charts.
*
* @return The array of shapes.
*/
public static Shape[] createStandardSeriesShapes() {
Shape[] result = new Shape[10];
double size = 6.0;
double delta = size / 2.0;
int[] xpoints = null;
int[] ypoints = null;
// square
result[0] = new Rectangle2D.Double(-delta, -delta, size, size);
// circle
result[1] = new Ellipse2D.Double(-delta, -delta, size, size);
// up-pointing triangle
xpoints = intArray(0.0, delta, -delta);
ypoints = intArray(-delta, delta, delta);
result[2] = new Polygon(xpoints, ypoints, 3);
// diamond
xpoints = intArray(0.0, delta, 0.0, -delta);
ypoints = intArray(-delta, 0.0, delta, 0.0);
result[3] = new Polygon(xpoints, ypoints, 4);
// horizontal rectangle
result[4] = new Rectangle2D.Double(-delta, -delta / 2, size, size / 2);
// down-pointing triangle
xpoints = intArray(-delta, +delta, 0.0);
ypoints = intArray(-delta, -delta, delta);
result[5] = new Polygon(xpoints, ypoints, 3);
// horizontal ellipse
result[6] = new Ellipse2D.Double(-delta, -delta / 2, size, size / 2);
// right-pointing triangle
xpoints = intArray(-delta, delta, -delta);
ypoints = intArray(-delta, 0.0, delta);
result[7] = new Polygon(xpoints, ypoints, 3);
// vertical rectangle
result[8] = new Rectangle2D.Double(-delta / 2, -delta, size / 2, size);
// left-pointing triangle
xpoints = intArray(-delta, delta, delta);
ypoints = intArray(0.0, -delta, +delta);
result[9] = new Polygon(xpoints, ypoints, 3);
return result;
}
/**
* Helper method to avoid lots of explicit casts in getShape(). Returns
* an array containing the provided doubles cast to ints.
*
* @param a x
* @param b y
* @param c z
*
* @return int[3] with converted params.
*/
private static int[] intArray(double a, double b, double c) {
return new int[] {(int) a, (int) b, (int) c};
}
/**
* Helper method to avoid lots of explicit casts in getShape(). Returns
* an array containing the provided doubles cast to ints.
*
* @param a x
* @param b y
* @param c z
* @param d t
*
* @return int[4] with converted params.
*/
private static int[] intArray(double a, double b, double c, double d) {
return new int[] {(int) a, (int) b, (int) c, (int) d};
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
// Mouse events defined within the MultipleShapesDemo Constructor
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
// Mouse events defined within the MultipleShapesDemo Constructor
}
}