/**
* https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson
*/
public class MapGeoJson {
/**
* type : FeatureCollection
* crs : {"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}}
* features : [{"type":"Feature","properties":{"id":"ak16994521","mag":2.3,"time":1507425650893,"felt":null,"tsunami":0},"geometry":{"type":"Point","coordinates":[-151.5129,63.1016,0]}},{"type":"Feature","properties":{"id":"ak16994519","mag":1.7,"time":1507425289659,"felt":null,"tsunami":0},"geometry":{"type":"Point","coordinates":[-150.4048,63.1224,105.5]}},{"type":"Feature","properties":{"id":"ak16994517","mag":1.6,"time":1507424832518,"felt":null,"tsunami":0},"geometry":{"type":"Point","coordinates":[-151.3597,63.0781,0]}}]
*/
private String type = "FeatureCollection";
private CrsBean crs;
private List features;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public CrsBean getCrs() {
return crs;
}
public void setCrs(CrsBean crs) {
this.crs = crs;
}
public List getFeatures() {
return features;
}
public void setFeatures(List features) {
this.features = features;
}
public static class CrsBean {
/**
* type : name
* properties : {"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}
*/
private String type = "name";
private PropertiesBean properties;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public PropertiesBean getProperties() {
return properties;
}
public void setProperties(PropertiesBean properties) {
this.properties = properties;
}
public static class PropertiesBean {
/**
* name : urn:ogc:def:crs:OGC:1.3:CRS84
*/
private String name = "urn:ogc:def:crs:OGC:1.3:CRS84";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
public static class FeaturesBean {
/**
* type : Feature
* properties : {"type":0,"id":"ak16994521","mag":2.3,"time":1507425650893,"felt":null,"tsunami":0}
* geometry : {"type":"Point","coordinates":[-151.5129,63.1016,0]}
*/
private String type = "Feature";
private PropertiesBeanX properties;
private GeometryBean geometry;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public PropertiesBeanX getProperties() {
return properties;
}
public void setProperties(PropertiesBeanX properties) {
this.properties = properties;
}
public GeometryBean getGeometry() {
return geometry;
}
public void setGeometry(GeometryBean geometry) {
this.geometry = geometry;
}
public static class PropertiesBeanX {
/**
* id : ak16994521
* mag : 2.3
* time : 1507425650893
* felt : null
* tsunami : 0
*/
private String id;
private double mag;
private long time;
private Object felt;
private int tsunami;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getMag() {
return mag;
}
public void setMag(double mag) {
this.mag = mag;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public Object getFelt() {
return felt;
}
public void setFelt(Object felt) {
this.felt = felt;
}
public int getTsunami() {
return tsunami;
}
public void setTsunami(int tsunami) {
this.tsunami = tsunami;
}
}
public static class GeometryBean {
/**
* type : Point
* coordinates : [-151.5129,63.1016,0]
*/
private String type = "Point";
private List coordinates;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List getCoordinates() {
return coordinates;
}
public void setCoordinates(List coordinates) {
this.coordinates = coordinates;
}
}
}
/**
* 生成Json字符串
*/
public String crateJson() {
Gson gson = new Gson();
return gson.toJson(this);
}
}
public class DemoObj {
private String id;
private double lat;
private double lng;
public DemoObj(String id, double lat, double lng) {
this.id = id;
this.lat = lat;
this.lng = lng;
}
public String getId() {
return id;
}
public double getLat() {
return lat;
}
public double getLng() {
return lng;
}
}
/**
* 类描述:聚合数据管理类
*/
public class ClusteringLayerManager {
private static final String MAP_SOURCE_ID = "map-source-id";
private static final String CLUSTER_CIRCLE_ICON_ID = "clustered-circle-icon-id";
private static final String UN_CLUSTERED_POINTS = "un-clustered-points";
private static final String CLUSTER_ = "cluster-";
private static final String COUNT = "count";
private static final String POINT_COUNT = "point_count";
private static final String PROPERTY_ID = "id";
private Style loadedMapStyle;
private GeoJsonSource geoJsonSource = null;
private final HashMap imageMap = new HashMap<>();
public ClusteringLayerManager(Style mapStyle) {
this.loadedMapStyle = mapStyle;
initLayerIcons();
initSource();
}
private void initLayerIcons() {
//添加图片
loadedMapStyle.addImage(CLUSTER_CIRCLE_ICON_ID, BitmapUtils.getBitmapFromDrawable(MyApplication.getInstance().getResources().getDrawable(R.drawable.ic_cluster)));
loadedMapStyle.addImages(imageMap);
}
private void initSource() {
//添加源
geoJsonSource = new GeoJsonSource(MAP_SOURCE_ID, FeatureCollection.fromFeatures(new Feature[]{}),
new GeoJsonOptions()
.withCluster(true)
.withClusterRadius(30)
);
loadedMapStyle.addSource(geoJsonSource);
//Creating a SymbolLayer icon layer for single data/icon points
loadedMapStyle.addLayer(new SymbolLayer(UN_CLUSTERED_POINTS, MAP_SOURCE_ID).withProperties(
iconImage("{" + PROPERTY_ID + "}")
// ,iconSize(
// division(
// get("mag"), literal(4.0f)
// )
// )
));
// Use the earthquakes GeoJSON source to create three point ranges.
int[] layers = new int[]{150, 20, 0};
for (int i = 0; i < layers.length; i++) {
//Add clusters' SymbolLayers images
SymbolLayer symbolLayer = new SymbolLayer(CLUSTER_ + i, MAP_SOURCE_ID);
symbolLayer.setProperties(
iconImage(CLUSTER_CIRCLE_ICON_ID)
);
Expression pointCount = toNumber(get(POINT_COUNT));
// Add a filter to the cluster layer that hides the icons based on "point_count"
symbolLayer.setFilter(
i == 0
? all(has(POINT_COUNT),
gte(pointCount, literal(layers[i]))
) : all(has(POINT_COUNT),
gt(pointCount, literal(layers[i])),
lt(pointCount, literal(layers[i - 1]))
)
);
loadedMapStyle.addLayer(symbolLayer);
}
//Add a SymbolLayer for the cluster data number point count
loadedMapStyle.addLayer(new SymbolLayer(COUNT, MAP_SOURCE_ID).withProperties(
textField(Expression.toString(get(POINT_COUNT))),
textSize(15f),
textColor(Color.WHITE),
textIgnorePlacement(true),
// The .5f offset moves the data numbers down a little bit so that they're
// in the middle of the triangle cluster image
// textOffset(new Float[] {0f, .5f}),
textAllowOverlap(true)
));
}
//region 添加
public void addClusteredGeoJsonSource(MapGeoJson mapGeoJson) {
//先清除
removeAllLayers();
List features = mapGeoJson.getFeatures();
if (!CheckUtil.checkList(features)) {
return;
}
//添加单个头像
for (MapGeoJson.FeaturesBean featuresBean : features) {
MapGeoJson.FeaturesBean.PropertiesBeanX properties = featuresBean.getProperties();
imageMap.put(properties.getId(), BitmapUtils.getBitmapFromDrawable(MyApplication.getInstance().getResources().getDrawable(R.drawable.mapbox_marker_icon_default)));
}
loadedMapStyle.addImages(imageMap);
geoJsonSource.setGeoJson(FeatureCollection.fromJson(mapGeoJson.crateJson()));
}
//endregion
//region 删除
/**
* 删除源
*/
public void removeAllLayers() {
imageMap.clear();
if (geoJsonSource != null) {
geoJsonSource.setGeoJson(FeatureCollection.fromFeatures(new Feature[]{}));
}
}
//endregion
}
public class ClusterActivity extends AppCompatActivity {
private MapView mapView;
private ClusteringLayerManager clusteringLayerManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化 Mapbox
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setContentView(R.layout.activity_cluster);
mapView = findViewById(R.id.cluster_map);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
mapReady(style);
});
});
}
private void mapReady(@NonNull Style style) {
clusteringLayerManager = new ClusteringLayerManager(style);
}
public void add(View view) {
List demoObjList = new ArrayList<>();
Random random = new Random();
int lat = random.nextInt(79);
int lng = random.nextInt(179);
for (int i = 0; i < 100; i++) {
DemoObj demoObj = new DemoObj("id" + i, lat + 0.001 * i, lng - 0.001 * i);
demoObjList.add(demoObj);
}
MapGeoJson mapGeoData = getMapGeoData(demoObjList);
clusteringLayerManager.addClusteredGeoJsonSource(mapGeoData);
}
public void clear(View view) {
clusteringLayerManager.removeAllLayers();
}
private MapGeoJson getMapGeoData(List demoObjList) {
MapGeoJson mapGeoJson = new MapGeoJson();
List featureList = new ArrayList<>();
//填充数据
for (DemoObj demoObj : demoObjList) {
MapGeoJson.FeaturesBean fBean = new MapGeoJson.FeaturesBean();
fBean.setProperties(getDevicePropertiesBeanX(demoObj.getId()));
fBean.setGeometry(getGeometryBean(demoObj.getLat(), demoObj.getLng()));
featureList.add(fBean);
}
mapGeoJson.setFeatures(featureList);
return mapGeoJson;
}
private MapGeoJson.FeaturesBean.GeometryBean getGeometryBean(double lat, double lng) {
MapGeoJson.FeaturesBean.GeometryBean geometryBean = new MapGeoJson.FeaturesBean.GeometryBean();
List coordinates = new ArrayList<>();
coordinates.add(lng);
coordinates.add(lat);
geometryBean.setCoordinates(coordinates);
return geometryBean;
}
private MapGeoJson.FeaturesBean.PropertiesBeanX getDevicePropertiesBeanX(String id) {
MapGeoJson.FeaturesBean.PropertiesBeanX pBeanX = new MapGeoJson.FeaturesBean.PropertiesBeanX();
pBeanX.setId(id);
return pBeanX;
}
//region 生命周期
@Override
protected void onStart() {
super.onStart();
if (mapView != null) {
mapView.onStart();
}
}
@Override
public void onResume() {
super.onResume();
if (mapView != null) {
mapView.onResume();
}
}
@Override
public void onPause() {
super.onPause();
if (mapView != null) {
mapView.onPause();
}
}
@Override
protected void onStop() {
super.onStop();
if (mapView != null) {
mapView.onStop();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapView != null) {
mapView.onDestroy();
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
if (mapView != null) {
mapView.onLowMemory();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mapView != null) {
mapView.onSaveInstanceState(outState);
}
}
//endregion
}