/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.broad.igv.charts;
/**
* @author Jim Robinson
* @date 10/25/11
*/
public class Axis {
enum Orientation {HORIZONTAL, VERTICAL}
;
Orientation orientation;
double min;
double max;
double[] ticks;
double scale; // Scale in value units per pixel
int panelSize = 500;
private String label;
public Axis(Orientation orientation) {
this.orientation = orientation;
}
public Orientation getOrientation() {
return orientation;
}
public int getPixelForValue(double value) {
int p = (int) ((value - min) * scale);
return (orientation == Orientation.HORIZONTAL) ? p : panelSize - p;
}
public double getDataValueForPixel(int pixel) {
int p = (orientation == Orientation.HORIZONTAL ? pixel : panelSize - pixel);
return min + p / scale;
}
public void setRange(double min, double max) {
ticks = computeTicks(min, max, 10);
this.min = ticks[0];
int maxTickNumber = (int) (max / ticks[1]) + 1;
if (max > 0) maxTickNumber++;
this.max = maxTickNumber * ticks[1];
rescale();
}
private void rescale() {
scale = ((double) panelSize) / (max - min);
}
public void setLabel(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public void setPanelSize(int panelSize) {
if (panelSize != this.panelSize) {
this.panelSize = panelSize;
rescale();
}
}
/**
* Computes the tick mark start location and increment for an axis. The start tick is the first tick to the left
* of the minimum value.
*
* @param min
* @param max
* @param targetTickCount approximate number of ticks desired between min and max
* @return tuple -- {firstTick, tickIncrement}
*/
public static double[] computeTicks(double min, double max, int targetTickCount) {
// TODO -- take into account the panel size
if (max <= min) {
return new double[]{max, 1};
}
final double v = max - min;
double d = Math.log10(v);
double r = Math.floor(d);
double delta0 = Math.pow(10, r);
int nTicks0 = (int) (v / delta0);
double delta = delta0;
int nTicks;
int[] mults = {1, 2, 5, 10};
for (int i = 0; i < mults.length; i++) {
nTicks = nTicks0 * mults[i];
delta = delta0 / mults[i];
if (nTicks > 0.7 * targetTickCount) {
break;
}
}
double minTick = min - min % delta;
if (min < 0) minTick -= delta;
return new double[]{minTick, delta};
}
public double getScale() {
return scale;
}
}