From 4912f9621adeeef08dbdf726b30ed0eee0c08dc8 Mon Sep 17 00:00:00 2001 From: akardapolov Date: Tue, 11 Mar 2014 11:41:05 +0600 Subject: [PATCH] New rectangular region selection handler and demo. --- .../chart/demo/selection/SelectionDemo8.java | 239 ++++++++++++++++++ ...ctangularHeightRegionSelectionHandler.java | 210 +++++++++++++++ 2 files changed, 449 insertions(+) create mode 100644 src/main/java/org/jfree/chart/demo/selection/SelectionDemo8.java create mode 100644 src/main/java/org/jfree/chart/panel/selectionhandler/RectangularHeightRegionSelectionHandler.java diff --git a/src/main/java/org/jfree/chart/demo/selection/SelectionDemo8.java b/src/main/java/org/jfree/chart/demo/selection/SelectionDemo8.java new file mode 100644 index 00000000..41d48709 --- /dev/null +++ b/src/main/java/org/jfree/chart/demo/selection/SelectionDemo8.java @@ -0,0 +1,239 @@ +/* ------------------- + * SelectionDemo1.java + * ------------------- + * (C) Copyright 2009-2013, by Object Refinery Limited. + * + */ + +package org.jfree.chart.demo.selection; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.panel.selectionhandler.*; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.item.IRSUtilities; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.chart.ui.ApplicationFrame; +import org.jfree.chart.ui.NumberCellRenderer; +import org.jfree.chart.ui.RefineryUtilities; +import org.jfree.data.extension.DatasetIterator; +import org.jfree.data.extension.DatasetSelectionExtension; +import org.jfree.data.extension.impl.DatasetExtensionManager; +import org.jfree.data.extension.impl.XYCursor; +import org.jfree.data.extension.impl.XYDatasetSelectionExtension; +import org.jfree.data.general.Dataset; +import org.jfree.data.general.SelectionChangeEvent; +import org.jfree.data.general.SelectionChangeListener; +import org.jfree.data.time.Month; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.xy.XYDataset; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; +import java.awt.*; + +public class SelectionDemo8 extends ApplicationFrame implements + SelectionChangeListener { + + private JTable table; + + private DefaultTableModel model; + + private TimeSeriesCollection dataset; + + /** + * A demonstration application showing how to create a simple time series + * chart. This example uses monthly data. + * + * @param title the frame title. + */ + public SelectionDemo8(String title) { + super(title); + ChartPanel chartPanel = (ChartPanel) createDemoPanel(); + chartPanel.setPreferredSize(new java.awt.Dimension(500, 270)); + chartPanel.setRangeZoomable(false); + + JFreeChart chart = chartPanel.getChart(); + XYPlot plot = (XYPlot) chart.getPlot(); + this.dataset = (TimeSeriesCollection) plot.getDataset(); + JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + split.add(chartPanel); + + this.model = new DefaultTableModel(new String[] { "Series:", "Item:", + "Period:", "Value:" }, 0); + this.table = new JTable(this.model); + TableColumnModel tcm = this.table.getColumnModel(); + tcm.getColumn(3).setCellRenderer(new NumberCellRenderer()); + JPanel p = new JPanel(new BorderLayout()); + JScrollPane scroller = new JScrollPane(this.table); + p.add(scroller); + p.setBorder(BorderFactory.createCompoundBorder(new TitledBorder( + "Selected Items: "), new EmptyBorder(4, 4, 4, 4))); + split.add(p); + setContentPane(split); + + } + + /** + * The selection changed, so we change the table model + * + * @param event + */ + public void selectionChanged(SelectionChangeEvent event) { + while (this.model.getRowCount() > 0) { + this.model.removeRow(0); + } + + XYDatasetSelectionExtension ext = (XYDatasetSelectionExtension) + event.getSelectionExtension(); + DatasetIterator iter = ext.getSelectionIterator(true); + + while (iter.hasNext()) { + XYCursor dc = iter.next(); + Comparable seriesKey = this.dataset.getSeriesKey(dc.series); + RegularTimePeriod p = this.dataset.getSeries(dc.series) + .getTimePeriod(dc.item); + Number value = this.dataset.getY(dc.series, dc.item); + + this.model.addRow(new Object[] { seriesKey, new Integer(dc.item), + p, value}); + } + } + + /** + * Creates a chart. + * + * @param dataset a dataset. + * + * @return A chart. + */ + private static JFreeChart createChart(XYDataset dataset, + DatasetSelectionExtension ext) { + + JFreeChart chart = ChartFactory.createTimeSeriesChart("Stock Prices", + "Date", "Price Per Unit", dataset); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setDomainPannable(true); + plot.setRangePannable(true); + plot.setDomainCrosshairVisible(true); + plot.setRangeCrosshairVisible(true); + + XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer(); + r.setBaseShapesVisible(true); + r.setBaseShapesFilled(true); + r.setUseFillPaint(true); + r.setSeriesFillPaint(0, r.lookupSeriesPaint(0)); + r.setSeriesFillPaint(1, r.lookupSeriesPaint(1)); + + r.setDrawOutlines(true); + + //add selection specific rendering + IRSUtilities.setSelectedItemFillPaint(r, ext, Color.white); + + //register plot as selection change listener + ext.addChangeListener(plot); + + return chart; + } + + /** + * Creates a dataset, consisting of two series of monthly data. + * + * @return The dataset. + */ + private static TimeSeriesCollection createDataset() { + + TimeSeries s1 = new TimeSeries("S1"); + s1.add(new Month(1, 2009), 181.8); + s1.add(new Month(2, 2009), 167.3); + s1.add(new Month(3, 2009), 153.8); + s1.add(new Month(4, 2009), 167.6); + s1.add(new Month(5, 2009), 158.8); + s1.add(new Month(6, 2009), 148.3); + s1.add(new Month(7, 2009), 153.9); + s1.add(new Month(8, 2009), 142.7); + s1.add(new Month(9, 2009), 123.2); + s1.add(new Month(10, 2009), 131.8); + s1.add(new Month(11, 2009), 139.6); + s1.add(new Month(12, 2009), 142.9); + s1.add(new Month(1, 2010), 138.7); + s1.add(new Month(2, 2010), 137.3); + s1.add(new Month(3, 2010), 143.9); + s1.add(new Month(4, 2010), 139.8); + s1.add(new Month(5, 2010), 137.0); + s1.add(new Month(6, 2010), 132.8); + + TimeSeries s2 = new TimeSeries("S2"); + s2.add(new Month(1, 2009), 129.6); + s2.add(new Month(2, 2009), 123.2); + s2.add(new Month(3, 2009), 117.2); + s2.add(new Month(4, 2009), 124.1); + s2.add(new Month(5, 2009), 122.6); + s2.add(new Month(6, 2009), 119.2); + s2.add(new Month(7, 2009), 116.5); + s2.add(new Month(8, 2009), 112.7); + s2.add(new Month(9, 2009), 101.5); + s2.add(new Month(10, 2009), 106.1); + s2.add(new Month(11, 2009), 110.3); + s2.add(new Month(12, 2009), 111.7); + s2.add(new Month(1, 2010), 111.0); + s2.add(new Month(2, 2010), 109.6); + s2.add(new Month(3, 2010), 113.2); + s2.add(new Month(4, 2010), 111.6); + s2.add(new Month(5, 2010), 108.8); + s2.add(new Month(6, 2010), 101.6); + + TimeSeriesCollection dataset = new TimeSeriesCollection(); + dataset.addSeries(s1); + dataset.addSeries(s2); + + return dataset; + } + + public final JPanel createDemoPanel() { + XYDataset xydataset = createDataset(); + //extend dataset and add selection change listener for the demo + DatasetSelectionExtension datasetExtension + = new XYDatasetSelectionExtension(xydataset); + datasetExtension.addChangeListener(this); + + //standard setup + JFreeChart chart = createChart(xydataset, datasetExtension); + ChartPanel panel = new ChartPanel(chart); + panel.setMouseWheelEnabled(true); + + // add a selection handler + RegionSelectionHandler selectionHandler = new RectangularHeightRegionSelectionHandler(); + panel.addMouseHandler(selectionHandler); + panel.addMouseHandler(new MouseClickSelectionHandler()); + panel.removeMouseHandler(panel.getZoomHandler()); + + // add a selection manager + DatasetExtensionManager dExManager = new DatasetExtensionManager(); + dExManager.registerDatasetExtension(datasetExtension); + panel.setSelectionManager(new EntitySelectionManager(panel, + new Dataset[] { xydataset }, dExManager)); + + return panel; + } + + /** + * Starting point for the demonstration application. + * + * @param args ignored. + */ + public static void main(String[] args) { + SelectionDemo8 demo = new SelectionDemo8("JFreeChart: SelectionDemo8"); + demo.pack(); + RefineryUtilities.centerFrameOnScreen(demo); + demo.setVisible(true); + } + +} diff --git a/src/main/java/org/jfree/chart/panel/selectionhandler/RectangularHeightRegionSelectionHandler.java b/src/main/java/org/jfree/chart/panel/selectionhandler/RectangularHeightRegionSelectionHandler.java new file mode 100644 index 00000000..f344ae6c --- /dev/null +++ b/src/main/java/org/jfree/chart/panel/selectionhandler/RectangularHeightRegionSelectionHandler.java @@ -0,0 +1,210 @@ +/* =========================================================== + * JFreeChart : a free chart library for the Java(tm) platform + * =========================================================== + * + * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors. + * + * Project Info: http://www.jfree.org/jfreechart/index.html + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * -------------------------------------- + * RectangularRegionSelectionHandler.java + * -------------------------------------- + * (C) Copyright 2009-2013, by Object Refinery Limited and Contributors. + * + * Original Author: David Gilbert (for Object Refinery Limited); + * Contributor(s): Michael Zinsmaier; + * + * Changes: + * -------- + * 19-Jun-2009 : Version 1 (DG); + * + */ + +package org.jfree.chart.panel.selectionhandler; + +import org.jfree.chart.ChartPanel; +import org.jfree.chart.util.ShapeUtilities; + +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * A mouse handler that allows data items to be selected. The selection shape + * is a rectangle that can be expanded by dragging the mouse away from the starting + * point. + * + * Will only work together with a ChartPanel as event source + * @author zinsmaie + */ +public class RectangularHeightRegionSelectionHandler extends RegionSelectionHandler { + + /** a generated serial id. */ + private static final long serialVersionUID = -8496935828054326324L; + + /** + * The selection rectangle (in Java2D space). + */ + private Rectangle selectionRect; + + /** + * The last mouse point. + */ + private Point2D startPoint; + + /** + * Creates a new default instance. + */ + public RectangularHeightRegionSelectionHandler() { + super(); + this.selectionRect = null; + this.startPoint = null; + } + + /** + * Creates a new instance with a modifier restriction + * @param modifier e.g. shift has to be pressed InputEvents.SHIFT_MASK + */ + public RectangularHeightRegionSelectionHandler(int modifier) { + super(modifier); + this.selectionRect = null; + this.startPoint = null; + } + + /** + * Creates a new selection handler with the specified attributes. + * + * @param outlineStroke the outline stroke. + * @param outlinePaint the outline paint. + * @param fillPaint the fill paint. + */ + public RectangularHeightRegionSelectionHandler(Stroke outlineStroke, + Paint outlinePaint, Paint fillPaint) { + super(outlineStroke, outlinePaint, fillPaint); + this.selectionRect = null; + this.startPoint = null; + } + + /** + * starts the rectangle selection by fixing the left upper corner of the rectangle + * + * @param e the event. + */ + public void mousePressed(MouseEvent e) { + if (!(e.getSource() instanceof ChartPanel)) { + return; + } + ChartPanel panel = (ChartPanel) e.getSource(); + Rectangle2D dataArea = panel.getScreenDataArea(); + if (dataArea.contains(e.getPoint())) { + SelectionManager selectionManager = panel.getSelectionManager(); + if (selectionManager != null) { + if (!e.isShiftDown()) { + selectionManager.clearSelection(); + } + Point pt = e.getPoint(); + this.startPoint = new Point(pt); + this.selectionRect = new Rectangle(pt.x, pt.y, 1, 1); + } + } + } + + /** + * adjusts with and height of the rectangle by expanding it to the actual + * position + * + * @param e the event. + */ + public void mouseDragged(MouseEvent e) { + ChartPanel panel = (ChartPanel) e.getSource(); + if (this.startPoint == null) { + panel.clearLiveMouseHandler(); + return; // we never started a selection + } + Point pt = e.getPoint(); + Point2D pt2 = ShapeUtilities.getPointInRectangle(pt.x, pt.y, + panel.getScreenDataArea()); + + selectionRect = getRect(startPoint, pt2, panel.getScreenDataArea()); + panel.setSelectionShape(selectionRect); + panel.setSelectionFillPaint(this.fillPaint); + panel.setSelectionOutlinePaint(this.outlinePaint); + panel.repaint(); + } + + /** + * finishes the selection and calls the {@link org.jfree.chart.panel.selectionhandler.SelectionManager} of + * the event source. The SelectionManager is then responsible for the processing + * of the geometric selection. + */ + public void mouseReleased(MouseEvent e) { + ChartPanel panel = (ChartPanel) e.getSource(); + if (this.startPoint == null) { + panel.clearLiveMouseHandler(); + return; // we never started a selection + } + SelectionManager selectionManager = panel.getSelectionManager(); + + // do something with the selection shape + if (selectionManager != null) { + selectionManager.select(selectionRect); + } + + panel.setSelectionShape(null); + this.selectionRect = null; + this.startPoint = null; + panel.repaint(); + panel.clearLiveMouseHandler(); + } + + + /** + * creates a rectangle from two points + * + * @param p1 one corner point + * @param p2 the other corner point + * @param plotarea the data area of the chart panel + * @return a new rectangle that has both points in opposite corners + */ + private Rectangle getRect(Point2D p1, Point2D p2, Rectangle2D plotarea ) { + int minX, minY; + int w, h; + + // process x and w + if (p1.getX() < p2.getX()) { + minX = (int) p1.getX(); + w = (int) p2.getX() - minX; + } else { + minX = (int) p2.getX(); + w = (int) p1.getX() - minX; + if (w <= 0) { + w = 1; + } + } + + // process y and h + minY = (int) plotarea.getMinY(); + h = (int) plotarea.getHeight(); + + return new Rectangle(minX, minY, w, h); + } +}