DefaultSelectionZoomStrategy.java
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2022, by David Gilbert 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.
*
* [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.]
*
* ---------------------------------
* DefaultSelectionZoomStrategy.java
* ---------------------------------
* (C) Copyright 2021-2022 by David Gilbert and Contributors.
*
* Original Author: -;
* Contributor(s): David Gilbert;
*
*
*/
package org.jfree.chart.swing;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.jfree.chart.internal.SerialUtils;
/**
* {@inheritDoc}
*
* This implementation can be extended to override default behavior.
*/
public class DefaultSelectionZoomStrategy implements SelectionZoomStrategy {
private static final long serialVersionUID = -8042265475645652131L;
/** The minimum size required to perform a zoom on a rectangle */
public static final int DEFAULT_ZOOM_TRIGGER_DISTANCE = 10;
/**
* The zoom rectangle starting point (selected by the user with a mouse
* click). This is a point on the screen, not the chart (which may have
* been scaled up or down to fit the panel).
*/
protected Point2D zoomPoint = null;
/**
* The zoom rectangle (selected by the user with the mouse).
*/
protected transient Rectangle2D zoomRectangle = null;
/**
* Controls if the zoom rectangle is drawn as an outline or filled.
*/
private boolean fillZoomRectangle = true;
/**
* The minimum distance required to drag the mouse to trigger a zoom.
*/
private int zoomTriggerDistance;
/**
* The paint used to draw the zoom rectangle outline.
*/
private transient Paint zoomOutlinePaint;
/**
* The zoom fill paint (should use transparency).
*/
private transient Paint zoomFillPaint;
public DefaultSelectionZoomStrategy() {
zoomTriggerDistance = DEFAULT_ZOOM_TRIGGER_DISTANCE;
this.zoomOutlinePaint = Color.BLUE;
this.zoomFillPaint = new Color(0, 0, 255, 63);
}
@Override
public boolean isActivated() {
return zoomRectangle != null;
}
@Override
public Point2D getZoomPoint() {
return zoomPoint;
}
@Override
public void setZoomPoint(Point2D zoomPoint) {
this.zoomPoint = zoomPoint;
}
@Override
public void setZoomTriggerDistance(int distance) {
this.zoomTriggerDistance = distance;
}
@Override
public int getZoomTriggerDistance() {
return zoomTriggerDistance;
}
@Override
public Paint getZoomOutlinePaint() {
return zoomOutlinePaint;
}
@Override
public void setZoomOutlinePaint(Paint paint) {
this.zoomOutlinePaint = paint;
}
@Override
public Paint getZoomFillPaint() {
return zoomFillPaint;
}
@Override
public void setZoomFillPaint(Paint paint) {
this.zoomFillPaint = paint;
}
@Override
public boolean getFillZoomRectangle() {
return this.fillZoomRectangle;
}
@Override
public void setFillZoomRectangle(boolean flag) {
this.fillZoomRectangle = flag;
}
@Override
public void updateZoomRectangleSelection(MouseEvent e, boolean hZoom, boolean vZoom, Rectangle2D scaledDataArea) {
if (hZoom && vZoom) {
// selected rectangle shouldn't extend outside the data area...
double xMax = Math.min(e.getX(), scaledDataArea.getMaxX());
double yMax = Math.min(e.getY(), scaledDataArea.getMaxY());
zoomRectangle = new Rectangle2D.Double(
zoomPoint.getX(), zoomPoint.getY(),
xMax - zoomPoint.getX(), yMax - zoomPoint.getY());
}
else if (hZoom) {
double xMax = Math.min(e.getX(), scaledDataArea.getMaxX());
zoomRectangle = new Rectangle2D.Double(
zoomPoint.getX(), scaledDataArea.getMinY(),
xMax - zoomPoint.getX(), scaledDataArea.getHeight());
}
else if (vZoom) {
double yMax = Math.min(e.getY(), scaledDataArea.getMaxY());
zoomRectangle = new Rectangle2D.Double(
scaledDataArea.getMinX(), zoomPoint.getY(),
scaledDataArea.getWidth(), yMax - zoomPoint.getY());
}
}
@Override
public Rectangle2D getZoomRectangle(boolean hZoom, boolean vZoom, Rectangle2D screenDataArea) {
double x, y, w, h;
double maxX = screenDataArea.getMaxX();
double maxY = screenDataArea.getMaxY();
// for mouseReleased event, (horizontalZoom || verticalZoom)
// will be true, so we can just test for either being false;
// otherwise both are true
if (!vZoom) {
x = zoomPoint.getX();
y = screenDataArea.getMinY();
w = Math.min(zoomRectangle.getWidth(),
maxX - zoomPoint.getX());
h = screenDataArea.getHeight();
}
else if (!hZoom) {
x = screenDataArea.getMinX();
y = zoomPoint.getY();
w = screenDataArea.getWidth();
h = Math.min(zoomRectangle.getHeight(),
maxY - zoomPoint.getY());
}
else {
x = zoomPoint.getX();
y = zoomPoint.getY();
w = Math.min(zoomRectangle.getWidth(),
maxX - zoomPoint.getX());
h = Math.min(zoomRectangle.getHeight(),
maxY - zoomPoint.getY());
}
return new Rectangle2D.Double(x, y, w, h);
}
@Override
public void reset() {
zoomPoint = null;
zoomRectangle = null;
}
@Override
public void drawZoomRectangle(Graphics2D g2, boolean xor) {
if (zoomRectangle != null) {
if (xor) {
// Set XOR mode to draw the zoom rectangle
g2.setXORMode(Color.GRAY);
}
if (fillZoomRectangle) {
g2.setPaint(zoomFillPaint);
g2.fill(zoomRectangle);
}
else {
g2.setPaint(zoomOutlinePaint);
g2.draw(zoomRectangle);
}
if (xor) {
// Reset to the default 'overwrite' mode
g2.setPaintMode();
}
}
}
/**
* Provides serialization support.
*
* @param stream the output stream.
*
* @throws IOException if there is an I/O error.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
SerialUtils.writePaint(this.zoomFillPaint, stream);
SerialUtils.writePaint(this.zoomOutlinePaint, stream);
}
/**
* Provides serialization support.
*
* @param stream the input stream.
*
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
this.zoomFillPaint = SerialUtils.readPaint(stream);
this.zoomOutlinePaint = SerialUtils.readPaint(stream);
}
}