1
public class PolygonClusterActivity extends AppCompatActivity implements OnMapReadyCallback, NextbillionMap.OnMapClickListener, View.OnClickListener {
3
private static final String TAG = "PolygonClusterActivity";
4
public static final String SOURCE_ID = "bus_stop";
5
public static final String SOURCE_ID_CLUSTER = "bus_stop_cluster";
6
public static final String URL_BUS_ROUTES = "https://raw.githubusercontent.com/cheeaun/busrouter-sg/master/data/2/bus-stops.geojson";
7
public static final String LAYER_ID = "stops_layer";
8
private static final String TAXI = "taxi";
9
private ImageView backBtn;
10
private MapView mapView;
11
private NextbillionMap nextbillionMap;
13
private FloatingActionButton styleFab;
14
private FloatingActionButton routeFab;
16
private CircleLayer layer;
17
private GeoJsonSource source;
19
private int currentStyleIndex = 0;
20
private boolean isLoadingStyle = true;
23
protected void onCreate(Bundle savedInstanceState) {
24
super.onCreate(savedInstanceState);
25
setContentView(R.layout.activity_polygon_cluster);
26
mapView = findViewById(R.id.map_view);
27
backBtn = findViewById(R.id.back_ib);
28
mapView.onCreate(savedInstanceState);
29
mapView.getMapAsync(this);
31
backBtn.setOnClickListener(new View.OnClickListener() {
33
public void onClick(View v) {
40
public void onMapReady(@NonNull NextbillionMap nbMap) {
41
this.nextbillionMap = nbMap;
42
mapView.addOnDidFinishLoadingStyleListener(() -> {
43
Style style = nextbillionMap.getStyle();
44
style.addImage(TAXI,(BitmapDrawable)getResources().getDrawable(R.mipmap.beat_taxi));
45
addBusStopSource(style);
46
addBusStopCircleLayer(style);
47
initFloatingActionButtons();
48
isLoadingStyle = false;
53
public boolean onMapClick(@NonNull LatLng latLng) {
59
private void addBusStopSource(Style style) {
61
source = new GeoJsonSource(SOURCE_ID, new URI(URL_BUS_ROUTES));
62
} catch (URISyntaxException exception) {
63
Log.e(TAG, "That's not an url... ");
65
style.addSource(source);
68
private void addBusStopCircleLayer(Style style) {
69
layer = new CircleLayer(LAYER_ID, SOURCE_ID);
71
circleColor(Color.parseColor("#FF0000")),
74
style.addLayerBelow(layer, "waterway-label");
77
private void initFloatingActionButtons() {
78
routeFab = findViewById(R.id.fab_route);
79
routeFab.setColorFilter(ContextCompat.getColor(PolygonClusterActivity.this, R.color.purple_200));
80
routeFab.setOnClickListener(PolygonClusterActivity.this);
82
styleFab = findViewById(R.id.fab_style);
83
styleFab.setOnClickListener(PolygonClusterActivity.this);
87
public void onClick(View view) {
92
if (view.getId() == R.id.fab_route) {
94
} else if (view.getId() == R.id.fab_style) {
99
private void showBusCluster() {
102
addClusteredSource();
105
private void removeOldSource() {
106
nextbillionMap.getStyle().removeSource(SOURCE_ID);
107
nextbillionMap.getStyle().removeLayer(LAYER_ID);
110
private void addClusteredSource() {
112
nextbillionMap.getStyle().addSource(
113
new GeoJsonSource(SOURCE_ID_CLUSTER,
114
new URI(URL_BUS_ROUTES),
117
.withClusterMaxZoom(14)
118
.withClusterRadius(50)
121
} catch (URISyntaxException malformedUrlException) {
122
Log.e(TAG, "That's not an url... ");
125
// Add unclustered layer
126
int[][] layers = new int[][]{
127
new int[]{150, ResourcesCompat.getColor(getResources(), R.color.purple_200, getTheme())},
128
new int[]{20, ResourcesCompat.getColor(getResources(), R.color.colorAccent, getTheme())},
129
new int[]{0, ResourcesCompat.getColor(getResources(), R.color.color_4158ce, getTheme())}
132
SymbolLayer unclustered = new SymbolLayer("unclustered-points", SOURCE_ID_CLUSTER);
133
unclustered.setProperties(
137
nextbillionMap.getStyle().addLayer(unclustered);
139
for (int i = 0; i < layers.length; i++) {
140
// Add some nice circles
141
CircleLayer circles = new CircleLayer("cluster-" + i, SOURCE_ID_CLUSTER);
142
circles.setProperties(
143
circleColor(layers[i][1]),
147
Expression pointCount = toNumber(get("point_count"));
150
? all(has("point_count"),
151
gte(pointCount, literal(layers[i][0]))
152
) : all(has("point_count"),
153
gt(pointCount, literal(layers[i][0])),
154
lt(pointCount, literal(layers[i - 1][0]))
157
nextbillionMap.getStyle().addLayer(circles);
160
// Add the count labels
161
SymbolLayer count = new SymbolLayer("count", SOURCE_ID_CLUSTER);
163
textField(Expression.toString(get("point_count"))),
165
textColor(Color.WHITE),
166
textIgnorePlacement(true),
167
textAllowOverlap(true)
169
nextbillionMap.getStyle().addLayer(count);
172
private void removeFabs() {
173
routeFab.setVisibility(View.GONE);
174
styleFab.setVisibility(View.GONE);
177
private void changeMapStyle() {
178
isLoadingStyle = true;
183
private void removeBusStop() {
184
nextbillionMap.getStyle().removeLayer(layer);
185
nextbillionMap.getStyle().removeSource(source);
188
private void loadNewStyle() {
189
nextbillionMap.setStyle(new Style.Builder().fromUri(getNextStyle()));
192
private void addBusStop() {
193
nextbillionMap.getStyle().addLayer(layer);
194
nextbillionMap.getStyle().addSource(source);
197
private String getNextStyle() {
199
if (currentStyleIndex == Data.STYLES.length) {
200
currentStyleIndex = 0;
202
return Data.STYLES[currentStyleIndex];
206
///////////////////////////////////////////////////////////////////////////
208
///////////////////////////////////////////////////////////////////////////
211
protected void onStart() {
217
protected void onResume() {
223
protected void onPause() {
229
protected void onStop() {
235
protected void onSaveInstanceState(@NonNull Bundle outState) {
236
super.onSaveInstanceState(outState);
237
mapView.onSaveInstanceState(outState);
241
protected void onDestroy() {
247
public void onLowMemory() {
249
mapView.onLowMemory();
252
private static class Data {
253
private static final String[] STYLES = new String[]{
259
Style.SATELLITE_STREETS