JFreeChart:使用ChartMouseListener和鼠标移动在ChartPanel中进行动态点选择

时间:2014-06-12 15:22:05

标签: java jfreechart

我有一个使用JFreeChart的图表,点击后将标记放在相关位置(见下图)。

我需要的是不是在点击之后改变位置,而是在鼠标移动时改变位置。

我知道使用模块ChartMouseListener我可以扩展它的功能。

    ChartMouseListener l = new ChartMouseListener() {
        @Override
        public void chartMouseMoved(ChartMouseEvent e) {
            int newX = e.getTrigger().getX();
            int newY = e.getTrigger().getY();
            System.out.println("chartMouseMoved to " + newX + " " + newY);
        }
        @Override
        public void chartMouseClicked(ChartMouseEvent e) {
        }
    };
    chartPanel.addChartMouseListener(l);

如何在图表中设置选定的轴?

JFreeChart withd aditional axis

    package org.jfree.chart.demo;

    import java.awt.Color;
    import java.text.SimpleDateFormat;

    import javax.swing.JPanel;

    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartMouseEvent;
    import org.jfree.chart.ChartMouseListener;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.StandardChartTheme;
    import org.jfree.chart.axis.DateAxis;
    import org.jfree.chart.entity.XYItemEntity;
    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.RectangleInsets;
    import org.jfree.ui.RefineryUtilities;

    /**
     * An example of a time series chart. For the most part, default settings are
     * used, except that the renderer is modified to show filled shapes (as well as
     * lines) at each data point.
     */
    public class TimeSeriesChartDemo1 extends ApplicationFrame {

        private static final long serialVersionUID = 1L;

        {
            // set a theme using the new shadow generator feature available in
            // 1.0.14 - for backwards compatibility it is not enabled by default
            ChartFactory
                    .setChartTheme(new StandardChartTheme("JFree/Shadow", true));
        }

        /**
         * A demonstration application showing how to create a simple time series
         * chart. This example uses monthly data.
         * 
         * @param title
         *            the frame title.
         */
        public TimeSeriesChartDemo1(String title) {
            super(title);
            ChartPanel chartPanel = (ChartPanel) createDemoPanel();
            chartPanel.setPreferredSize(new java.awt.Dimension(800, 600));
            setContentPane(chartPanel);
            ChartMouseListener l = new ChartMouseListener() {
                @Override
                public void chartMouseMoved(ChartMouseEvent e) {
                    int newX = e.getTrigger().getX();
                    int newY = e.getTrigger().getY();
                    System.out.println("chartMouseMoved to " + newX + " " + newY);
                }
                @Override
                public void chartMouseClicked(ChartMouseEvent e) {
                }
            };
            System.out.println(chartPanel.getMouseListeners()[0]);
            chartPanel.addChartMouseListener(l);
        }

        /**
         * Creates a chart.
         * 
         * @param dataset
         *            a dataset.
         * 
         * @return A chart.
         */
        private static JFreeChart createChart(XYDataset dataset) {

            JFreeChart chart = ChartFactory.createTimeSeriesChart(
                    "Legal & General Unit Trust Prices", // title
                    "Date", // x-axis label
                    "Price Per Unit", // y-axis label
                    dataset, // data
                    true, // create legend?
                    true, // generate tooltips?
                    true // generate URLs?
                    );

            chart.setBackgroundPaint(Color.white);

            XYPlot plot = (XYPlot) chart.getPlot();
            plot.setBackgroundPaint(Color.lightGray);
            plot.setDomainGridlinePaint(Color.white);
            plot.setRangeGridlinePaint(Color.white);
            plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
            plot.setDomainCrosshairVisible(true);
            plot.setRangeCrosshairVisible(true);

            XYItemRenderer r = plot.getRenderer();
            if (r instanceof XYLineAndShapeRenderer) {
                XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
                renderer.setBaseShapesVisible(true);
                renderer.setBaseShapesFilled(true);
                renderer.setDrawSeriesLineAsPath(true);
            }

            DateAxis axis = (DateAxis) plot.getDomainAxis();
            axis.setDateFormatOverride(new SimpleDateFormat("MMM-yyyy"));

            return chart;

        }

        /**
         * Creates a dataset, consisting of two series of monthly data.
         * 
         * @return The dataset.
         */
        private static XYDataset createDataset() {

            TimeSeries s1 = new TimeSeries("L&G European Index Trust");
            s1.add(new Month(2, 1), .8);
            s1.add(new Month(3, 1), .3);
            s1.add(new Month(4, 1), .8);
            s1.add(new Month(5, 1), .6);
            s1.add(new Month(6, 1), .8);
            s1.add(new Month(7, 1), .3);
            s1.add(new Month(8, 1), .9);
            s1.add(new Month(9, 1), .7);
            s1.add(new Month(10, 1), .2);
            s1.add(new Month(11, 1), .8);
            s1.add(new Month(12, 1), .6);
            s1.add(new Month(1, 2), .9);
            s1.add(new Month(2, 2), .7);
            s1.add(new Month(3, 2), .3);
            s1.add(new Month(4, 2), .9);
            s1.add(new Month(5, 2), .8);
            s1.add(new Month(6, 2), .0);
            s1.add(new Month(7, 2), .8);

            TimeSeries s2 = new TimeSeries("L&G UK Index Trust");
            s2.add(new Month(2, 1), .6);
            s2.add(new Month(3, 1), .2);
            s2.add(new Month(4, 1), .2);
            s2.add(new Month(5, 1), .1);
            s2.add(new Month(6, 1), .6);
            s2.add(new Month(7, 1), .2);
            s2.add(new Month(8, 1), .5);
            s2.add(new Month(9, 1), .7);
            s2.add(new Month(10, 1), .5);
            s2.add(new Month(11, 1), .1);
            s2.add(new Month(12, 1), .3);
            s2.add(new Month(1, 2), .7);
            s2.add(new Month(2, 2), .0);
            s2.add(new Month(3, 2), .6);
            s2.add(new Month(4, 2), .2);
            s2.add(new Month(5, 2), .6);
            s2.add(new Month(6, 2), .8);
            s2.add(new Month(7, 2), .6);

            // ******************************************************************
            // More than demo applications are included with the JFreeChart
            // Developer Guide...for more information, see:
            //
            // > http://www.object-refinery.com/jfreechart/guide.html
            //
            // ******************************************************************

            TimeSeriesCollection dataset = new TimeSeriesCollection();
            dataset.addSeries(s1);
            dataset.addSeries(s2);

            return dataset;

        }

        /**
         * Creates a panel for the demo (used by SuperDemo.java).
         * 
         * @return A panel.
         */
        public static JPanel createDemoPanel() {
            JFreeChart chart = createChart(createDataset());
            ChartPanel panel = new ChartPanel(chart);
            panel.setFillZoomRectangle(true);
            panel.setMouseWheelEnabled(true);
            return panel;
        }

        /**
         * Starting point for the demonstration application.
         * 
         * @param args
         *            ignored.
         */
        public static void main(String[] args) {

            TimeSeriesChartDemo1 demo = new TimeSeriesChartDemo1(
                    "Time Series Chart Demo 1");
            demo.pack();
            RefineryUtilities.centerFrameOnScreen(demo);
            demo.setVisible(true);

        }

    }

