台灣圖霸 | Map8 Platform
歡迎使用 台灣圖霸 | Map8 Platform 地圖平台
- 歡迎試用我們的 台灣圖霸 (Map8 Platform) 地圖平台 API!! 請點此申請試用~
- 然後也歡迎您到我們的 官方 API Explorer 試用看看~
有任何技術疑難,或其他疑問,都歡迎您 跟我們聯絡 喔!!!
初始化地圖
- 範例說明:
- 設定地圖中心點
- 顯示使用者位置
- 旋轉地圖
- 2D 轉 3D 俯瞰視角
Example
public class SimpleMapViewActivity extends AppCompatActivity {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private MapboxMap mapboxMap;
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.03625, 121.54885))
.zoom(16)
.bearing(0)
.tilt(50)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
SimpleMapViewActivity.this.mapboxMap = mapboxMap;
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
enableLocationComponent(style);
}
});
}
});
setContentView(mapView);
}
@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
// Check if permissions are enabled and if not request
if (PermissionsManager.areLocationPermissionsGranted(this)) {
// Get an instance of the component
LocationComponent locationComponent = mapboxMap.getLocationComponent();
// Activate with options
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
// Enable to make component visible
locationComponent.setLocationComponentEnabled(true);
// Set the component's camera mode
locationComponent.setCameraMode(CameraMode.TRACKING);
// Set the component's render mode
locationComponent.setRenderMode(RenderMode.COMPASS);
}
}
// Add the mapView's own lifecycle methods to the activity's lifecycle methods
@SuppressWarnings( {"MissingPermission"})
@Override
public void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
攝影機視角移動地圖
- 範例說明:
- 點擊任一點以攝影機動畫移動地圖
- 顯示地圖標記 ( Marker )
- 點擊 Marker 顯示座標
- 圖示下載
Example
public class CameraAnimationActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private MapView mapView;
private MapboxMap mapboxMap;
private Marker theMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.03625, 121.54885))
.zoom(16)
.bearing(0)
.tilt(50)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
CameraAnimationActivity.this.mapboxMap = mapboxMap;
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
enableLocationComponent(style);
// Toast instructing user to tap on the map
Toast.makeText(CameraAnimationActivity.this, "Tap anywhere on the map", Toast.LENGTH_LONG).show();
mapboxMap.addOnMapClickListener(CameraAnimationActivity.this);
LocationComponent locationComponent = mapboxMap.getLocationComponent();
double currentLat = locationComponent.getLastKnownLocation().getLatitude();
double currentLong = locationComponent.getLastKnownLocation().getLongitude();
// Create an Icon object for the marker to use
IconFactory iconFactory = IconFactory.getInstance(CameraAnimationActivity.this);
Icon icon = iconFactory.fromResource(R.drawable.red_marker);
// Add the marker to the map
theMarker = mapboxMap.addMarker(new MarkerOptions()
.position(new LatLng(currentLat, currentLong))
.icon(icon));
mapboxMap.setOnMarkerClickListener(new MapboxMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(@NonNull Marker marker) {
// Show a toast with the title of the selected marker
Toast.makeText(CameraAnimationActivity.this, "座標:\n" + marker.getPosition().getLatitude() + ", " + marker.getPosition().getLongitude(), Toast.LENGTH_LONG).show();
return true;
}
});
}
});
}
});
setContentView(mapView);
}
@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
if (PermissionsManager.areLocationPermissionsGranted(this)) {
LocationComponent locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
locationComponent.setLocationComponentEnabled(true);
locationComponent.setCameraMode(CameraMode.TRACKING);
locationComponent.setRenderMode(RenderMode.COMPASS);
}
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
CameraPosition position = new CameraPosition.Builder()
.target(point) // Sets the new camera position
.zoom(17) // Sets the zoom
.bearing(0) // Rotate the camera
.tilt(30) // Set the camera tilt
.build(); // Creates a CameraPosition from the builder
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 2000);
theMarker.setPosition(point);
mapboxMap.updateMarker(theMarker);
return true;
}
// Add the mapView's own lifecycle methods to the activity's lifecycle methods
@Override
public void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
移動地圖標記
- 範例說明:
- 顯示地圖標記 ( Marker )
- 點擊地圖任一點可移動 Marker
- 圖示下載
Example
public class MoveMarkerAnimationActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnMapClickListener {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private MapView mapView;
private MapboxMap mapboxMap;
private LatLng currentPosition = new LatLng(25.03625, 121.54885);
private GeoJsonSource geoJsonSource;
private ValueAnimator animator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.03625, 121.54885))
.zoom(16)
.bearing(0)
.tilt(50)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
setContentView(mapView);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
style.addImage(("marker_icon"), BitmapFactory.decodeResource(
getResources(), R.drawable.red_marker));
geoJsonSource = new GeoJsonSource("source-id",
Feature.fromGeometry(Point.fromLngLat(currentPosition.getLongitude(), currentPosition.getLatitude())));
style.addSource(geoJsonSource);
style.addLayer(new SymbolLayer("layer-id", "source-id")
.withProperties(
PropertyFactory.iconImage("marker_icon"),
PropertyFactory.iconIgnorePlacement(true),
PropertyFactory.iconAllowOverlap(true)
));
Toast.makeText(
MoveMarkerAnimationActivity.this,
"Tap on the map anywhere",
Toast.LENGTH_LONG
).show();
mapboxMap.addOnMapClickListener(MoveMarkerAnimationActivity.this);
}
});
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
// When the user clicks on the map, we want to animate the marker to that location.
if (animator != null && animator.isStarted()) {
currentPosition = (LatLng) animator.getAnimatedValue();
animator.cancel();
}
animator = ObjectAnimator
.ofObject(latLngEvaluator, currentPosition, point)
.setDuration(2000);
animator.addUpdateListener(animatorUpdateListener);
animator.start();
currentPosition = point;
return true;
}
private final ValueAnimator.AnimatorUpdateListener animatorUpdateListener =
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
LatLng animatedPosition = (LatLng) valueAnimator.getAnimatedValue();
geoJsonSource.setGeoJson(Point.fromLngLat(animatedPosition.getLongitude(), animatedPosition.getLatitude()));
}
};
// Class is used to interpolate the marker animation.
private static final TypeEvaluator<LatLng> latLngEvaluator = new TypeEvaluator<LatLng>() {
private final LatLng latLng = new LatLng();
@Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
latLng.setLatitude(startValue.getLatitude()
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
latLng.setLongitude(startValue.getLongitude()
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
return latLng;
}
};
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (animator != null) {
animator.cancel();
}
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(this);
}
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
自定義地圖標記圖示
- 範例說明:
- 顯示地圖標記 ( Marker )
- 使用自定義圖示
- 圖示下載
- callout layout
- 範例 geojson
Example
public class PopupInfoActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnMapClickListener {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private static final String GEOJSON_SOURCE_ID = "GEOJSON_SOURCE_ID";
private static final String IMAGE_ID_PUSH_PIN = "IMAGE_ID_PUSH_PIN";
private static final String LAYER_ID_PUSH_PIN = "LAYER_ID_PUSH_PIN";
private static final String CALLOUT_LAYER_ID = "CALLOUT_LAYER_ID";
private static final String PROPERTY_SELECTED = "selected";
private static final String PROPERTY_NAME = "name";
private static final String PROPERTY_CAPITAL = "capital";
private MapView mapView;
private MapboxMap mapboxMap;
private GeoJsonSource source;
private FeatureCollection featureCollection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.03625, 121.54885))
.zoom(16)
.bearing(0)
.tilt(50)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
setContentView(mapView);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
new LoadGeoJsonDataTask(PopupInfoActivity.this).execute();
mapboxMap.addOnMapClickListener(PopupInfoActivity.this);
}
});
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
return handleClickIcon(mapboxMap.getProjection().toScreenLocation(point));
}
/**
* Sets up all of the sources and layers needed for this example
*
* @param collection the FeatureCollection to set equal to the globally-declared FeatureCollection
*/
public void setUpData(final FeatureCollection collection) {
featureCollection = collection;
if (mapboxMap != null) {
mapboxMap.getStyle(style -> {
setupSource(style);
setUpImage(style);
setUpMarkerLayer(style);
setUpInfoWindowLayer(style);
});
}
}
/**
* Adds the GeoJSON source to the map
*/
private void setupSource(@NonNull Style loadedStyle) {
source = new GeoJsonSource(GEOJSON_SOURCE_ID, featureCollection);
loadedStyle.addSource(source);
}
/**
* Adds the marker image to the map for use as a SymbolLayer icon
*/
private void setUpImage(@NonNull Style loadedStyle) {
loadedStyle.addImage(IMAGE_ID_PUSH_PIN, BitmapFactory.decodeResource(
this.getResources(), R.drawable.map_marker_push_pin_pink));
}
/**
* Updates the display of data on the map after the FeatureCollection has been modified
*/
private void refreshSource() {
if (source != null && featureCollection != null) {
source.setGeoJson(featureCollection);
}
}
/**
* Setup a layer with push pin icons
*/
private void setUpMarkerLayer(@NonNull Style loadedStyle) {
loadedStyle.addLayer(new SymbolLayer(LAYER_ID_PUSH_PIN, GEOJSON_SOURCE_ID)
.withProperties(
iconImage(IMAGE_ID_PUSH_PIN),
iconAllowOverlap(true),
iconOffset(new Float[]{0f, -8f})
));
}
/**
* Setup a layer with Android SDK call-outs
* name of the feature is used as key for the iconImage
*/
private void setUpInfoWindowLayer(@NonNull Style loadedStyle) {
loadedStyle.addLayer(new SymbolLayer(CALLOUT_LAYER_ID, GEOJSON_SOURCE_ID)
.withProperties(
/* show image with id title based on the value of the name feature property */
iconImage("{name}"),
/* set anchor of icon to bottom-left */
iconAnchor(ICON_ANCHOR_BOTTOM),
/* all info window and marker image to appear at the same time*/
iconAllowOverlap(true),
/* offset the info window to be above the marker */
iconOffset(new Float[]{-2f, -28f})
)
/* add a filter to show only when selected feature property is true */
.withFilter(eq((get(PROPERTY_SELECTED)), literal(true))));
}
/**
* This method handles click events for SymbolLayer symbols.
* When a SymbolLayer icon is clicked, we moved that feature to the selected state.
*
* @param screenPoint the point on screen clicked
*/
private boolean handleClickIcon(PointF screenPoint) {
List<Feature> features = mapboxMap.queryRenderedFeatures(screenPoint, LAYER_ID_PUSH_PIN);
if (!features.isEmpty()) {
String name = features.get(0).getStringProperty(PROPERTY_NAME);
List<Feature> featureList = featureCollection.features();
if (featureList != null) {
for (int i = 0; i < featureList.size(); i++) {
if (featureList.get(i).getStringProperty(PROPERTY_NAME).equals(name)) {
if (featureSelectStatus(i)) {
setFeatureSelectState(featureList.get(i), false);
} else {
setSelected(i);
}
}
}
}
return true;
} else {
return false;
}
}
/**
* Set a feature selected state.
*
* @param index the index of selected feature
*/
private void setSelected(int index) {
if (featureCollection.features() != null) {
Feature feature = featureCollection.features().get(index);
setFeatureSelectState(feature, true);
refreshSource();
}
}
/**
* Selects the state of a feature
*
* @param feature the feature to be selected.
*/
private void setFeatureSelectState(Feature feature, boolean selectedState) {
if (feature.properties() != null) {
feature.properties().addProperty(PROPERTY_SELECTED, selectedState);
refreshSource();
}
}
/**
* Checks whether a Feature's boolean "selected" property is true or false
*
* @param index the specific Feature's index position in the FeatureCollection's list of Features.
* @return true if "selected" is true. False if the boolean property is false.
*/
private boolean featureSelectStatus(int index) {
if (featureCollection == null) {
return false;
}
return featureCollection.features().get(index).getBooleanProperty(PROPERTY_SELECTED);
}
/**
* Invoked when the bitmaps have been generated from a view.
*/
public void setImageGenResults(HashMap<String, Bitmap> imageMap) {
if (mapboxMap != null) {
mapboxMap.getStyle(style -> {
// calling addImages is faster as separate addImage calls for each bitmap.
style.addImages(imageMap);
});
}
}
/**
* AsyncTask to load data from the assets folder.
*/
private static class LoadGeoJsonDataTask extends AsyncTask<Void, Void, FeatureCollection> {
private final WeakReference<PopupInfoActivity> activityRef;
LoadGeoJsonDataTask(PopupInfoActivity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
protected FeatureCollection doInBackground(Void... params) {
PopupInfoActivity activity = activityRef.get();
if (activity == null) {
return null;
}
String geoJson = loadGeoJsonFromAsset(activity, "pop_up_info_example.geojson");
return FeatureCollection.fromJson(geoJson);
}
@Override
protected void onPostExecute(FeatureCollection featureCollection) {
super.onPostExecute(featureCollection);
PopupInfoActivity activity = activityRef.get();
if (featureCollection == null || activity == null) {
return;
}
// This example runs on the premise that each GeoJSON Feature has a "selected" property,
// with a boolean value. If your data's Features don't have this boolean property,
// add it to the FeatureCollection 's features with the following code:
for (Feature singleFeature : featureCollection.features()) {
singleFeature.addBooleanProperty(PROPERTY_SELECTED, false);
}
activity.setUpData(featureCollection);
new GenerateViewIconTask(activity).execute(featureCollection);
}
static String loadGeoJsonFromAsset(Context context, String filename) {
try {
// Load GeoJSON file from local asset folder
InputStream is = context.getAssets().open(filename);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer, Charset.forName("UTF-8"));
}
catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
/**
* AsyncTask to generate Bitmap from Views to be used as iconImage in a SymbolLayer.
* Call be optionally be called to update the underlying data source after execution.
* Generating Views on background thread since we are not going to be adding them to the view hierarchy.
*/
private static class GenerateViewIconTask extends AsyncTask<FeatureCollection, Void, HashMap<String, Bitmap>> {
private final HashMap<String, View> viewMap = new HashMap<>();
private final WeakReference<PopupInfoActivity> activityRef;
private final boolean refreshSource;
GenerateViewIconTask(PopupInfoActivity activity, boolean refreshSource) {
this.activityRef = new WeakReference<>(activity);
this.refreshSource = refreshSource;
}
GenerateViewIconTask(PopupInfoActivity activity) {
this(activity, false);
}
@SuppressWarnings("WrongThread")
@Override
protected HashMap<String, Bitmap> doInBackground(FeatureCollection... params) {
PopupInfoActivity activity = activityRef.get();
if (activity != null) {
HashMap<String, Bitmap> imagesMap = new HashMap<>();
LayoutInflater inflater = LayoutInflater.from(activity);
FeatureCollection featureCollection = params[0];
for (Feature feature : featureCollection.features()) {
BubbleLayout bubbleLayout = (BubbleLayout)
inflater.inflate(R.layout.symbol_layer_info_window_layout_callout, null);
String name = feature.getStringProperty(PROPERTY_NAME);
TextView titleTextView = bubbleLayout.findViewById(R.id.info_window_title);
titleTextView.setText(name);
TextView descriptionTextView = bubbleLayout.findViewById(R.id.info_window_description);
String style = feature.getStringProperty(PROPERTY_CAPITAL);
descriptionTextView.setText(String.format("描述", style));
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
bubbleLayout.measure(measureSpec, measureSpec);
float measuredWidth = bubbleLayout.getMeasuredWidth();
bubbleLayout.setArrowPosition(measuredWidth / 2 - 5);
Bitmap bitmap = SymbolGenerator.generate(bubbleLayout);
imagesMap.put(name, bitmap);
viewMap.put(name, bubbleLayout);
}
return imagesMap;
} else {
return null;
}
}
@Override
protected void onPostExecute(HashMap<String, Bitmap> bitmapHashMap) {
super.onPostExecute(bitmapHashMap);
PopupInfoActivity activity = activityRef.get();
if (activity != null && bitmapHashMap != null) {
activity.setImageGenResults(bitmapHashMap);
if (refreshSource) {
activity.refreshSource();
}
}
Toast.makeText(activity, "Tap on the marker", Toast.LENGTH_SHORT).show();
}
}
/**
* Utility class to generate Bitmaps for Symbol.
*/
private static class SymbolGenerator {
/**
* Generate a Bitmap from an Android SDK View.
*
* @param view the View to be drawn to a Bitmap
* @return the generated bitmap
*/
static Bitmap generate(@NonNull View view) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
view.layout(0, 0, measuredWidth, measuredHeight);
Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(this);
}
mapView.onDestroy();
}
}
限制地圖可滑區域
- 範例說明:
- 設定東北與西南的經緯度,限制使用者在此座標內滑動地圖
Example
public class RestrictCameraActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLng BOUND_CORNER_NW = new LatLng(25.188526, 121.272374);
private static final LatLng BOUND_CORNER_SE = new LatLng(24.794329, 121.672012);
private static final LatLngBounds RESTRICTED_BOUNDS_AREA = new LatLngBounds.Builder()
.include(BOUND_CORNER_NW)
.include(BOUND_CORNER_SE)
.build();
private final List<List<Point>> points = new ArrayList<>();
private final List<Point> outerPoints = new ArrayList<>();
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.012947, 121.464916))
.zoom(9)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
setContentView(mapView);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Set the boundary area for the map camera
mapboxMap.setLatLngBoundsForCameraTarget(RESTRICTED_BOUNDS_AREA);
// Set the minimum zoom level of the map camera
mapboxMap.setMinZoomPreference(2);
showBoundsArea(style);
showCrosshair();
}
});
}
/**
* Add a FillLayer to show the boundary area
*
* @param loadedMapStyle a Style object which has been loaded by the map
*/
private void showBoundsArea(@NonNull Style loadedMapStyle) {
outerPoints.add(Point.fromLngLat(RESTRICTED_BOUNDS_AREA.getNorthWest().getLongitude(),
RESTRICTED_BOUNDS_AREA.getNorthWest().getLatitude()));
outerPoints.add(Point.fromLngLat(RESTRICTED_BOUNDS_AREA.getNorthEast().getLongitude(),
RESTRICTED_BOUNDS_AREA.getNorthEast().getLatitude()));
outerPoints.add(Point.fromLngLat(RESTRICTED_BOUNDS_AREA.getSouthEast().getLongitude(),
RESTRICTED_BOUNDS_AREA.getSouthEast().getLatitude()));
outerPoints.add(Point.fromLngLat(RESTRICTED_BOUNDS_AREA.getSouthWest().getLongitude(),
RESTRICTED_BOUNDS_AREA.getSouthWest().getLatitude()));
outerPoints.add(Point.fromLngLat(RESTRICTED_BOUNDS_AREA.getNorthWest().getLongitude(),
RESTRICTED_BOUNDS_AREA.getNorthWest().getLatitude()));
points.add(outerPoints);
loadedMapStyle.addSource(new GeoJsonSource("source-id",
Polygon.fromLngLats(points)));
loadedMapStyle.addLayer(new FillLayer("layer-id", "source-id").withProperties(
fillColor(Color.RED),
fillOpacity(.25f)
));
}
private void showCrosshair() {
View crosshair = new View(this);
crosshair.setLayoutParams(new FrameLayout.LayoutParams(15, 15, Gravity.CENTER));
crosshair.setBackgroundColor(Color.GREEN);
mapView.addView(crosshair);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
繪製多邊形圖層
- 範例說明:
- 給予指定經緯度座標點,畫出 Polygon Annotation 顯示在地圖上
Example
public class DrawPolygonActivity extends AppCompatActivity {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private MapView mapView;
private static final List<List<Point>> POINTS = new ArrayList<>();
private static final List<Point> OUTER_POINTS = new ArrayList<>();
static {
OUTER_POINTS.add(Point.fromLngLat(121.544111, 25.051779));
OUTER_POINTS.add(Point.fromLngLat(121.548695, 25.057678));
OUTER_POINTS.add(Point.fromLngLat(121.555254, 25.058218));
OUTER_POINTS.add(Point.fromLngLat(121.556052, 25.054389));
OUTER_POINTS.add(Point.fromLngLat(121.556656, 25.053385));
OUTER_POINTS.add(Point.fromLngLat(121.557468, 25.051451));
OUTER_POINTS.add(Point.fromLngLat(121.544111, 25.051779));
POINTS.add(OUTER_POINTS);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.05488, 121.55097))
.zoom(14)
.bearing(0)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
style.addSource(new GeoJsonSource("source-id", Polygon.fromLngLats(POINTS)));
style.addLayerBelow(new FillLayer("layer-id", "source-id").withProperties(
fillColor(Color.parseColor("#3bb2d0")),
fillOpacity(.5f)), "settlement-label"
);
}
});
}
});
setContentView(mapView);
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
繪製圓形圖層
- 範例說明:
- 給予指定中心點經緯度,畫出圓形圖層顯示在地圖上
Example
public class DrawCirclePolygonActivity extends AppCompatActivity {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private static final List<Feature> CIRCLE_POINTS = new ArrayList<>();
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.037853, 121.54885))
.zoom(16)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
Feature singleFeature = Feature.fromGeometry(Point.fromLngLat(121.54885,25.037853));
CIRCLE_POINTS.add(singleFeature);
FeatureCollection featureCollection = FeatureCollection.fromFeatures(CIRCLE_POINTS);
style.addSource(new GeoJsonSource("source-id", featureCollection));
CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
circleLayer.withProperties(
PropertyFactory.circleRadius(100.0f),
PropertyFactory.circleOpacity(0.5f),
PropertyFactory.circleColor(Color.parseColor("#3bb2d0")),
PropertyFactory.circleStrokeColor(Color.parseColor("#3bb2d0"))
);
style.addLayer(circleLayer);
}
});
}
});
setContentView(mapView);
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
多個圓形圖層疊加
- 範例說明:
- 畫出複數個圓形圖層顯示在地圖上
- 圓形可依地圖俯瞰視角與縮放變動
Example
public class DrawMultiCirclesActivity extends AppCompatActivity {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private static final List<Feature> CIRCLE_POINTS = new ArrayList<>();
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, MY_MAP8_KEY);
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.04624, 121.52415))
.zoom(14)
.tilt(42)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
mapboxMap.addPolygon(generatePerimeter(
new LatLng(25.04624, 121.52415),
0.5,
64,
Color.parseColor("#2970C0")));
mapboxMap.addPolygon(generatePerimeter(
new LatLng(25.05003, 121.52942),
0.3,
64,
Color.parseColor("#4E9A54")));
mapboxMap.addPolygon(generatePerimeter(
new LatLng(25.04996, 121.50792),
1.5,
64,
Color.parseColor("#D0104C")));
}
});
}
});
setContentView(mapView);
}
private PolygonOptions generatePerimeter(LatLng centerCoordinates, double radiusInKilometers, int numberOfSides, int fillColor) {
List<LatLng> positions = new ArrayList<>();
double distanceX = radiusInKilometers / (111.319 * Math.cos(centerCoordinates.getLatitude() * Math.PI / 180));
double distanceY = radiusInKilometers / 110.574;
double slice = (2 * Math.PI) / numberOfSides;
double theta;
double x;
double y;
LatLng position;
for (int i = 0; i < numberOfSides; ++i) {
theta = i * slice;
x = distanceX * Math.cos(theta);
y = distanceY * Math.sin(theta);
position = new LatLng(centerCoordinates.getLatitude() + y,
centerCoordinates.getLongitude() + x);
positions.add(position);
}
return new PolygonOptions()
.addAll(positions)
.fillColor(fillColor)
.alpha(0.4f);
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
路徑線段動畫展示
- 範例說明:
- 載入自定義的 geojson 檔案
- 繪出路徑線段,並以動畫方式呈現
- 範例 geojson
Example
public class LineAnimationActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String DOT_SOURCE_ID = "dot-source-id";
private static final String LINE_SOURCE_ID = "line-source-id";
private MapView mapView;
private MapboxMap mapboxMap;
private GeoJsonSource pointSource;
private GeoJsonSource lineSource;
private List<Point> routeCoordinateList;
private List<Point> markerLinePointList = new ArrayList<>();
private int routeIndex;
private Point originPoint = Point.fromLngLat(121.5438079, 25.041573);
private Point destinationPoint = Point.fromLngLat(121.552777, 25.033116);
private Animator currentAnimator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(25.037682, 121.548785))
.zoom(14)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
setContentView(mapView);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
new LoadGeoJson(LineAnimationActivity.this).execute();
}
});
}
private void drawLines(@NonNull FeatureCollection featureCollection) {
if (mapboxMap != null) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngBounds(
new LatLngBounds.Builder()
.include(new LatLng(originPoint.latitude(), originPoint.longitude()))
.include(new LatLng(destinationPoint.latitude(), destinationPoint.longitude()))
.build(), 50), 5000);
initData(style, featureCollection);
}
});
}
}
/**
* Add data to the map once the GeoJSON has been loaded
*
* @param featureCollection returned GeoJSON FeatureCollection from the Directions API route request
*/
private void initData(Style fullyLoadedStyle, @NonNull FeatureCollection featureCollection) {
if (featureCollection.features() != null) {
LineString lineString = ((LineString) featureCollection.features().get(0).geometry());
if (lineString != null) {
routeCoordinateList = lineString.coordinates();
initSources(fullyLoadedStyle, featureCollection);
initSymbolLayer(fullyLoadedStyle);
initDotLinePath(fullyLoadedStyle);
animate();
}
}
}
/**
* Set up the repeat logic for moving the icon along the route.
*/
private void animate() {
// Check if we are at the end of the points list
if ((routeCoordinateList.size() - 1 > routeIndex)) {
Point indexPoint = routeCoordinateList.get(routeIndex);
Point newPoint = Point.fromLngLat(indexPoint.longitude(), indexPoint.latitude());
currentAnimator = createLatLngAnimator(indexPoint, newPoint);
currentAnimator.setDuration(100);
currentAnimator.start();
routeIndex++;
}
}
private static class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
return Point.fromLngLat(
startValue.longitude() + ((endValue.longitude() - startValue.longitude()) * fraction),
startValue.latitude() + ((endValue.latitude() - startValue.latitude()) * fraction)
);
}
}
private Animator createLatLngAnimator(Point currentPosition, Point targetPosition) {
ValueAnimator latLngAnimator = ValueAnimator.ofObject(new PointEvaluator(), currentPosition, targetPosition);
latLngAnimator.setDuration((long) TurfMeasurement.distance(currentPosition, targetPosition, "meters"));
latLngAnimator.setInterpolator(new LinearInterpolator());
latLngAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animate();
}
});
latLngAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point point = (Point) animation.getAnimatedValue();
pointSource.setGeoJson(point);
markerLinePointList.add(point);
lineSource.setGeoJson(Feature.fromGeometry(LineString.fromLngLats(markerLinePointList)));
}
});
return latLngAnimator;
}
/**
* Add various sources to the map.
*/
private void initSources(@NonNull Style loadedMapStyle, @NonNull FeatureCollection featureCollection) {
loadedMapStyle.addSource(pointSource = new GeoJsonSource(DOT_SOURCE_ID, featureCollection));
loadedMapStyle.addSource(lineSource = new GeoJsonSource(LINE_SOURCE_ID));
}
/**
* Add the marker icon SymbolLayer.
*/
private void initSymbolLayer(@NonNull Style loadedMapStyle) {
loadedMapStyle.addImage("moving-red-marker", BitmapFactory.decodeResource(
getResources(), R.drawable.pink_dot));
loadedMapStyle.addLayer(new SymbolLayer("symbol-layer-id", DOT_SOURCE_ID).withProperties(
iconImage("moving-red-marker"),
iconSize(1f),
iconOffset(new Float[] {5f, 0f}),
iconIgnorePlacement(true),
iconAllowOverlap(true)
));
}
/**
* Add the LineLayer for the marker icon's travel route. Adding it under the "road-label" layer, so that the
* this LineLayer doesn't block the street name.
*/
private void initDotLinePath(@NonNull Style loadedMapStyle) {
loadedMapStyle.addLayerBelow(new LineLayer("line-layer-id", LINE_SOURCE_ID).withProperties(
lineColor(Color.parseColor("#F13C6E")),
lineCap(Property.LINE_CAP_ROUND),
lineJoin(Property.LINE_JOIN_ROUND),
lineWidth(4f)), "road-label");
}
private static class LoadGeoJson extends AsyncTask<Void, Void, FeatureCollection> {
private WeakReference<LineAnimationActivity> weakReference;
LoadGeoJson(LineAnimationActivity activity) {
this.weakReference = new WeakReference<>(activity);
}
@Override
protected FeatureCollection doInBackground(Void... voids) {
try {
LineAnimationActivity activity = weakReference.get();
if (activity != null) {
InputStream inputStream = activity.getAssets().open("map.geojson");
return FeatureCollection.fromJson(convertStreamToString(inputStream));
}
} catch (Exception exception) {
Log.e("[Map8 SDK Demo]", "Exception Loading GeoJSON: " + exception.toString());
}
return null;
}
static String convertStreamToString(InputStream is) {
Scanner scanner = new Scanner(is).useDelimiter("\\A");
return scanner.hasNext() ? scanner.next() : "";
}
@Override
protected void onPostExecute(@Nullable FeatureCollection featureCollection) {
super.onPostExecute(featureCollection);
LineAnimationActivity activity = weakReference.get();
if (activity != null && featureCollection != null) {
activity.drawLines(featureCollection);
}
}
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
建立群聚標示
- 範例說明:
- 載入自定義的 geojson 檔案
- 在地圖上建立群聚標示
- 範例 geojson
- 範例圖示
Example
public class ShowClusterActivity extends AppCompatActivity {
// Taiwan map boundary
private static final LatLng TW_BOUND_CORNER_NE = new LatLng(33.4, 138.45858);
private static final LatLng TW_BOUND_CORNER_SW = new LatLng(15, 105);
private static final LatLngBounds TW_BOUNDS_AREA = new LatLngBounds.Builder()
.include(TW_BOUND_CORNER_NE)
.include(TW_BOUND_CORNER_SW)
.build();
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Map8 access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Map8.getInstance(this, "<您的 Map8 Key>");
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.camera(new CameraPosition.Builder()
.target(new LatLng(24.95997, 121.22649))
.zoom(13)
.bearing(0)
.tilt(50)
.build());
// create map
mapView = new MapView(this, options);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
ShowClusterActivity.this.mapboxMap = mapboxMap;
mapboxMap.setMaxZoomPreference(19.99);
mapboxMap.setMinZoomPreference(6);
mapboxMap.setLatLngBoundsForCameraTarget(TW_BOUNDS_AREA);
mapboxMap.setStyle(new Style.Builder().fromUri("https://api.map8.zone/styles/go-life-maps-tw-style-std/style.json"), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
Log.d("[Map8 SDK Demo]", "mapView.getMapAsync() > onMapReady() > setStyle() > onStyleLoaded()");
addClusteredGeoJsonSource(style);
style.addImage(
"port",
BitmapFactory.decodeResource(ShowClusterActivity.this.getResources(), R.drawable.port),
true
);
}
});
}
});
setContentView(mapView);
}
@Override
public void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private void addClusteredGeoJsonSource(@NonNull Style loadedMapStyle) {
// Add a new source from the GeoJSON data and set the 'cluster' option to true.
try {
loadedMapStyle.addSource(
new GeoJsonSource("housesale",
new URI("asset://housesale.geojson"),
new GeoJsonOptions()
.withCluster(true)
.withClusterMaxZoom(14)
.withClusterRadius(50)
)
);
} catch (URISyntaxException uriSyntaxException) {
Log.e("[Map8 SDK Demo]", "Check the URL " + uriSyntaxException.getMessage());
}
int[][] layers = new int[][] {
new int[] {150, ContextCompat.getColor(this, R.color.mapboxRed)},
new int[] {20, ContextCompat.getColor(this, R.color.mapboxGreen)},
new int[] {0, ContextCompat.getColor(this, R.color.mapbox_blue)}
};
float[][] layers_radius = new float[][] {
new float[] {150, 40f},
new float[] {20, 30f},
new float[] {0, 20f}
};
//Creating a marker layer for single data points
SymbolLayer unclustered = new SymbolLayer("unclustered-points", "housesale");
unclustered.setProperties(
iconImage("port"),
iconAllowOverlap(true)
);
loadedMapStyle.addLayer(unclustered);
for (int i = 0; i < layers.length; i++) {
//Add clusters' circles
CircleLayer circles = new CircleLayer("cluster-" + i, "housesale");
circles.setProperties(
circleColor(layers[i][1]),
circleRadius(layers_radius[i][1])
);
Expression pointCount = toNumber(get("point_count"));
// Add a filter to the cluster layer that hides the circles based on "point_count"
circles.setFilter(
i == 0
? all(has("point_count"),
gte(pointCount, literal(layers[i][0]))
) : all(has("point_count"),
gte(pointCount, literal(layers[i][0])),
lt(pointCount, literal(layers[i - 1][0]))
)
);
loadedMapStyle.addLayer(circles);
}
//Add the count labels
SymbolLayer count = new SymbolLayer("count", "housesale");
count.setProperties(
textField(Expression.toString(get("point_count"))),
textSize(16f),
textColor(Color.WHITE),
textIgnorePlacement(true),
textAllowOverlap(true),
// *** IMPORTANT, 必須要指定字型,Cluster 才能運作
textFont(new String[]{"Noto Sans Regular"})
);
loadedMapStyle.addLayer(count);
}
}
台灣圖霸感謝您的支持與愛護!
有任何疑問,或是指教,都非常歡迎您找我們詢問。
非常感謝!
https://map8.zone