Add doc for annotation (#1135)
Co-authored-by: Hsieh Chin Fan <pham@topo.tw> Co-authored-by: Bart Louwers <bart@emeel.net> Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
@@ -12,4 +12,5 @@
|
||||
|
||||
- [MapLibre Native for Android](./android/README.md)
|
||||
- [Quickstart](./android/getting-started-guide.md)
|
||||
- [Annotation: Marker](./android/annotation-guide.md)
|
||||
- [Location Component](./android/location-component-guide.md)
|
||||
|
||||
89
docs/mdbook/src/android/annotation-guide.md
Normal file
89
docs/mdbook/src/android/annotation-guide.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Annotation: Marker
|
||||
|
||||
This guide will show you how to add Markers in the map.
|
||||
|
||||
`Annotation` is an overlay on top of a Map. In package
|
||||
`com.mapbox.mapboxsdk.annotations`, it has the following subclasses:
|
||||
1. [Marker]
|
||||
2. [Polyline]
|
||||
3. [Polygon]
|
||||
|
||||
A Marker shows an icon image at a geographical location. By default, marker uses
|
||||
a [provided image] as its icon.
|
||||
|
||||
![marker image]
|
||||
|
||||
Or, the icon can be customized using [IconFactory] to generate an
|
||||
[Icon] using a provided image.
|
||||
|
||||
For more customization, please read the documentation about [MarkerOptions].
|
||||
|
||||
In this showcase, we continue the code from the [Quickstart],
|
||||
rename Activity into `JsonApiActivity`,
|
||||
and pull the GeoJSON data from a free and public API.
|
||||
Then add markers to the map with GeoJSON:
|
||||
|
||||
1. In your module Gradle file (usually `<project>/<app-module>/build.gradle`), add
|
||||
`okhttp` to simplify code for making HTTP requests.
|
||||
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
...
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
2. Sync your Android project the with Gradle files.
|
||||
|
||||
3. In `JsonApiActivity` we add a new variable for `MapboxMap`.
|
||||
It is used to add annotations to the map instance.
|
||||
|
||||
```kotlin
|
||||
{{#include ../../../../platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/JsonApiActivity.kt:top}}
|
||||
```
|
||||
|
||||
4. Call `mapview.getMapSync()` in order to get a `MapboxMap` object.
|
||||
After `mapboxMap` is assigned, call the `getEarthQuakeDataFromUSGS()` method
|
||||
to make a HTTP request and transform data into the map annotations.
|
||||
|
||||
```kotlin
|
||||
{{#include ../../../../platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/JsonApiActivity.kt:mapAsync}}
|
||||
```
|
||||
|
||||
5. Define a function `getEarthQuakeDataFromUSGS()` to fetch GeoJSON data from a public API.
|
||||
If we successfully get the response, call `addMarkersToMap()` on the UI thread.
|
||||
|
||||
```kotlin
|
||||
{{#include ../../../../platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/JsonApiActivity.kt:getEarthquakes}}
|
||||
```
|
||||
|
||||
6. Now it is time to add markers into the map.
|
||||
- In the `addMarkersToMap()` method, we define two types of bitmap for the marker icon.
|
||||
- For each feature in the GeoJSON, add a marker with a snippet about earthquake details.
|
||||
- If the magnitude of an earthquake is bigger than 6.0, we use the red icon. Otherwise, we use the blue one.
|
||||
- Finally, move the camera to the bounds of the newly added markers
|
||||
|
||||
```kotlin
|
||||
{{#include ../../../../platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/JsonApiActivity.kt:addMarkers}}
|
||||
```
|
||||
|
||||
7. Here is the final result. For the full contents of `JsonApiActivity`, please visit source code of [Test APP]
|
||||
|
||||
<div style="align: center">
|
||||
<img src="https://github.com/maplibre/maplibre-native/assets/19887090/00446249-9b19-4a48-8a46-00d4c5a2f981" alt="Screenshot with the map in demotile style">
|
||||
</div>
|
||||
|
||||
[Marker]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-marker/index.html
|
||||
[provided image]: https://github.com/maplibre/maplibre-native/blob/main/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/maplibre_marker_icon_default.png
|
||||
[Polyline]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-polyline/index.html
|
||||
[Polygon]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-polygon/index.html
|
||||
[marker image]: https://raw.githubusercontent.com/maplibre/maplibre-native/main/test/fixtures/sprites/default_marker.png
|
||||
[IconFactory]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-icon-factory/index.html
|
||||
[Icon]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-icon/index.html
|
||||
[Quickstart]: ./getting-started-guide.md
|
||||
[mvn]: https://mvnrepository.com/artifact/org.maplibre.gl/android-plugin-annotation-v9
|
||||
[Android Developer Documentation]: https://developer.android.com/topic/libraries/architecture/coroutines
|
||||
[MarkerOptions]: https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20for%20-android/com.mapbox.mapboxsdk.annotations/-marker-options/index.html
|
||||
[Test App]: https://github.com/maplibre/maplibre-native/tree/main/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/JsonApiActivity.kt
|
||||
@@ -111,6 +111,19 @@
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.annotation.JsonApiActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:description="@string/description_add_makers_by_json_api"
|
||||
android:exported="true"
|
||||
android:label="@string/activity_json_api">
|
||||
<meta-data
|
||||
android:name="@string/category"
|
||||
android:value="@string/category_annotation" />
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.camera.CameraAnimationTypeActivity"
|
||||
android:description="@string/description_camera_animation_types"
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
package org.maplibre.android.testapp.activity.annotation
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.mapbox.geojson.FeatureCollection
|
||||
import com.mapbox.geojson.Point
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.maplibre.android.MapLibre
|
||||
import org.maplibre.android.annotations.IconFactory
|
||||
import org.maplibre.android.annotations.MarkerOptions
|
||||
import org.maplibre.android.camera.CameraPosition
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.geometry.LatLngBounds
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.testapp.R
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
/* ANCHOR: top */
|
||||
class JsonApiActivity : AppCompatActivity() {
|
||||
|
||||
// Declare a variable for MapView
|
||||
private lateinit var mapView: MapView
|
||||
|
||||
// Declare a variable for MapboxMap
|
||||
private lateinit var maplibreMap: MapLibreMap
|
||||
/* ANCHOR_END: top */
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// Init MapLibre
|
||||
MapLibre.getInstance(this)
|
||||
|
||||
// Init layout view
|
||||
setContentView(R.layout.activity_json_api)
|
||||
|
||||
// Init the MapView
|
||||
mapView = findViewById(R.id.mapView)
|
||||
|
||||
/* ANCHOR: mapAsync */
|
||||
mapView.getMapAsync { map ->
|
||||
maplibreMap = map
|
||||
|
||||
maplibreMap.setStyle("https://demotiles.maplibre.org/style.json")
|
||||
|
||||
// Fetch data from USGS
|
||||
getEarthQuakeDataFromUSGS()
|
||||
}
|
||||
/* ANCHOR_END: mapAsync */
|
||||
}
|
||||
|
||||
/* ANCHOR: getEarthquakes */
|
||||
// Get Earthquake data from usgs.gov, read API doc at:
|
||||
// https://earthquake.usgs.gov/fdsnws/event/1/
|
||||
private fun getEarthQuakeDataFromUSGS() {
|
||||
val url = "https://earthquake.usgs.gov/fdsnws/event/1/query".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("format", "geojson")
|
||||
.addQueryParameter("starttime", "2022-01-01")
|
||||
.addQueryParameter("endtime", "2022-12-31")
|
||||
.addQueryParameter("minmagnitude", "5.8")
|
||||
.addQueryParameter("latitude", "24")
|
||||
.addQueryParameter("longitude", "121")
|
||||
.addQueryParameter("maxradius", "1.5")
|
||||
.build()
|
||||
val request: Request = Request.Builder().url(url).build()
|
||||
|
||||
OkHttpClient().newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
Toast.makeText(this@JsonApiActivity, "Fail to fetch data", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val featureCollection = response.body?.string()
|
||||
?.let(FeatureCollection::fromJson)
|
||||
?: return
|
||||
// If FeatureCollection in response is not null
|
||||
// Then add markers to map
|
||||
runOnUiThread { addMarkersToMap(featureCollection) }
|
||||
}
|
||||
})
|
||||
}
|
||||
/* ANCHOR_END: getEarthquakes */
|
||||
|
||||
/* ANCHOR: addMarkers */
|
||||
private fun addMarkersToMap(data: FeatureCollection) {
|
||||
val bounds = mutableListOf<LatLng>()
|
||||
|
||||
// Get bitmaps for marker icon
|
||||
val infoIconDrawable = ResourcesCompat.getDrawable(
|
||||
this.resources,
|
||||
// Intentionally specify package name
|
||||
// This makes copy from another project easier
|
||||
org.maplibre.android.R.drawable.maplibre_info_icon_default,
|
||||
null
|
||||
)!!
|
||||
val bitmapBlue = infoIconDrawable.toBitmap()
|
||||
val bitmapRed = infoIconDrawable
|
||||
.mutate()
|
||||
.apply { setTint(Color.RED) }
|
||||
.toBitmap()
|
||||
|
||||
// Add symbol for each point feature
|
||||
data.features()?.forEach { feature ->
|
||||
val geometry = feature.geometry()?.toJson() ?: return@forEach
|
||||
val point = Point.fromJson(geometry) ?: return@forEach
|
||||
val latLng = LatLng(point.latitude(), point.longitude())
|
||||
bounds.add(latLng)
|
||||
|
||||
// Contents in InfoWindow of each marker
|
||||
val title = feature.getStringProperty("title")
|
||||
val epochTime = feature.getNumberProperty("time")
|
||||
val dateString = SimpleDateFormat("yyyy/MM/dd HH:mm", Locale.TAIWAN).format(epochTime)
|
||||
|
||||
// If magnitude > 6.0, show marker with red icon. If not, show blue icon instead
|
||||
val mag = feature.getNumberProperty("mag")
|
||||
val icon = IconFactory.getInstance(this)
|
||||
.fromBitmap(if (mag.toFloat() > 6.0) bitmapRed else bitmapBlue)
|
||||
|
||||
// Use MarkerOptions and addMarker() to add a new marker in map
|
||||
val markerOptions = MarkerOptions()
|
||||
.position(latLng)
|
||||
.title(dateString)
|
||||
.snippet(title)
|
||||
.icon(icon)
|
||||
maplibreMap.addMarker(markerOptions)
|
||||
}
|
||||
|
||||
// Move camera to newly added annotations
|
||||
maplibreMap.getCameraForLatLngBounds(LatLngBounds.fromLatLngs(bounds))?.let {
|
||||
val newCameraPosition = CameraPosition.Builder()
|
||||
.target(it.target)
|
||||
.zoom(it.zoom - 0.5)
|
||||
.build()
|
||||
maplibreMap.cameraPosition = newCameraPosition
|
||||
}
|
||||
}
|
||||
/* ANCHOR_END: addMarkers */
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
mapView.onStart()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mapView.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mapView.onPause()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
mapView.onStop()
|
||||
}
|
||||
|
||||
override fun onLowMemory() {
|
||||
super.onLowMemory()
|
||||
mapView.onLowMemory()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mapView.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
mapView.onSaveInstanceState(outState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.maplibre.android.maps.MapView
|
||||
android:id="@id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -8,6 +8,7 @@
|
||||
<string name="description_map_fragment_backstack">Showcase using a Map Fragment with a fragment backstack</string>
|
||||
<string name="description_multimap">Activity with multiple maps on screen</string>
|
||||
<string name="description_press_for_marker">Add marker to map on long press</string>
|
||||
<string name="description_add_makers_by_json_api">Use JSON API to add markers</string>
|
||||
<string name="description_camera_zoom">Different types of zoom methods</string>
|
||||
<string name="description_minmax_zoom">Configure a max and min zoomlevel</string>
|
||||
<string name="description_info_window">Learn how to handle the InfoWindow</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<string name="activity_polygon">Polygon</string>
|
||||
<string name="activity_press_for_marker">Press Map For Marker</string>
|
||||
<string name="activity_add_remove_markers">Zoom function with SymbolLayer</string>
|
||||
<string name="activity_json_api">Add Markers From JSON API</string>
|
||||
<string name="activity_info_window">Standard InfoWindow</string>
|
||||
<string name="activity_infowindow_adapter">Custom InfoWindow</string>
|
||||
<string name="activity_dynamic_infowindow_adapter">Custom Dynamic InfoWindow</string>
|
||||
|
||||
Reference in New Issue
Block a user