1 个答案:

答案 0 :(得分:4)

有几种方法可以在JFreeChart中绘制十字准线。对于您给出的示例,十字准线被绘制为图表的一部分,因此每次十字准线的位置发生变化时,需要重新绘制图表。在鼠标移动事件上执行此操作并不会非常有效。

另一种方法是使用CrosshairOverlay类。这会将十字准线绘制为现有图表上的叠加层,从而避免在十字准线值更改时重绘图表的需要。对于你想做的事情,这将更好地发挥作用。

JFreeChart开发者指南中包含了这个功能的几个例子(我们鼓励JFreeChart用户购买,因此他们可以在财务上帮助JFreeChart项目 - 只有很小的比例,但是那个人类性质)。

以下是其中一个例子:

/* --------------------------
 * CrosshairOverlayDemo1.java
 * --------------------------
 * (C) Copyright 2003-2014, by Object Refinery Limited.
 *
 */

package demo;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;

/**
 * A demo showing crosshairs that follow the data points on an XYPlot.
 */
public class CrosshairOverlayDemo1 extends JFrame {

    static class MyDemoPanel extends JPanel implements ChartMouseListener {

        private ChartPanel chartPanel;

        private Crosshair xCrosshair;

        private Crosshair yCrosshair;

        public MyDemoPanel() {
            super(new BorderLayout());
            JFreeChart chart = createChart(createDataset());
            this.chartPanel = new ChartPanel(chart);
            this.chartPanel.addChartMouseListener(this);
            CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
            this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, 
                    new BasicStroke(0f));
            this.xCrosshair.setLabelVisible(true);
            this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, 
                    new BasicStroke(0f));
            this.yCrosshair.setLabelVisible(true);
            crosshairOverlay.addDomainCrosshair(xCrosshair);
            crosshairOverlay.addRangeCrosshair(yCrosshair);
            this.chartPanel.addOverlay(crosshairOverlay);
            add(this.chartPanel);
        }

        private JFreeChart createChart(XYDataset dataset) {
            JFreeChart chart = ChartFactory.createXYLineChart(
                    "CrosshairOverlayDemo1", "X", "Y", dataset);
            return chart;
        }

        private XYDataset createDataset() {
            XYSeries series = new XYSeries("S1");
            for (int x = 0; x < 10; x++) {
                series.add(x, x + Math.random() * 4.0);
            }
            XYSeriesCollection dataset = new XYSeriesCollection(series);
            return dataset;
        }

        @Override
        public void chartMouseClicked(ChartMouseEvent event) {
            // ignore
        }

        @Override
        public void chartMouseMoved(ChartMouseEvent event) {
            Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
            JFreeChart chart = event.getChart();
            XYPlot plot = (XYPlot) chart.getPlot();
            ValueAxis xAxis = plot.getDomainAxis();
            double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea, 
                    RectangleEdge.BOTTOM);
            // make the crosshairs disappear if the mouse is out of range
            if (!xAxis.getRange().contains(x)) { 
                x = Double.NaN;                  
            }
            double y = DatasetUtilities.findYValue(plot.getDataset(), 0, x);
            this.xCrosshair.setValue(x);
            this.yCrosshair.setValue(y);
        }  

    }

    public CrosshairOverlayDemo1(String title) {
        super(title);
        setContentPane(createDemoPanel());
    }

    /**
     * Creates a panel for the demo (used by SuperDemo.java).
     *
     * @return A panel.
     */
    public static JPanel createDemoPanel() {
        return new MyDemoPanel();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                CrosshairOverlayDemo1 app = new CrosshairOverlayDemo1(
                        "JFreeChart: CrosshairOverlayDemo1.java");
                app.pack();
                app.setVisible(true);
            }
        });
    }

}