Sunday, October 19, 2008

Work with proportions

Lets say you have some data to present, for example, the amount of money per month you spend with food. How do we create an application that shows this data as columns?
First thing is to know how much space the application has to use. This can be achieved with a Canvas child class calling the methods getWidth() and getHeight().
The number of columns displayed at a time depends on the screen width and the font used to draw the month name. To make things easier I suggest using a Font with FACE_MONOSPACE and let the column be the same width of the month short name. You may vary style and size, but this will not change the result greatly.
As the columns should not touch each other we will add an one pixel gap between them.

String [] months = new String [] {
    "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
Font monospacedFont = Font.getFont(
    Font.FACE_MONOSPACE, Font.STYLE_PLAIN,
    Font.SIZE_MEDIUM);
int columnWidth = monospacedFont.stringWidth(months[0]);
// 1 == gap between columns
int numColumns = (getWidth() - 1) / (columnWidth + 1);

Next thing we need to know is the highest value in the data set and how many pixels we will use to represent this special column.

// 1 == gap to the top of the screen
// 2 == space to draw month name and value
int maxColumnHeight = getHeight() - (2 * monospacedFont.getHeight()) - 1;
int highestValue = 0;

for (int i = 0; i < data.length; i++) {
if (data[i] > highestValue) {
highestValue = data[i];
}
}

Now we do the painting:

int x = 1; // 1 == gap to the left side of the screen
int y = getHeight() - monospacedFont.getHeight();

// clear the screen
g.setColor(0xffffff); // white
g.fillRect(0, 0, getWidth(), getHeight());

g.setFont(monospacedFont);
g.setColor(0); // black

for (int i = 0; i < numColumns; i++) {
  int columnHeight = (data[i] * maxColumnHeight) / highestValue;
  g.fillRect(x, y - columnHeight, columnWidth, columnHeight);
  // month name at the bottom
  g.drawString(months[i], x, y, Graphics.LEFT | Graphics.TOP);
  // data value on top of the column
  g.drawString(String.valueOf(data[i]), x, y - columnHeight, Graphics.LEFT | Graphics.BOTTOM);
  x = x + columnWidth + 1;
}

Below are two screen shots with different resolutions:








2 comments:

Serge Rehem said...

Congratulations for this blog iniciative! I have 2 tips for you:

1) Special Copy/Paste Plugin
http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=9275. The editor content copied to the clipboard will be readily pastable as HTML/CSS, for insertion into blogs, wiki's etc.

2) Projects Marge (marge.dev.java.net), Java Bluetooth Framework, and mOOo! (mooo.dev.java.net), Mobile OpenOffice.org (The Impress Controler is a Java ME application and a Java SE Add-On that controls a slide presentation in OOo Impress). More about mOOo IC at http://javabahia.blogspot.com/2008/10/mooo-controlando-apresentaes-do.html (ptBR).

Cheers!

Telmo Mota said...

Hi Serge, thank you for the tips. I'll take a look at both.