×
Namespaces

Variants
Actions
Revision as of 18:05, 22 May 2012 by jasfox (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Creating Touchable Custom Map Components for the Maps API for Java ME

From Nokia Developer Wiki
Jump to: navigation, search


This article explains how to create a framework for custom MapComponents which respond to touch Events. A series of touchable components (scale bar, button, attribution image) are then added using the framework.


Contents

Introduction

In order to maximize the screen real estate available to display a Map, it is necessary to invoke Full Screen mode. This can be done when the MapCanvas is initialised, through a call to MapCanvas.setFullScreenMode(true). Command buttons cannot be used when a full screen is displayed, and therefore it is necessary to add at least one MapComponent to allow the user to interact with the Map. This article proposes a framework for creating touchable MapComponents and a series of compoments such as a custon button and a scale bar are added to an example MIDlet


TouchableDisplayComponent

public abstract class TouchableDisplayComponent implements MapComponent {
 
private final String version = "1.0";
private final Image bitmap;
private MapDisplay map;
private static final int SMALL_CORNER_ARC = 5;
private static final int DEFAULT_OFFSET = 5;
protected static final int NO_FILL = -1;
private final int border;
private final int borderColor;
private final int backgroundColor;
private Point borderAnchor;
private Point backgroundAnchor;
private EventListener touchEventHandler = null;
private TouchEventListener listener;
private final int anchor;
private Point offset = new Point(DEFAULT_OFFSET, DEFAULT_OFFSET);
 
 
public TouchableDisplayComponent(Image bitmap, int anchor, int border, int borderColor,
int backgroundColor) {
this.bitmap = bitmap;
this.border = border;
this.borderColor = borderColor;
this.backgroundColor = backgroundColor;
this.anchor = anchor;
touchEventHandler = new TouchEventHandler(this);
}
 
public TouchableDisplayComponent(Image bitmap, int anchor) {
this(bitmap, anchor,0, NO_FILL, NO_FILL);
}
 
 
 
// from MapComponent
public void attach(MapDisplay map) {
this.map = map;
calculateBorders(map);
 
return;
}
 
protected void calculateBorders(MapDisplay map) {
int x = getOffset().getX();
int y = getOffset().getY();
if ((getAnchor() & Graphics.BOTTOM) != 0) {
y = map.getHeight() - getImageHeight() - getOffset().getY();
}
if ((getAnchor() & Graphics.RIGHT) != 0) {
x = map.getWidth() - getImageWidth() - getOffset().getX();
}
 
setBorderAnchor(new Point(x - getBorder(),
y - getBorder()));
setBackgroundAnchor(new Point(x, y));
}
 
// from MapComponent
public void detach(MapDisplay map) {
this.map = null;
return;
}
 
// from MapComponent
public String getVersion() {
return version;
}
 
// from MapComponent
public void mapUpdated(boolean zoomChanged) {
}
 
// from MapComponent
public void paint(Graphics g) {
 
if (getBorder() > 0) {
g.setColor(borderColor);
g.fillRoundRect(getBorderAnchor().getX(), getBorderAnchor().getY(),
getImageWidth() + (getBorder() * 2), getImageHeight() + (getBorder() * 2),
SMALL_CORNER_ARC, SMALL_CORNER_ARC);
}
 
if (backgroundColor > NO_FILL) {
// Draw the background.
g.setColor(backgroundColor);
g.fillRoundRect(getBackgroundAnchor().getX(), getBackgroundAnchor().getY(),
getImageWidth(),
getImageHeight(), SMALL_CORNER_ARC, SMALL_CORNER_ARC);
}
 
if (bitmap != null) {
g.drawImage(bitmap,
getBackgroundAnchor().getX(), getBackgroundAnchor().getY(),
Graphics.TOP | Graphics.LEFT);
}
 
}
 
protected int getImageHeight() {
return bitmap.getHeight();
}
 
protected int getImageWidth() {
return bitmap.getWidth();
}
 
public EventListener getEventListener() {
return touchEventHandler;
}
 
//protected void setEventHandler(TouchableDisplayComponent component) {
//}
/**
* @return the map
*/

public MapDisplay getMap() {
return map;
}
 
/**
* @return the borderAnchor
*/

protected Point getBorderAnchor() {
return borderAnchor;
}
 
/**
* @param borderAnchor the borderAnchor to set
*/

protected void setBorderAnchor(Point borderAnchor) {
this.borderAnchor = borderAnchor;
}
 
/**
* @return the backgroundAnchor
*/

protected Point getBackgroundAnchor() {
return backgroundAnchor;
}
 
/**
* @param backgroundAnchor the backgroundAnchor to set
*/

protected void setBackgroundAnchor(Point backgroundAnchor) {
this.backgroundAnchor = backgroundAnchor;
}
 
/**
* @return the border
*/

protected int getBorder() {
return border;
}
 
/**
* @return the anchor
*/

public int getAnchor() {
return anchor;
}
 
 
 
/**
* @param yOffset the yOffset to set
*/

public void setOffset(Point offset) {
this.offset = offset;
}
 
/**
* @return the offset
*/

public Point getOffset() {
return offset;
}
 
 
 
private class TouchEventHandler implements EventListener {
 
private final TouchableDisplayComponent component;
 
public TouchEventHandler(TouchableDisplayComponent component) {
this.component = component;
 
}
 
public boolean keyPressed(int keyCode, int gameAction) {
return false;
}
 
public boolean keyReleased(int keyCode, int gameAction) {
return false;
}
 
public boolean keyRepeated(int keyCode, int gameAction, int repeatCount) {
return false;
}
 
public boolean pointerDragged(int x, int y) {
return false;
}
 
public boolean pointerPressed(int x, int y) {
 
if (x > getBackgroundAnchor().getX()
&& x < getBackgroundAnchor().getX() + getImageWidth()
&& y > getBackgroundAnchor().getY()
&& y < getBackgroundAnchor().getY() + getImageHeight()) {
this.component.doClick(x - getBackgroundAnchor().getX(), y
+ getBackgroundAnchor().getY());
return true;
 
}
 
return false;
}
 
public boolean pointerReleased(int x, int y) {
return false;
}
};
 
public boolean doClick(int x, int y) {
if (listener != null) {
listener.touchAction(this, x, y);
return true;
}
return false;
}
 
public void setEventListener(TouchEventListener listener) {
this.listener = listener;
}
}


TouchTextComponent

public class TouchTextComponent extends TouchableDisplayComponent {
 
protected static final int TEXT_MARGIN = 5;
private String text = "";
private final Font font;
private final int textColor;
private static final String ID = "TextButton";
 
public TouchTextComponent(int anchor, int border, int borderColor,
int backgroundColor, int textColor, Font font) {
super(null,anchor, border, borderColor, backgroundColor);
this.font = font;
this.textColor = textColor;
}
 
public TouchTextComponent(int anchor, int border, int borderColor,
int backgroundColor, int textColor) {
this(anchor, border, borderColor, backgroundColor, textColor, Font.getDefaultFont());
}
 
/**
* @return the text
*/

public String getText() {
return text;
}
 
/**
* @param text the text to set
*/

public void setText(String text) {
this.text = text;
}
 
protected int getImageHeight() {
return font.getHeight() + 4;
}
 
protected int getImageWidth() {
return font.stringWidth(text) + (2 * TEXT_MARGIN);
}
 
public String getId() {
return ID;
}
 
public void paint(Graphics g) {
if ("".equals(getText()) == false) {
super.paint(g);
g.setColor(textColor);
g.drawString(
getText(), getBackgroundAnchor().getX() + TEXT_MARGIN, getBackgroundAnchor().getY(), Graphics.TOP | Graphics.LEFT);
}
}
}


AttributionMapComponent

public class AttributionMapComponent extends TouchableDisplayComponent {
 
private final String id = "attribution";
 
public AttributionMapComponent(Image attribution, int anchor, int border, int borderColor,
int backgroundColor) {
super(attribution, anchor, border, borderColor, backgroundColor);
 
}
 
 
public AttributionMapComponent(Image attribution, int anchor) {
super(attribution, anchor);
}
 
// from MapComponent
public String getId() {
return id;
}
 
public void paint(Graphics g) {
if (getMap() != null && getMap().getAllMapOverlays().length > 0) {
super.paint(g);
}
}
}


ScaleBarComponent

public class ScaleBarComponent extends TouchTextComponent {
 
private static final String ID = "ScaleBar";
private int y_coord;
private int x_coord_start;
private int x_coord_end;
private boolean imperial;
final static int[] SCALE_IN_METRES = new int[]{5000000, 2000000, 1000000,
600000, 300000, 150000, 75000, 30000, 20000, 10000, 5000, 2000, 1000,
500, 250, 100, 50, 25};
final static String[] SCALE_IN_METRES_TEXT = new String[]{"5000km", "2000km", "1000km",
"600km", "300km", "150km", "75km", "30km", "20km", "10km", "5km", "2km", "1km",
"500m", "250m", "100m", "50m", "25m"};
final static int[] SCALE_IN_IMPERIAL = new int[]{4828000, 2414000, 1207000, 643737, 321868, 160934, 80467, 40233, 24140,
16093, 8046, 3218, 1609, 457, 228, 91, 45, 22};
final static String[] SCALE_IN_IMPERIAL_TEXT = new String[]{"3000 miles", "1500 miles", "750 miles",
"400 miles", "200 miles", "100 miles", "50 miles", "25 miles", "15 miles", "10 miles", "5 miles", "2 miles", "1 mile",
"500 yds", "250 yds", "100 yds", "50 yds", "75 ft"};
 
public ScaleBarComponent() {
super(Graphics.BOTTOM | Graphics.RIGHT, 0, NO_FILL, NO_FILL, 000000 );
}
 
public ScaleBarComponent(int textColor, Font font) {
super(Graphics.BOTTOM | Graphics.RIGHT, 0, NO_FILL, NO_FILL, textColor, font);
}
 
public ScaleBarComponent(int anchor, int border, int borderColor,
int backgroundColor) {
super(anchor, border, borderColor, backgroundColor, 000000, Font.getDefaultFont());
}
 
public ScaleBarComponent(int anchor, int border, int borderColor,
int backgroundColor, int textColor, Font font) {
super(anchor, border, borderColor, backgroundColor, textColor, font);
 
}
 
 
 
// from MapComponent
public String getId() {
return ID;
}
 
/**
* When the map is updated, we need to check if one of the MapObjects held
* in the Hashtable has the current focus. If so, the tooltip is set,
* the tooltip is cleared otherwise.
* @param zoomChanged
*/

public void mapUpdated(boolean zoomChanged) {
 
 
x_coord_end = getBackgroundAnchor().getX() + getImageWidth() - TEXT_MARGIN;//getMap().getWidth() - X_OFFSET - TEXT_MARGIN;
y_coord = getBackgroundAnchor().getY() + getImageHeight() - TEXT_MARGIN; // getMap().getHeight() - Y_OFFSET - TEXT_MARGIN;
double zoom = getMap().getZoomLevel();
zoom = (zoom >= getMap().getMinZoomLevel()) ? zoom : getMap().getMinZoomLevel();
if (isImperial()) {
displayImperial(zoom);
} else {
displayMetric(zoom);
}
calculateBorders(getMap());
}
 
protected void displayMetric(double zoom) {
if (zoom <= SCALE_IN_METRES.length - 1) {
GeoCoordinate end = getMap().pixelToGeo(new Point(x_coord_end, y_coord));
x_coord_start = x_coord_end - 10;
while (getMap().pixelToGeo(new Point(x_coord_start, y_coord)).distanceTo(end) < SCALE_IN_METRES[(int) zoom]) {
x_coord_start--;
}
 
setText(SCALE_IN_METRES_TEXT[(int) zoom]);
}
}
 
protected void displayImperial(double zoom) {
if (zoom <= SCALE_IN_IMPERIAL.length - 1) {
GeoCoordinate end = getMap().pixelToGeo(new Point(x_coord_end, y_coord));
x_coord_start = x_coord_end - 10;
while (getMap().pixelToGeo(new Point(x_coord_start, y_coord)).distanceTo(end) < SCALE_IN_IMPERIAL[(int) zoom]) {
x_coord_start--;
}
 
setText(SCALE_IN_IMPERIAL_TEXT[(int) zoom]);
}
}
 
public void paint(Graphics g) {
if ("".equals(getText()) == false) {
super.paint(g);
 
g.setColor(000000);
g.drawLine(x_coord_start, y_coord, x_coord_end, y_coord);
g.drawLine(x_coord_start, y_coord + 1, x_coord_end, y_coord + 1);
 
g.drawLine(x_coord_start, y_coord + 3, x_coord_start, y_coord);
g.drawLine(x_coord_end, y_coord + 3, x_coord_end, y_coord);
 
 
/*g.drawString(
getText(), x_coord_end, y_coord, Graphics.BOTTOM | Graphics.RIGHT); */

}
}
 
 
 
public boolean doClick(int x, int y) {
setImperial(!isImperial());
mapUpdated(false);
 
System.out.println("doClick1");
return true;
}
 
/**
* @return the imperial
*/

public boolean isImperial() {
return imperial;
}
 
/**
* @param imperial the imperial to set
*/

public void setImperial(boolean imperial) {
this.imperial = imperial;
}
}
Article Metadata
Code ExampleTested with
Devices(s): X3-02
Compatibility
Device(s): All
Dependencies: Maps API for Java ME v1.0
Article
Keywords: Location API, Ovi Maps, MapComponent, MapDisplay, FullScreen, Scale bar, Button, Touch
Created: jasfox (29 May 2012)
Updated: :
Last edited: jasfox (22 May 2012)



Summary

Add categories below. Remove Category:Draft when the page is complete or near complete

164 page views in the last 30 days.