import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.util.Arrays;
/**
* A field that can display data in a bar graph format.
*/
public class BarGraphField extends GraphField {
/**
*
* Use no padding.
*/
public static final int PADDING_NONE = 0;
/**
*
* Use low padding.
*/
public static final int PADDING_LOW = 4;
/**
*
* Use medium padding.
*/
public static final int PADDING_MEDIUM = 8;
/**
*
* Use high padding.
*/
public static final int PADDING_HIGH = 12;
private int _scale, _increment, _barWidth, _barPadding, _scalePadding;
private boolean _showScale;
/**
*
* Constructs a bar graph using the default (PADDING_MEDIUM) padding without
* scale labels.
*
* @param values
* The values (data) to be graphed.
* @param colors
* The colors used to draw each bar.
* @param scale
* The maximum possible value of the graph, the top scale value.
* @param increment
* The increment amount for each scale value.
* @param barWidth
* The width in pixels of each bar.
*
* @throws IllegalArgumentException
* If the scale, increment or barWidth are <= 0, the array
* lengths of values and colors do not match or if any value is
* greater than the scale.
*/
public BarGraphField(int[] values, int[] colors, int scale, int increment,
int barWidth) {
this(values, colors, scale, increment, barWidth, PADDING_MEDIUM,
PADDING_MEDIUM, false);
}
/**
*
* Constructs a bar graph using the default (PADDING_MEDIUM) padding.
*
* @param values
* The values (data) to be graphed.
* @param colors
* The colors used to draw each bar.
* @param scale
* The maximum possible value of the graph, the top scale value.
* @param increment
* The increment amount for each scale value.
* @param barWidth
* The width in pixels of each bar.
* @param showScale
* True to display scale labels, false to not.
*
* @throws IllegalArgumentException
* If the scale, increment or barWidth are <= 0, the array
* lengths of values and colors do not match or if any value is
* greater than the scale.
*/
public BarGraphField(int[] values, int[] colors, int scale, int increment,
int barWidth, boolean showScale) {
this(values, colors, scale, increment, barWidth, PADDING_MEDIUM,
PADDING_MEDIUM, showScale);
}
/**
*
* Constructs a bar graph.
*
* @param values
* The values (data) to be graphed.
* @param colors
* The colors used to draw each bar.
* @param scale
* The maximum possible value of the graph, the top scale value.
* @param increment
* The increment amount for each scale value.
* @param barWidth
* The width in pixels of each bar.
* @param barPadding
* The amount of space between each bar. Can be PADDING_NONE,
* PADDING_LOW, PADDING_MEDIUM or PADDING_HIGH.
* @param scalePadding
* The amount of space between scale ticks. Ignored if scale
* labels are shown. Can be PADDING_NONE, PADDING_LOW,
* PADDING_MEDIUM or PADDING_HIGH.
* @param showScale
* True to display scale labels, false to not.
*
* @throws IllegalArgumentException
* If the scale, increment or barWidth are <= 0, the padding
*
* not match or if any value is greater than the scale.
*/
public BarGraphField(int[] values, int[] colors, int scale, int increment,
int barWidth, int barPadding, int scalePadding, boolean showScale) {
// Ensure the scale is greater than 0.
if (scale <= 0)
throw new IllegalArgumentException("Scale must be greater than 0.");
// Ensure the increment is greater than 0.
if (increment <= 0)
throw new IllegalArgumentException(
"Increment must be greater than 0.");
// Ensure the barWidth is greater than 0.
if (barWidth <= 0)
throw new IllegalArgumentException(
"Bar width must be greater than 0.");
// Ensure barPadding is a valid value.
switch (barPadding) {
case PADDING_NONE:
case PADDING_LOW:
case PADDING_MEDIUM:
case PADDING_HIGH:
break;
default:
throw new IllegalArgumentException("Invalid bar padding specified");
}
// Ensure scalePadding is a valid value.
switch (scalePadding) {
case PADDING_NONE:
case PADDING_LOW:
case PADDING_MEDIUM:
case PADDING_HIGH:
break;
default:
throw new IllegalArgumentException(
"Invalid scale padding specified");
}
// Ensure the number of bar values match the number of colors.
if (values.length != colors.length)
throw new IllegalArgumentException(
"Non matching array lengths for values and colors.");
// Ensure not values are greater than the scale value.
for (int count = values.length - 1; count >= 0; --count) {
if (values[count] > scale)
throw new IllegalArgumentException("Value greater than scale.");
}
_values = values;
_colors = colors;
_scale = scale;
_increment = increment;
_barWidth = barWidth;
barPadding = barPadding;
_scalePadding = scalePadding;
_showScale = showScale;
_width = calcWidth();
_height = calcHeight();
}
/**
*
* Calculate the width of the bar graph. The width is calculated by adding
* the width of the scale, a 4 pixel spacer between the end of the scale
* text and the start of the graph, a 2 pixel y axis, 2 pixels between the x
* axis and first bar and the total width of all bars and spaces between
* them. If _showScale is false the width of the scale and 2 pixel space is
* not included.
*
* @return The width of the graph.
*/
private int calcWidth() {
int theWidth;
if (_showScale)
theWidth = Font.getDefault().getAdvance(Integer.toString(_scale))
+ 8 + (_values.length * _barWidth)
+ ((_values.length - 1) * _barPadding);
else
theWidth = 10 + (_values.length * _barWidth)
+ ((_values.length - 1) * _barPadding);
return theWidth;
}
/**
*
* Calculate the height of the bar graph. If _showScale is true the height
* is calculated by adding the 2 pixel line along the bottom the graph to
* the font height multiplied by the number of scale increments shown. If
* _showScale is false the padding value is used for the scale increment
* height.
*
* @return The height of the graph.
*/
private int calcHeight() {
if (_showScale)
return 2 + (Font.getDefault().getHeight() * (_scale / _increment));
else if (_scalePadding == PADDING_NONE)
return 2 + (PADDING_LOW * (_scale / _increment));
else
return 2 + (_scalePadding * (_scale / _increment));
}
/**
*
* Draws the graph.
*
*/
protected void paint(Graphics graphics) {
int count, tempX, tempY, leftOver, graphHeight = 0;
int tickHeight; // The height of the scale ticks.
int tickIndent; // The distance to indent the scale ticks.
if (_showScale) {
tickHeight = Font.getDefault().getHeight();
// Subtract 4 from the width of the scale (2 pixels for the scale
// width and 2 pixels for spacing).
tickIndent = Font.getDefault().getAdvance(Integer.toString(_scale)) - 4;
} else {
if (_scalePadding == PADDING_NONE)
tickHeight = PADDING_LOW;
else
tickHeight = _scalePadding;
tickIndent = 0;
}
// Wipe out any existing graph image data.
graphics.clear();
graphics.setColor(0);
// In case the increment doesn't divide into the scale evenly.
leftOver = _scale % _increment;
tempY = 0;
// Draw the scale.
for (count = _scale; count > leftOver; count -= _increment) {
graphics.fillRect(tickIndent, tempY, 6, 2);
if (_showScale)
graphics.drawText(Integer.toString(count), 0, tempY);
tempY += tickHeight;
}
tempX = tickIndent + 6;
// Draw the x axis.
graphics.fillRect(tempX, tempY, _width - tempX, 2);
// Draw the y axis.
graphics.fillRect(tempX, 0, 2, _height);
tempX = _width - _barWidth;
// Draw the bars.
for (count = _values.length - 1; count >= 0; --count) {
graphics.setColor(_colors[count]);
// Calculate the top bar as a percentage of the available graphing
// space
// relating to the value. Graphing space is _height - 2 (2 pixel y
// axis).
tempY = _height - (int) (((_height - 2) * _values[count]) / _scale);
graphHeight = _height - tempY - 2;
graphics.fillRect(tempX, tempY, _barWidth, graphHeight);
// Calculate the next graph starting point.
tempX -= (_barWidth + _barPadding);
}
}
/**
*
* Retrieves the bar padding.
*
* @return the bar padding.
*/
public int getBarPadding() {
return _barPadding;
}
/**
*
* Retrieves the bar width.
*
* @return the bar width.
*/
public int getBarWidth() {
return _barWidth;
}
/**
*
* Retrieves the increment.
*
* @return the increment.
*/
public int getIncrement() {
return _increment;
}
/**
*
* Retrieves the scale.
*
* @return the scale.
*/
public int getScale() {
return _scale;
}
/**
*
* Retrieves the scale padding.
*
* @return the scale padding.
*/
public int getScalePadding() {
return _scalePadding;
}
/**
*
* Retrieves the scale label visibility flag.
*
* @return true if the scale labels are visible, false if they are not.
*/
public boolean isScaleVisible() {
return _showScale;
}
/**
*
* Sets the bar padding
*
* @param barPadding
* Can be PADDING_NONE, PADDING_LOW, PADDING_MEDIUM or
* PADDING_HIGH.
*
* @throws IllegalArgumentException
* if an invalid padding value is specified.
*/
public void setBarPadding(int barPadding) {
// Don't do anything unless the bar padding has changed.
if (_barPadding != barPadding) {
// Ensure barPadding is a valid value.
switch (barPadding) {
case PADDING_NONE:
case PADDING_LOW:
case PADDING_MEDIUM:
case PADDING_HIGH:
break;
default:
throw new IllegalArgumentException(
"Invalid bar padding specified");
}
_barPadding = barPadding;
_width = calcWidth();
}
}
/**
*
* Set the bar width
*
* @param barWidth
* the bar width.
*
* @throws IllegalArgumentException
* if the width <= 0.
*/
public void setBarWidth(int barWidth) {
// Dont do anything unless the bar width has changed.
if (_barWidth != barWidth) {
// Ensure the barWidth is greater than 0.
if (barWidth <= 0)
throw new IllegalArgumentException(
"Bar width must be greater than 0.");
_barWidth = barWidth;
_width = calcWidth();
}
}
/**
*
* Set the graph values (data) and colors.
*
* @param values
* data used to create the graph.
* @param colors
* an array of colors used to draw each bar in the form of form
* of 0x00RRGGBB.
*
* @throws IllegalArgumentException
* if the array lengths of values and colors do not match or if
* a value is larger than the current scale value.
*/
public void setGraphData(int[] values, int[] colors) {
// Don't do anything unless the data has changed.
if (!Arrays.equals(_values, values) || !Arrays.equals(_colors, colors)) {
// Ensure the number of values match the number of colors.
if (values.length != colors.length)
throw new IllegalArgumentException(
"Non matching array lengths for bars and colors.");
// Ensure not values are greater than the scale value.
for (int count = values.length - 1; count >= 0; --count) {
if (values[count] > _scale)
throw new IllegalArgumentException(
"Value greater than scale.");
}
_values = values;
_colors = colors;
_width = calcWidth();
_height = calcHeight();
}
}
/**
*
* Sets the scale increment. The increment value will determine the number
* of ticks on the scale. It is recommended to use an increment value that
* divides evenly into the scale.
*
* @param increment
* the scale increment.
*
* @throws IllegalArgumentException
* if the increment <= 0.
*/
public void setIncrement(int increment) {
// Don't do anything unless the increment has changed.
if (_increment != increment) {
// Ensure the increment is greater than 0.
if (increment <= 0)
throw new IllegalArgumentException(
"Increment must be greater than 0.");
// Only the height changes with an increment change.
_increment = increment;
_height = calcHeight();
}
}
/**
*
* Sets the scale value. The scale represents the maximum value possible of
* data in the graph, all values must be <= this value.
*
* @param scale
* the scale value.
*
* @throws IllegalArgumentException
* if the scale is <= 0 or if a value is greater than the
* scale.
*/
public void setScale(int scale) {
// /Don't do anything unless the scale has changed.
if (_scale != scale) {
// Ensure the scale is greater than 0.
if (scale <= 0)
throw new IllegalArgumentException(
"Scale must be greater than 0.");
// Ensure no values are greater than the scale value.
for (int count = _values.length - 1; count >= 0; --count) {
if (_values[count] > scale)
throw new IllegalArgumentException(
"Value greater than scale.");
}
_scale = scale;
_width = calcWidth();
_height = calcHeight();
}
}
// Set the scale padding.
/**
*
* Set the scale padding. This represents the spacing between the ticks of
* the scale. This parameter is only used if the scale labels are not
* visible. If scale labels are visible the spacing is derived by the font
* height.
*
* @param scalePadding
* Can be PADDING_NONE, PADDING_LOW, PADDING_MEDIUM or
* PADDING_HIGH.
*
* @throws IllegalArgumentException
* if an invalid padding value is specified.
*/
public void setScalePadding(int scalePadding) {
// Don't do anything unless the scale padding has changed.
if (_scalePadding != scalePadding) {
// Ensure scalePadding is a valid value.
switch (scalePadding) {
case PADDING_NONE:
case PADDING_LOW:
case PADDING_MEDIUM:
case PADDING_HIGH:
break;
default:
throw new IllegalArgumentException(
"Invalid scale padding specified");
}
_scalePadding = scalePadding;
_height = calcHeight();
}
}
// Set the scale visibility flag.
/**
*
* Sets the scale label visibility flag.
*
* @param showScale
* True to display scale labels, false to disable it.
*/
public void setScaleVisible(boolean showScale) {
// Don't do anything unless the flag has changed.
if (_showScale != showScale) {
_showScale = showScale;
_width = calcWidth();
_height = calcHeight();
}
}
}
Comments
Post a Comment