Skip to content

Commit 600540f

Browse files
ecgrebsarahsnow1
authored andcommitted
Bitmap markers (#340)
* Upgrades Tangram to version 0.5.1 * Adds basic bitmap marker support using drawable resource * Adds custom marker demo * Javadoc * Adds marker pick listener callback * Fix NPE * Markers should be removable * Invoke map controller marker pick only if listener has been set * Disable my location layer in custom marker demo
1 parent b32721b commit 600540f

File tree

19 files changed

+493
-13
lines changed

19 files changed

+493
-13
lines changed

core/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ group = GROUP
1919
version = VERSION_NAME
2020
project.archivesBaseName = POM_ARTIFACT_ID
2121

22-
ext.tangram_version = "0.5.0"
22+
ext.tangram_version = "0.5.1"
2323

2424
android {
2525
compileSdkVersion 25

core/src/main/java/com/mapzen/android/graphics/MapInitializer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.mapzen.android.core.MapzenManager;
44
import com.mapzen.android.graphics.model.BubbleWrapStyle;
55
import com.mapzen.android.graphics.model.MapStyle;
6+
import com.mapzen.android.graphics.model.MarkerManager;
67
import com.mapzen.tangram.MapController;
78
import com.mapzen.tangram.SceneUpdate;
89

@@ -92,7 +93,8 @@ private void loadMap(final MapView mapView, String sceneFile, final OnMapReadyCa
9293
mapController.setHttpHandler(tileHttpHandler);
9394
callback.onMapReady(
9495
new MapzenMap(mapView, mapController, new OverlayManager(mapView, mapController,
95-
mapDataManager, mapStateManager), mapStateManager, new LabelPickHandler(mapView)));
96+
mapDataManager, mapStateManager), mapStateManager, new LabelPickHandler(mapView),
97+
new MarkerManager(mapController)));
9698
}
9799
}, sceneFile, sceneUpdates);
98100
}

core/src/main/java/com/mapzen/android/graphics/MapzenMap.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package com.mapzen.android.graphics;
22

3+
import com.mapzen.android.graphics.model.BitmapMarker;
34
import com.mapzen.android.graphics.model.CameraType;
45
import com.mapzen.android.graphics.model.EaseType;
56
import com.mapzen.android.graphics.model.MapStyle;
67
import com.mapzen.android.graphics.model.Marker;
8+
import com.mapzen.android.graphics.model.MarkerManager;
9+
import com.mapzen.android.graphics.model.MarkerOptions;
710
import com.mapzen.android.graphics.model.Polygon;
811
import com.mapzen.android.graphics.model.Polyline;
912
import com.mapzen.tangram.LngLat;
1013
import com.mapzen.tangram.MapController;
1114
import com.mapzen.tangram.MapData;
15+
import com.mapzen.tangram.MarkerPickResult;
1216
import com.mapzen.tangram.SceneUpdate;
1317
import com.mapzen.tangram.TouchInput;
1418

