forked from maplibre/maplibre-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add doc for annotation (maplibre#1135)
Co-authored-by: Hsieh Chin Fan <[email protected]> Co-authored-by: Bart Louwers <[email protected]> Co-authored-by: Bart Louwers <[email protected]>
- Loading branch information
1 parent
1438791
commit ca17d6b
Showing
7 changed files
with
302 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
185 changes: 185 additions & 0 deletions
185
...TestApp/src/main/java/org/maplibre/android/testapp/activity/annotation/JsonApiActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_json_api.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters