Skip to content

Commit

Permalink
Add zoom control and touch events
Browse files Browse the repository at this point in the history
  • Loading branch information
stellaraccident committed Apr 4, 2011
1 parent 7139286 commit 1f15653
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 8 deletions.
16 changes: 10 additions & 6 deletions nanomaps-library/src/net/rcode/nanomaps/MapState.java
Expand Up @@ -152,6 +152,12 @@ public double getViewportOriginY() {
return viewportOriginY;
}

public void setViewportOrigin(double x, double y) {
this.viewportOriginX=x;
this.viewportOriginY=y;
_updated(false);
}

public int getViewportWidth() {
return viewportWidth;
}
Expand Down Expand Up @@ -241,12 +247,10 @@ public double projectedToDisplayY(double projectedY) {
* @param deltaX
* @param deltaY
*/
public void moveOrigin(int deltaX, int deltaY) {
if (deltaX!=0 || deltaY!=0) {
viewportOriginX+=deltaX;
viewportOriginY+=deltaY;
_updated(false);
}
public void moveViewport(double deltaX, double deltaY) {
viewportOriginX+=deltaX;
viewportOriginY+=deltaY;
_updated(false);
}

/**
Expand Down
98 changes: 98 additions & 0 deletions nanomaps-library/src/net/rcode/nanomaps/MapSurface.java
Expand Up @@ -3,6 +3,8 @@
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

/**
Expand All @@ -27,6 +29,7 @@ public MapSurface(Context context) {
// Allocate the background layer
backgroundLayer=createContentView();
addView(backgroundLayer, createFillLayoutParams());
setupTouchEvents(backgroundLayer);
}

private MapContentView createContentView() {
Expand Down Expand Up @@ -70,4 +73,99 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (DEBUG) Log.d(Constants.LOG_TAG, "onSizeChanged(" + w + "," + h + ")");
mapState.setViewportSize(w, h);
}

// -- touch handling
protected static final int TOUCH_STATE_NONE=0;
protected static final int TOUCH_STATE_SINGLE=1;
protected int touchState;
protected float touchAnchorX, touchAnchorY;

protected void setupTouchEvents(final View target) {
target.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
handleTouchEvent(event);
return true;
}
});
}

protected void handleTouchEvent(MotionEvent event) {
// Newer api levels support multi-touch and getters to separate them.
// We just do the bitwise math. Lower 8bits==action, next 8bits==pointer index.
int action=event.getAction() & 0xff;
int pid=(event.getAction() & 0xff00) >> 8;

switch (action) {
case MotionEvent.ACTION_MOVE:
// Accumulate
if (pid==0) {
handleTouchMovePrimary(event);
}
break;
case MotionEvent.ACTION_DOWN:
// Initiate a gesture
if (pid==0) {
handleTouchStart(event);
}
break;
case MotionEvent.ACTION_UP:
// End the gesture
if (pid==0) {
handleTouchDone(event, false);
}
break;

case MotionEvent.ACTION_CANCEL:
// Framework cancelled the gesture
if (pid==0) {
handleTouchDone(event, true);
}
break;
}
}

protected void clearTouchState() {
touchState=TOUCH_STATE_NONE;
}

protected void handleTouchStart(MotionEvent event) {
clearTouchState();
touchState=TOUCH_STATE_SINGLE;
touchAnchorX=event.getX();
touchAnchorY=event.getY();
if (DEBUG) Log.d(Constants.LOG_TAG, "Start touch: " + event);
}

protected void handleTouchMovePrimary(MotionEvent event) {
if (touchState==TOUCH_STATE_SINGLE) {
//if (DEBUG) Log.d(Constants.LOG_TAG, "Touch move: " + event);

float currentX=event.getX();
float currentY=event.getY();

float deltaX=touchAnchorX - currentX;
float deltaY=touchAnchorY - currentY;

// Update the map state
mapState.moveViewport(deltaX, deltaY);
touchAnchorX=currentX;
touchAnchorY=currentY;
}
}

protected void handleTouchDone(MotionEvent event, boolean cancelled) {
if (DEBUG) Log.d(Constants.LOG_TAG, "Touch done: " + event);

clearTouchState();
}

// -- public api
public int getMapMaxLevel() {
return mapState.getProjection().getMaxLevel();
}
public int getMapMinLevel() {
return mapState.getProjection().getMinLevel();
}

}
4 changes: 2 additions & 2 deletions nanomaps-library/src/net/rcode/nanomaps/MapTileView.java
Expand Up @@ -78,10 +78,10 @@ public Blitter(MapState mapState, Canvas canvas) {
public void handleTile(TileKey tile) {
Rect rect=new Rect();
mapTileToDisplay(mapState, tile, rect);
Log.d(Constants.LOG_TAG, "Blitter tile: " + tile + " -> " + rect);
//Log.d(Constants.LOG_TAG, "Blitter tile: " + tile + " -> " + rect);

Paint paint=new Paint();
paint.setColor(COLORS[tile.hashCode() % COLORS.length]);
paint.setColor(COLORS[Math.abs(tile.hashCode()) % COLORS.length]);
canvas.drawRoundRect(new RectF(rect), 10, 10, paint);

paint.setColor(Color.BLACK);
Expand Down
22 changes: 22 additions & 0 deletions nanomaps-sample/res/layout/nmsmallzoom.xml
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_width="fill_parent"
a:layout_height="fill_parent"
a:orientation="horizontal"
>

<Button
a:id="@id/nmbtnzoomout"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:background="@android:drawable/btn_minus"
/>
<Button
a:id="@id/nmbtnzoomin"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:background="@android:drawable/btn_plus"
/>

</LinearLayout>
6 changes: 6 additions & 0 deletions nanomaps-sample/res/values/ids.xml
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Pre-allocate ids that are used by user defined layouts -->
<item type="id" name="nmbtnzoomout" />
<item type="id" name="nmbtnzoomin" />
</resources>
Expand Up @@ -4,6 +4,7 @@
import net.rcode.nanomaps.MapState;
import net.rcode.nanomaps.MapSurface;
import net.rcode.nanomaps.MapTileView;
import net.rcode.nanomaps.sample.widgets.MapControls;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
Expand Down Expand Up @@ -31,6 +32,13 @@ public void onCreate(Bundle savedInstanceState) {
MapTileView mtv=new MapTileView(this, new CartesianMapTileSelector());
map.getBackgroundLayer().addView(mtv);

// Add zoom control
MapControls mapControls=new MapControls(map);
RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
map.addView(mapControls.createZoomControl(R.layout.nmsmallzoom), lp);

setContentView(rl);
}
}
@@ -0,0 +1,72 @@
package net.rcode.nanomaps.sample.widgets;

import net.rcode.nanomaps.MapSurface;
import net.rcode.nanomaps.sample.R;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;

/**
* Helper for instantiating map controls
* @author stella
*
*/
public class MapControls {
MapSurface map;
Context context;

public MapControls(MapSurface map) {
this.map=map;
this.context=map.getContext();
}

public View createZoomControl(int layoutResource) {
FrameLayout root=new FrameLayout(context);
View control=LayoutInflater.from(context).inflate(layoutResource, root);
configureZoomControl(control);
return root;
}

/**
* Given a view, hook it up with events so that it controls the
* zoom settings of the map.
* @param control
*/
public void configureZoomControl(View control) {
View btn;

// Zoom in button
btn=control.findViewById(R.id.nmbtnzoomin);
if (btn!=null) {
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("nanomaps", "Zoom In");
double current=map.getMapState().getLevel();
int max=map.getMapMaxLevel();
double next=Math.floor(current)+1;
if (next>max) next=max;
map.getMapState().setLevel(next, map.getWidth()/2, map.getHeight()/2);
}
});
}

// Zoom out button
btn=control.findViewById(R.id.nmbtnzoomout);
if (btn!=null) {
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("nanomaps", "Zoom Out");
double current=map.getMapState().getLevel();
int min=map.getMapMinLevel();
double next=Math.ceil(current)-1;
if (next<min) next=min;
map.getMapState().setLevel(next, map.getWidth()/2, map.getHeight()/2);
}
});
}
}
}

0 comments on commit 1f15653

Please sign in to comment.