@@ -36,9 +40,11 @@ public class MapzenMap {
3640
private final OverlayManager overlayManager;
3741
private final MapStateManager mapStateManager;
3842
private final LabelPickHandler labelPickHandler;
43+
private final MarkerManager markerManager;
3944

4045
boolean pickFeatureOnSingleTapConfirmed = false;
4146
boolean pickLabelOnSingleTapConfirmed = false;
47+
boolean pickMarkerOnSingleTapConfirmed = false;
4248

4349
private TouchInput.TapResponder internalTapResponder = new TouchInput.TapResponder() {
4450
@Override public boolean onSingleTapUp(float x, float y) {
@@ -58,6 +64,9 @@ public class MapzenMap {
5864
if (pickLabelOnSingleTapConfirmed) {
5965
mapController.pickLabel(x, y);
6066
}
67+
if (pickMarkerOnSingleTapConfirmed) {
68+
mapController.pickMarker(x, y);
69+
}
6170
return false;
6271
}
6372
};
@@ -130,12 +139,14 @@ public boolean onRotate(float x, float y, float rotation) {
130139
* Creates a new map based on the given {@link MapView} and {@link MapController}.
131140
*/
132141
MapzenMap(MapView mapView, MapController mapController, OverlayManager overlayManager,
133-
MapStateManager mapStateManager, LabelPickHandler labelPickHandler) {
142+
MapStateManager mapStateManager, LabelPickHandler labelPickHandler,
143+
MarkerManager markerManager) {
134144
this.mapView = mapView;
135145
this.mapController = mapController;
136146
this.overlayManager = overlayManager;
137147
this.mapStateManager = mapStateManager;
138148
this.labelPickHandler = labelPickHandler;
149+
this.markerManager = markerManager;
139150
mapView.setMapzenMap(this);
140151
mapController.setPanResponder(internalPanResponder);
141152
mapController.setRotateResponder(internalRotateResponder);
@@ -611,6 +622,29 @@ public void setLabelPickListener(final LabelPickListener listener) {
611622
mapController.setTapResponder(internalTapResponder);
612623
}
613624

625+
/**
626+
* Set a listener for marker pick events.
627+
*
628+
* @param listener Listener to receive callback when markers are selected.
629+
*/
630+
public void setMarkerPickListener(final MarkerPickListener listener) {
631+
mapController.setMarkerPickListener(new MapController.MarkerPickListener() {
632+
@Override
633+
public void onMarkerPick(final MarkerPickResult markerPickResult, final float positionX,
634+
final float positionY) {
635+
mapView.post(new Runnable() {
636+
@Override public void run() {
637+
if (markerPickResult != null) {
638+
listener.onMarkerPick(new BitmapMarker(markerManager, markerPickResult.getMarker()));
639+
}
640+
}
641+
});
642+
}
643+
});
644+
pickMarkerOnSingleTapConfirmed = (listener != null);
645+
mapController.setTapResponder(internalTapResponder);
646+
}
647+
614648
private void postFeaturePickRunnable(final Map<String, String> properties, final float positionX,
615649
final float positionY, final FeaturePickListener listener) {
616650
mapView.post(new Runnable() {
@@ -843,4 +877,14 @@ void onDestroy() {
843877
mapStateManager.setRotation(mapController.getRotation());
844878
mapStateManager.setTilt(mapController.getTilt());
845879
}
880+
881+
/**
882+
* Adds a custom bitmap marker to the map.
883+
*
884+
* @param markerOptions options used to define marker appearance.
885+
* @return a new bitmap marker instance.
886+
*/
887+
public BitmapMarker addBitmapMarker(MarkerOptions markerOptions) {
888+
return markerManager.addMarker(markerOptions);
889+
}
846890
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.mapzen.android.graphics;
2+
3+
import com.mapzen.android.graphics.model.BitmapMarker;
4+
5+
/**
6+
* Listener invoked when a marker on the map is selected.
7+
*/
8+
public interface MarkerPickListener {
9+
/**
10+
* Receives information about markers found in a call to {@link
11+
* com.mapzen.tangram.MapController#pickMarker(float, float)} (float, float)}.
12+
*/
13+
void onMarkerPick(BitmapMarker marker);
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.mapzen.android.graphics.model;
2+
3+
import com.mapzen.tangram.Marker;
4+
5+
/**
6+
* Dynamic marker overlay constructed using a local bitmap.
7+
*/
8+
public class BitmapMarker {
9+
private final MarkerManager markerManager;
10+
private final Marker tangramMarker;
11+
12+
/**
13+
* Constructor that wraps a Tangram marker.
14+
*
15+
* @param tangramMarker the underlying Tangram marker object.
16+
*/
17+
public BitmapMarker(MarkerManager markerManager, Marker tangramMarker) {
18+
this.markerManager = markerManager;
19+
this.tangramMarker = tangramMarker;
20+
}
21+
22+
/**
23+
* Removes this marker from the map. After a marker has been removed, the behavior of all its
24+
* methods is undefined.
25+
*/
26+
public void remove() {
27+
markerManager.removeMarker(tangramMarker);
28+
}
29+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.mapzen.android.graphics.model;
2+
3+
import com.mapzen.tangram.MapController;
4+
import com.mapzen.tangram.Marker;
5+
6+
/**
7+
* Manages {@link BitmapMarker} instances on the map.
8+
*/
9+
public class MarkerManager {
10+
private final MapController mapController;
11+
12+
/**
13+
* Constructor.
14+
*
15+
* @param mapController Tangram map controller used to generate markers.
16+
*/
17+
public MarkerManager(MapController mapController) {
18+
this.mapController = mapController;
19+
}
20+
21+
/**
22+
* Adds a new marker to the map.
23+
*
24+
* @param markerOptions options that define the appearance of the marker.
25+
* @return a new bitmap marker wrapper for the Tangram marker object.
26+
*/
27+
public BitmapMarker addMarker(MarkerOptions markerOptions) {
28+
final Marker marker = mapController.addMarker();
29+
marker.setPoint(markerOptions.getPosition());
30+
marker.setDrawable(markerOptions.getIcon());
31+
marker.setStylingFromString(markerOptions.getStyle());
32+
return new BitmapMarker(this, marker);
33+
}
34+
35+
/**
36+
* Removes a marker from the map.
37+
*
38+
* @param marker Tangram marker to be removed.
39+
*/
40+
public void removeMarker(Marker marker) {
41+
mapController.removeMarker(marker);
42+
}
43+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.mapzen.android.graphics.model;
2+
3+
import com.mapzen.R;
4+
import com.mapzen.tangram.LngLat;
5+
6+
/**
7+
* Defines options for a {@link BitmapMarker}.
8+
*/
9+
public class MarkerOptions {
10+
private static final LngLat DEFAULT_POSITION = new LngLat(-73.985428, 40.748817);
11+
private static final int DEFAULT_DRAWABLE = R.drawable.mapzen;
12+
private static final String DEFAULT_STYLE = "{ style: 'points', color: 'white',"
13+
+ "size: [50px, 50px], collide: false, interactive: true }";
14+
15+
private LngLat position = DEFAULT_POSITION;
16+
private int resId = DEFAULT_DRAWABLE;
17+
private String style = DEFAULT_STYLE;
18+
19+
// Setters
20+
21+
/**
22+
* Set the marker position.
23+
*
24+
* @param position coordinate to display the marker.
25+
* @return this marker options instance.
26+
*/
27+
public MarkerOptions position(LngLat position) {
28+
this.position = position;
29+
return this;
30+
}
31+
32+
/**
33+
* Set the marker icon resource ID.
34+
*
35+
* @param resId drawable resource ID for the marker to display.
36+
* @return this marker options instance.
37+
*/
38+
public MarkerOptions icon(int resId) {
39+
this.resId = resId;
40+
return this;
41+
}
42+
43+
/**
44+
* Set the marker icon style string.
45+
*
46+
* @param style Tangram style string used to define the marker appearance.
47+
* @return this marker options instance.
48+
*/
49+
public MarkerOptions style(String style) {
50+
this.style = style;
51+
return this;
52+
}
53+
54+
// Getters
55+
56+
public LngLat getPosition() {
57+
return position;
58+
}
59+
60+
public int getIcon() {
61+
return resId;
62+
}
63+
64+
public String getStyle() {
65+
return style;
66+
}
67+
}

core/src/main/res/drawable/mapzen.png

25.9 KB
Loading

core/src/test/java/com/mapzen/android/graphics/MapzenMapTest.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.mapzen.android.graphics;
22

3+
import com.mapzen.android.graphics.model.BitmapMarker;
34
import com.mapzen.android.graphics.model.CameraType;
45
import com.mapzen.android.graphics.model.EaseType;
56
import com.mapzen.android.graphics.model.Marker;
7+
import com.mapzen.android.graphics.model.MarkerManager;
68
import com.mapzen.android.graphics.model.Polygon;
79
import com.mapzen.android.graphics.model.Polyline;
810
import com.mapzen.tangram.LabelPickResult;
@@ -46,13 +48,17 @@ public class MapzenMapTest {
4648
private OverlayManager overlayManager;
4749
private LabelPickHandler labelPickHandler;
4850
private MapStateManager mapStateManager;
51+
private MarkerManager markerManager;
4952

5053
@Before public void setUp() throws Exception {
5154
mapView = new TestMapView();
5255
mapController = mock(TestMapController.class);
5356
doCallRealMethod().when(mapController)
5457
.setFeaturePickListener(any(MapController.FeaturePickListener.class));
5558
doCallRealMethod().when(mapController).pickFeature(anyFloat(), anyFloat());
59+
doCallRealMethod().when(mapController)
60+
.setMarkerPickListener(any(MapController.MarkerPickListener.class));
61+
doCallRealMethod().when(mapController).pickMarker(anyFloat(), anyFloat());
5662
doCallRealMethod().when(mapController).queueSceneUpdate(any(SceneUpdate.class));
5763
doCallRealMethod().when(mapController).getSceneUpdate();
5864
doCallRealMethod().when(mapController).setPosition(any(LngLat.class));
@@ -66,7 +72,9 @@ public class MapzenMapTest {
6672
overlayManager = mock(OverlayManager.class);
6773
mapStateManager = new MapStateManager();
6874
labelPickHandler = new LabelPickHandler(mapView);
69-
map = new MapzenMap(mapView, mapController, overlayManager, mapStateManager, labelPickHandler);
75+
markerManager = new MarkerManager(mapController);
76+
map = new MapzenMap(mapView, mapController, overlayManager, mapStateManager, labelPickHandler,
77+
markerManager);
7078
}
7179

7280
@Test public void shouldNotBeNull() throws Exception {
@@ -473,7 +481,7 @@ public class MapzenMapTest {
473481
verify(overlayManager).clearTransitRouteLine();
474482
}
475483

476-
@Test public void setFeaturePickListener_shouldInvokeFeatureListener() {
484+
@Test public void setFeaturePickListener_shouldInvokeFeatureListener() throws Exception {
477485
TestFeaturePickListener listener = new TestFeaturePickListener();
478486
map.setFeaturePickListener(listener);
479487
mapController.pickFeature(0, 0);
@@ -487,6 +495,20 @@ public class MapzenMapTest {
487495
assertThat(mapView.getAction()).isNotNull();
488496
}
489497

498+
@Test public void setMarkerPickListener_shouldInvokeMarkerListener() throws Exception {
499+
TestMarkerPickListener listener = new TestMarkerPickListener();
500+
map.setMarkerPickListener(listener);
501+
mapController.pickMarker(0, 0);
502+
assertThat(listener.picked).isTrue();
503+
}
504+
505+
@Test public void setMarkerPickListener_shouldInvokeCallbackOnMainThread() throws Exception {
506+
TestMarkerPickListener listener = new TestMarkerPickListener();
507+
map.setMarkerPickListener(listener);
508+
mapController.pickMarker(0, 0);
509+
assertThat(mapView.getAction()).isNotNull();
510+
}
511+
490512
@Test public void setLabelPickListener_shouldInvokeLabelListener() {
491513
TestLabelPickListener listener = new TestLabelPickListener();
492514
map.setLabelPickListener(listener);
@@ -581,6 +603,16 @@ public void onFeaturePick(Map<String, String> properties, float positionX, float
581603
}
582604
}
583605

606+
private class TestMarkerPickListener implements MarkerPickListener {
607+
608+
boolean picked = false;
609+
610+
@Override
611+
public void onMarkerPick(BitmapMarker marker) {
612+
picked = true;
613+
}
614+
}
615+
584616
private class TestLabelPickListener implements LabelPickListener {
585617

586618
boolean picked = false;

0 commit comments

Comments
 (0)