Skip to content

Commit 72c0788

Browse files
committed
docs
1 parent b797283 commit 72c0788

6 files changed

Lines changed: 1037 additions & 16 deletions

File tree

platform/android/docs/annotations/add-markers.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,141 @@ This example demonstrates how you can add markers in bulk.
1212
[//]: # (</div>)
1313

1414
```kotlin title="BulkMarkerActivity.kt"
15-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/BulkMarkerActivity.kt"
15+
class BulkMarkerActivity : AppCompatActivity(), OnItemSelectedListener {
16+
private lateinit var maplibreMap: MapLibreMap
17+
private lateinit var mapView: MapView
18+
private var locations: List<LatLng>? = null
19+
private var progressDialog: ProgressDialog? = null
20+
override fun onCreate(savedInstanceState: Bundle?) {
21+
super.onCreate(savedInstanceState)
22+
setContentView(R.layout.activity_marker_bulk)
23+
mapView = findViewById(R.id.mapView)
24+
mapView.onCreate(savedInstanceState)
25+
mapView.getMapAsync { initMap(it) }
26+
}
27+
28+
private fun initMap(maplibreMap: MapLibreMap) {
29+
this.maplibreMap = maplibreMap
30+
maplibreMap.setStyle(TestStyles.getPredefinedStyleWithFallback("Streets"))
31+
}
32+
33+
override fun onCreateOptionsMenu(menu: Menu): Boolean {
34+
val spinnerAdapter = ArrayAdapter.createFromResource(
35+
this,
36+
R.array.bulk_marker_list,
37+
android.R.layout.simple_spinner_item
38+
)
39+
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
40+
menuInflater.inflate(R.menu.menu_bulk_marker, menu)
41+
val item = menu.findItem(R.id.spinner)
42+
val spinner = item.actionView as Spinner
43+
spinner.adapter = spinnerAdapter
44+
spinner.onItemSelectedListener = this@BulkMarkerActivity
45+
return true
46+
}
47+
48+
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
49+
val amount = Integer.valueOf(resources.getStringArray(R.array.bulk_marker_list)[position])
50+
if (locations == null) {
51+
progressDialog = ProgressDialog.show(this, "Loading", "Fetching markers", false)
52+
lifecycleScope.launch(Dispatchers.IO) {
53+
locations = loadLocationTask(this@BulkMarkerActivity)
54+
withContext(Dispatchers.Main) {
55+
onLatLngListLoaded(locations, amount)
56+
}
57+
}
58+
} else {
59+
showMarkers(amount)
60+
}
61+
}
62+
63+
private fun onLatLngListLoaded(latLngs: List<LatLng>?, amount: Int) {
64+
progressDialog!!.hide()
65+
locations = latLngs
66+
showMarkers(amount)
67+
}
68+
69+
private fun showMarkers(amount: Int) {
70+
if (!this::maplibreMap.isInitialized || locations == null || mapView.isDestroyed) {
71+
return
72+
}
73+
maplibreMap.clear()
74+
showGlMarkers(min(amount, locations!!.size))
75+
}
76+
77+
private fun showGlMarkers(amount: Int) {
78+
val markerOptionsList: MutableList<MarkerOptions> = ArrayList()
79+
val formatter = DecimalFormat("#.#####")
80+
val random = Random()
81+
var randomIndex: Int
82+
for (i in 0 until amount) {
83+
randomIndex = random.nextInt(locations!!.size)
84+
val latLng = locations!![randomIndex]
85+
markerOptionsList.add(
86+
MarkerOptions()
87+
.position(latLng)
88+
.title(i.toString())
89+
.snippet(formatter.format(latLng.latitude) + "`, " + formatter.format(latLng.longitude))
90+
)
91+
}
92+
maplibreMap.addMarkers(markerOptionsList)
93+
}
94+
95+
override fun onNothingSelected(parent: AdapterView<*>?) {
96+
// nothing selected, nothing to do!
97+
}
98+
99+
override fun onStart() {
100+
super.onStart()
101+
mapView.onStart()
102+
}
103+
104+
override fun onResume() {
105+
super.onResume()
106+
mapView.onResume()
107+
}
108+
109+
override fun onPause() {
110+
super.onPause()
111+
mapView.onPause()
112+
}
113+
114+
override fun onStop() {
115+
super.onStop()
116+
mapView.onStop()
117+
}
118+
119+
override fun onSaveInstanceState(outState: Bundle) {
120+
super.onSaveInstanceState(outState)
121+
mapView.onSaveInstanceState(outState)
122+
}
123+
124+
override fun onDestroy() {
125+
super.onDestroy()
126+
if (progressDialog != null) {
127+
progressDialog!!.dismiss()
128+
}
129+
mapView.onDestroy()
130+
}
131+
132+
override fun onLowMemory() {
133+
super.onLowMemory()
134+
mapView.onLowMemory()
135+
}
136+
137+
private fun loadLocationTask(
138+
activity: BulkMarkerActivity,
139+
) : List<LatLng>? {
140+
try {
141+
val json = GeoParseUtil.loadStringFromAssets(
142+
activity.applicationContext,
143+
"points.geojson"
144+
)
145+
return GeoParseUtil.parseGeoJsonCoordinates(json)
146+
} catch (exception: IOException) {
147+
Timber.e(exception, "Could not add markers")
148+
}
149+
return null
150+
}
151+
}
16152
```

platform/android/docs/annotations/marker-annotations.md

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,62 @@ Then add markers to the map with GeoJSON:
3838
3. In `JsonApiActivity` we add a new variable for `MapLibreMap`.
3939
It is used to add annotations to the map instance.
4040
```kotlin
41-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt:top"
41+
class JsonApiActivity : AppCompatActivity() {
42+
43+
// Declare a variable for MapView
44+
private lateinit var mapView: MapView
45+
46+
// Declare a variable for MapLibreMap
47+
private lateinit var maplibreMap: MapLibreMap}
4248
```
4349

4450
4. Call `mapview.getMapSync()` in order to get a `MapLibreMap` object.
4551
After `maplibreMap` is assigned, call the `getEarthQuakeDataFromUSGS()` method
4652
to make a HTTP request and transform data into the map annotations.
4753
```kotlin
48-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt:mapAsync"
54+
mapView.getMapAsync { map ->
55+
maplibreMap = map
56+
57+
maplibreMap.setStyle("https://demotiles.maplibre.org/style.json")
58+
59+
// Fetch data from USGS
60+
getEarthQuakeDataFromUSGS()
61+
}
4962
```
5063

5164
5. Define a function `getEarthQuakeDataFromUSGS()` to fetch GeoJSON data from a public API.
5265
If we successfully get the response, call `addMarkersToMap()` on the UI thread.
5366
```kotlin
54-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt:getEarthquakes"
67+
// Get Earthquake data from usgs.gov, read API doc at:
68+
// https://earthquake.usgs.gov/fdsnws/event/1/
69+
private fun getEarthQuakeDataFromUSGS() {
70+
val url = "https://earthquake.usgs.gov/fdsnws/event/1/query".toHttpUrl().newBuilder()
71+
.addQueryParameter("format", "geojson")
72+
.addQueryParameter("starttime", "2022-01-01")
73+
.addQueryParameter("endtime", "2022-12-31")
74+
.addQueryParameter("minmagnitude", "5.8")
75+
.addQueryParameter("latitude", "24")
76+
.addQueryParameter("longitude", "121")
77+
.addQueryParameter("maxradius", "1.5")
78+
.build()
79+
val request: Request = Request.Builder().url(url).build()
80+
81+
OkHttpClient().newCall(request).enqueue(object : Callback {
82+
override fun onFailure(call: Call, e: IOException) {
83+
Toast.makeText(this@JsonApiActivity, "Fail to fetch data", Toast.LENGTH_SHORT)
84+
.show()
85+
}
86+
87+
override fun onResponse(call: Call, response: Response) {
88+
val featureCollection = response.body?.string()
89+
?.let(FeatureCollection::fromJson)
90+
?: return
91+
// If FeatureCollection in response is not null
92+
// Then add markers to map
93+
runOnUiThread { addMarkersToMap(featureCollection) }
94+
}
95+
})
96+
}
5597
```
5698

5799
6. Now it is time to add markers into the map.
@@ -60,7 +102,58 @@ Then add markers to the map with GeoJSON:
60102
- If the magnitude of an earthquake is bigger than 6.0, we use the red icon. Otherwise, we use the blue one.
61103
- Finally, move the camera to the bounds of the newly added markers
62104
```kotlin
63-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt:addMarkers"
105+
private fun addMarkersToMap(data: FeatureCollection) {
106+
val bounds = mutableListOf<LatLng>()
107+
108+
// Get bitmaps for marker icon
109+
val infoIconDrawable = ResourcesCompat.getDrawable(
110+
this.resources,
111+
// Intentionally specify package name
112+
// This makes copy from another project easier
113+
org.maplibre.android.R.drawable.maplibre_info_icon_default,
114+
theme
115+
)!!
116+
val bitmapBlue = infoIconDrawable.toBitmap()
117+
val bitmapRed = infoIconDrawable
118+
.mutate()
119+
.apply { setTint(Color.RED) }
120+
.toBitmap()
121+
122+
// Add symbol for each point feature
123+
data.features()?.forEach { feature ->
124+
val geometry = feature.geometry()?.toJson() ?: return@forEach
125+
val point = Point.fromJson(geometry) ?: return@forEach
126+
val latLng = LatLng(point.latitude(), point.longitude())
127+
bounds.add(latLng)
128+
129+
// Contents in InfoWindow of each marker
130+
val title = feature.getStringProperty("title")
131+
val epochTime = feature.getNumberProperty("time")
132+
val dateString = SimpleDateFormat("yyyy/MM/dd HH:mm", Locale.TAIWAN).format(epochTime)
133+
134+
// If magnitude > 6.0, show marker with red icon. If not, show blue icon instead
135+
val mag = feature.getNumberProperty("mag")
136+
val icon = IconFactory.getInstance(this)
137+
.fromBitmap(if (mag.toFloat() > 6.0) bitmapRed else bitmapBlue)
138+
139+
// Use MarkerOptions and addMarker() to add a new marker in map
140+
val markerOptions = MarkerOptions()
141+
.position(latLng)
142+
.title(dateString)
143+
.snippet(title)
144+
.icon(icon)
145+
maplibreMap.addMarker(markerOptions)
146+
}
147+
148+
// Move camera to newly added annotations
149+
maplibreMap.getCameraForLatLngBounds(LatLngBounds.fromLatLngs(bounds))?.let {
150+
val newCameraPosition = CameraPosition.Builder()
151+
.target(it.target)
152+
.zoom(it.zoom - 0.5)
153+
.build()
154+
maplibreMap.cameraPosition = newCameraPosition
155+
}
156+
}
64157
```
65158

66159
[//]: # (7. Here is the final result. For the full contents of `JsonApiActivity`, please visit source code of our [Test App].)
@@ -83,4 +176,4 @@ Then add markers to the map with GeoJSON:
83176
[mvn]: https://mvnrepository.com/artifact/org.maplibre.gl/android-plugin-annotation-v9
84177
[Android Developer Documentation]: https://developer.android.com/topic/libraries/architecture/coroutines
85178
[MarkerOptions]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20-android/org.maplibre.android.annotations/-marker-options/index.html
86-
[Test App]: https://github.com/maplibre/maplibre-native/tree/main/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt
179+
[Test App]: https://github.com/MapMetrics/mapmetrics-native-sdk/tree/main/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt

platform/android/docs/camera/animation-types.md

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ This example showcases the different animation types.
1313
The `MapLibreMap.moveCamera` method jumps to the camera position provided.
1414

1515
```kotlin
16-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/camera/CameraAnimationTypeActivity.kt:moveCamera"
16+
val cameraPosition =
17+
CameraPosition.Builder()
18+
.target(nextLatLng)
19+
.zoom(14.0)
20+
.tilt(30.0)
21+
.tilt(0.0)
22+
.build()
23+
maplibreMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
1724
```
1825

1926
[//]: # (<figure markdown="span">)
@@ -31,7 +38,18 @@ The `MapLibreMap.moveCamera` method jumps to the camera position provided.
3138
The `MapLibreMap.moveCamera` eases to the camera position provided (with constant ground speed).
3239

3340
```kotlin
34-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/camera/CameraAnimationTypeActivity.kt:easeCamera"
41+
val cameraPosition =
42+
CameraPosition.Builder()
43+
.target(nextLatLng)
44+
.zoom(15.0)
45+
.bearing(180.0)
46+
.tilt(30.0)
47+
.build()
48+
maplibreMap.easeCamera(
49+
CameraUpdateFactory.newCameraPosition(cameraPosition),
50+
7500,
51+
callback
52+
)
3553
```
3654

3755
[//]: # (<figure markdown="span">)
@@ -52,7 +70,13 @@ The `MapLibreMap.animateCamera` uses a powered flight animation move to the came
5270
[^1]: The implementation is based on Van Wijk, Jarke J.; Nuij, Wim A. A. “Smooth and efficient zooming and panning.” INFOVIS ’03. pp. 15–22. [https://www.win.tue.nl/~vanwijk/zoompan.pdf#page=5](https://www.win.tue.nl/~vanwijk/zoompan.pdf#page=5)
5371

5472
```kotlin
55-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/camera/CameraAnimationTypeActivity.kt:animateCamera"
73+
val cameraPosition =
74+
CameraPosition.Builder().target(nextLatLng).bearing(270.0).tilt(20.0).build()
75+
maplibreMap.animateCamera(
76+
CameraUpdateFactory.newCameraPosition(cameraPosition),
77+
7500,
78+
callback
79+
)
5680
```
5781

5882
[//]: # (<figure markdown="span">)
@@ -70,5 +94,26 @@ The `MapLibreMap.animateCamera` uses a powered flight animation move to the came
7094
In the previous section a `CancellableCallback` was passed to the last two animation methods. This callback shows a toast message when the animation is cancelled or when it is finished.
7195

7296
```kotlin
73-
--8<-- "MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/camera/CameraAnimationTypeActivity.kt:callback"
97+
private val callback: CancelableCallback =
98+
object : CancelableCallback {
99+
override fun onCancel() {
100+
Timber.i("Duration onCancel Callback called.")
101+
Toast.makeText(
102+
applicationContext,
103+
"Ease onCancel Callback called.",
104+
Toast.LENGTH_LONG
105+
)
106+
.show()
107+
}
108+
109+
override fun onFinish() {
110+
Timber.i("Duration onFinish Callback called.")
111+
Toast.makeText(
112+
applicationContext,
113+
"Ease onFinish Callback called.",
114+
Toast.LENGTH_LONG
115+
)
116+
.show()
117+
}
118+
}
74119
```

0 commit comments

Comments
 (0)