/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.org.smithfamily.mslogger.chart.tools;
import java.util.ArrayList;
import java.util.List;
import uk.org.smithfamily.mslogger.chart.chart.AbstractChart;
import uk.org.smithfamily.mslogger.chart.chart.XYChart;
/**
* The pan tool.
*/
public class Pan extends AbstractTool {
/** The pan listeners. */
private List<PanListener> mPanListeners = new ArrayList<PanListener>();
/** Pan limits reached on the X axis. */
private boolean limitsReachedX = false;
/** Pan limits reached on the X axis. */
private boolean limitsReachedY = false;
/**
* Builds and instance of the pan tool.
*
* @param chart the XY chart
*/
public Pan(AbstractChart chart) {
super(chart);
}
/**
* Apply the tool.
*
* @param oldX the previous location on X axis
* @param oldY the previous location on Y axis
* @param newX the current location on X axis
* @param newY the current location on the Y axis
*/
public void apply(float oldX, float oldY, float newX, float newY) {
boolean notLimitedUp = true;
boolean notLimitedBottom = true;
boolean notLimitedLeft = true;
boolean notLimitedRight = true;
if (mChart instanceof XYChart) {
int scales = mRenderer.getScalesCount();
double[] limits = mRenderer.getPanLimits();
boolean limited = limits != null && limits.length == 4;
XYChart chart = (XYChart) mChart;
for (int i = 0; i < scales; i++) {
double[] range = getRange(i);
double[] calcRange = chart.getCalcRange(i);
if (limitsReachedX
&& limitsReachedY
&& (range[0] == range[1] && calcRange[0] == calcRange[1] || range[2] == range[3]
&& calcRange[2] == calcRange[3])) {
return;
}
checkRange(range, i);
double[] realPoint = chart.toRealPoint(oldX, oldY, i);
double[] realPoint2 = chart.toRealPoint(newX, newY, i);
double deltaX = realPoint[0] - realPoint2[0];
double deltaY = realPoint[1] - realPoint2[1];
double ratio = getAxisRatio(range);
if (chart.isVertical(mRenderer)) {
double newDeltaX = -deltaY * ratio;
double newDeltaY = deltaX / ratio;
deltaX = newDeltaX;
deltaY = newDeltaY;
}
if (mRenderer.isPanXEnabled()) {
if (limits != null) {
if (notLimitedLeft) {
notLimitedLeft = limits[0] <= range[0] + deltaX;
}
if (notLimitedRight) {
notLimitedRight = limits[1] >= range[1] + deltaX;
}
}
if (!limited || (notLimitedLeft && notLimitedRight)) {
setXRange(range[0] + deltaX, range[1] + deltaX, i);
limitsReachedX = false;
} else {
limitsReachedX = true;
}
}
if (mRenderer.isPanYEnabled()) {
if (limits != null) {
if (notLimitedBottom) {
notLimitedBottom = limits[2] <= range[2] + deltaY;
}
if (notLimitedUp) {
notLimitedUp = limits[3] >= range[3] + deltaY;
}
}
if (!limited || (notLimitedBottom && notLimitedUp)) {
setYRange(range[2] + deltaY, range[3] + deltaY, i);
limitsReachedY = false;
} else {
limitsReachedY = true;
}
}
}
}
notifyPanListeners();
}
/**
* Return the X / Y axis range ratio.
*
* @param range the axis range
* @return the ratio
*/
private double getAxisRatio(double[] range) {
return Math.abs(range[1] - range[0]) / Math.abs(range[3] - range[2]);
}
/**
* Notify the pan listeners about a pan.
*/
private synchronized void notifyPanListeners() {
for (PanListener listener : mPanListeners) {
listener.panApplied();
}
}
/**
* Adds a new pan listener.
*
* @param listener pan listener
*/
public synchronized void addPanListener(PanListener listener) {
mPanListeners.add(listener);
}
/**
* Removes a pan listener.
*
* @param listener pan listener
*/
public synchronized void removePanListener(PanListener listener) {
mPanListeners.add(listener);
}
}