MapBoxMap 之CircleLayer

CircleLayer:实心圆

一 、添加到地图(基本属性):

 如图添加了几个绿色的实现圆。

public class CircleLayerActivity extends AppCompatActivity {
    private static final String CIRCLE_SOURCE_ID = "circle-source-id";
    private static final String CIRCLE_LAYER_ID = "circle-layer-id";

    private MapView mapView;
    private MapboxMap mapboxMap;
    private List<Point> routeCoordinates;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Mapbox.getInstance(this, getString(R.string.mapbox_access_token));

        setContentView(R.layout.activity_circle_layer);

        mapView = findViewById(R.id.mapView);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(@NonNull MapboxMap mapboxMap) {
                CircleLayerActivity.this.mapboxMap = mapboxMap;
                mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(38.875,-77.035),12));
                mapboxMap.setStyle(Style.LIGHT, new Style.OnStyleLoaded() {
                    @Override
                    public void onStyleLoaded(@NonNull Style style) {
                        initCoordinates();
                        initCircleSource(style);
                        initLayer(style);
                    }
                });
            }
        });
    }

    private void initCoordinates() {
        routeCoordinates = new ArrayList<>();
        routeCoordinates.add(Point.fromLngLat(-77.044211, 38.852924));

        routeCoordinates.add(Point.fromLngLat(-77.044232, 38.862326));

        routeCoordinates.add(Point.fromLngLat(-77.039936, 38.867698));

        routeCoordinates.add(Point.fromLngLat(-77.04264, 38.872528));

        routeCoordinates.add(Point.fromLngLat(-77.032309, 38.87937));

        routeCoordinates.add(Point.fromLngLat(-77.027645, 38.881779));

        routeCoordinates.add(Point.fromLngLat(-77.028054, 38.887449));

        routeCoordinates.add(Point.fromLngLat(-77.03364, 38.892108));
        ;
    }

    private void initCircleSource(@NonNull Style style) {
        FeatureCollection featureCollection = FeatureCollection.fromFeatures(
                new Feature[]{Feature.fromGeometry(LineString.fromLngLats(routeCoordinates))});

        GeoJsonSource circleGeoJsonSource = new GeoJsonSource(CIRCLE_SOURCE_ID, featureCollection);
        style.addSource(circleGeoJsonSource);
    }

    private void initLayer(Style style) {
        CircleLayer circleLayer = new CircleLayer(CIRCLE_LAYER_ID, CIRCLE_SOURCE_ID).withProperties(
                /*
                 *circle-blur
                 * Paint property. Optional number. Defaults to 0. Supports feature-state and interpolateexpressions. Transitionable.
                 * Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
                 */
                PropertyFactory.circleBlur(0f),
                /*
                 *circle-color
                 * Paint property. Optional color. Defaults to "#000000". Supports feature-state and interpolateexpressions. Transitionable.
                 * The fill color of the circle.
                 */
                PropertyFactory.circleColor(Color.GREEN),
                /*
                 *circle-opacity
                 * Paint property. Optional number between 0 and 1 inclusive. Defaults to 1. Supports feature-state and interpolateexpressions. Transitionable.
                 * The opacity at which the circle will be drawn.
                 */
                PropertyFactory.circleOpacity(1f),
                /*
                 *circle-pitch-alignment
                 * Paint property. Optional enum. One of "map", "viewport". Defaults to "viewport".
                 * Orientation of circle when map is pitched.
                 *
                 * "map":
                 * The circle is aligned to the plane of the map.
                 *
                 * "viewport":
                 * The circle is aligned to the plane of the viewport.
                 */
                PropertyFactory.circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_VIEWPORT),
                /*
                 *circle-pitch-scale
                 * Paint property. Optional enum. One of "map", "viewport". Defaults to "map".
                 * Controls the scaling behavior of the circle when the map is pitched.
                 *
                 * "map":
                 * Circles are scaled according to their apparent distance to the camera.
                 *
                 * "viewport":
                 * Circles are not scaled.
                 */
                PropertyFactory.circlePitchScale(Property.CIRCLE_PITCH_SCALE_MAP),
                /*
                 *circle-radius
                 * Paint property. Optional number greater than or equal to 0. Units in pixels. Defaults to 5. Supports feature-state and interpolateexpressions. Transitionable.
                 * Circle radius.
                 */
                PropertyFactory.circleRadius(8f),
                /*
                 *circle-sort-key
                 * Layout property. Optional number.
                 * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key.
                 */
//                PropertyFactory.circleSortKey(),
                /*
                 *circle-stroke-color
                 * Paint property. Optional color. Defaults to "#000000". Supports feature-state and interpolateexpressions. Transitionable.
                 * The stroke color of the circle.
                 */
                PropertyFactory.circleStrokeColor(Color.parseColor("#000000")),
                /*
                 * circle-stroke-opacity
                 * Paint property. Optional number between 0 and 1 inclusive. Defaults to 1. Supports feature-state and interpolateexpressions. Transitionable.
                 * The opacity of the circle's stroke.
                 */
                PropertyFactory.circleStrokeOpacity(1f),
                /*
                 *circle-stroke-width
                 * Paint property. Optional number greater than or equal to 0. Units in pixels. Defaults to 0. Supports feature-state and interpolateexpressions. Transitionable.
                 * The width of the circle's stroke. Strokes are placed outside of the circle-radius.
                 */
                PropertyFactory.circleStrokeWidth(0f),
                /*
                 * circle-translate
                 * Paint property. Optional array of numbers. Units in pixels. Defaults to [0,0]. Supports interpolateexpressions. Transitionable.
                 * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
                 */
                PropertyFactory.circleTranslate(new Float[]{0f, 0f}),
                /*
                 *circle-translate-anchor
                 * Paint property. Optional enum. One of "map", "viewport". Defaults to "map". Requires circle-translate.
                 * Controls the frame of reference for circle-translate.
                 *
                 * "map":
                 * The circle is translated relative to the map.
                 *
                 * "viewport":
                 * The circle is translated relative to the viewport.
                 */
                PropertyFactory.circleTranslateAnchor(Property.CIRCLE_TRANSLATE_ANCHOR_MAP),
                /*
                 * visibility
                 * Layout property. Optional enum. One of "visible", "none". Defaults to "visible".
                 * Whether this layer is displayed.
                 *
                 * "visible":
                 * The layer is shown.
                 *
                 * "none":
                 * The layer is not shown.
                 */
                PropertyFactory.visibility(Property.VISIBLE));
        style.addLayer(circleLayer);
    }
}

二、使用GeoJSON和CircleLayer将点数据聚合。 

GeoGson格式示例:

{
"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.0 ] } }
]
}
package com.ming.androidmapbox.layers;

import android.graphics.Color;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.ming.androidmapbox.R;

import java.net.URI;
import java.net.URISyntaxException;

import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gte;
import static com.mapbox.mapboxsdk.style.expressions.Expression.has;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;

/**
 * Use GeoJSON and circle layers to visualize point data as circle clusters.
 */
public class CircleLayerClusteringActivity extends AppCompatActivity {
    private static final String URL = "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson";
    private static final String SOURCE_ID = "earthquakes";
    private static final String UN_CLUSTERED_LAYER_ID = "unclustered-points";
    private static final String CROSS_ICON_ID = "cross-icon-id";
    private static final String POINT_COUNT = "point_count";
    private static final String COUNT = "count";
    private static final String MAG = "mag";
    private static final String CLUSTER_LAYER_ID_PRE = "cluster-";

    private static final int CLUSTER_MAX_ZOOM = 14;
    private static final int CLUSTER_RADIUS = 50;

    private MapView mapView;
    private MapboxMap mapboxMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Mapbox.getInstance(this, getString(R.string.mapbox_access_token));

        setContentView(R.layout.activity_circle_layer_clustering);

        mapView = findViewById(R.id.mapView);

        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(@NonNull MapboxMap map) {

                mapboxMap = map;

                map.setStyle(Style.LIGHT, new Style.OnStyleLoaded() {
                    @Override
                    public void onStyleLoaded(@NonNull Style style) {

                        // 当图标在地图上碰撞时,禁用任何类型的衰落过渡。这增强了聚集在一起并分离的数据的视觉效果。
                        style.setTransition(new TransitionOptions(0, 0, false));

                        mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(
                                12.099, -79.045), 3));

                        addClusteredGeoJsonSource(style);

                        style.addImage(CROSS_ICON_ID, getResources().getDrawable(R.drawable.mapbox_marker_icon_default));

                        Toast.makeText(CircleLayerClusteringActivity.this, "缩放地图查看聚合效果",
                                Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }

    private void addClusteredGeoJsonSource(@NonNull Style loadedMapStyle) {

        //从GeoJSON数据中添加新来源,并将群集选项设置为true。
        try {
            loadedMapStyle.addSource(
                    // 指向GeoJSON数据。此示例显示了USGS地震灾害计划记录的从12/22/15到1/21/16的所有M1.0 +地震。
                    new GeoJsonSource(SOURCE_ID,
                            new URI(URL),
                            new GeoJsonOptions()
                                    .withCluster(true)
                                    .withClusterMaxZoom(CLUSTER_MAX_ZOOM)
                                    .withClusterRadius(CLUSTER_RADIUS)
                    )
            );
        } catch (URISyntaxException uriSyntaxException) {
//            Timber.e("Check the URL %s", uriSyntaxException.getMessage());
        }

        //为单个数据点创建标记层
        SymbolLayer unclustered = new SymbolLayer(UN_CLUSTERED_LAYER_ID, SOURCE_ID);

        unclustered.setProperties(
                iconImage(CROSS_ICON_ID),
                iconSize(
                        division(
                                get(MAG), literal(4.0f)
                        )
                ),
                iconColor(
                        interpolate(exponential(1), get(MAG),
                                stop(2.0, rgb(0, 255, 0)),
                                stop(4.5, rgb(0, 0, 255)),
                                stop(7.0, rgb(255, 0, 0))
                        )
                )
        );
        unclustered.setFilter(has(MAG));
        loadedMapStyle.addLayer(unclustered);

        // 使用地震GeoJSON源创建三个图层:每个群集类别一个图层。
        // 每个点范围将获得不同的填充颜色。
        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)}
        };

        for (int i = 0; i < layers.length; i++) {
            //添加集群的圈子
            CircleLayer circles = new CircleLayer(CLUSTER_LAYER_ID_PRE + i, SOURCE_ID);
            circles.setProperties(
                    circleColor(layers[i][1]),
                    circleRadius(18f)
            );

            Expression pointCount = toNumber(get(POINT_COUNT));

            // 将过滤器添加到群集层,以基于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);
        }

        //添加计数标签
        SymbolLayer count = new SymbolLayer(COUNT, SOURCE_ID);
        count.setProperties(
                textField(Expression.toString(get(POINT_COUNT))),
                textSize(12f),
                textColor(Color.WHITE),
                textIgnorePlacement(true),
                textAllowOverlap(true)
        );
        loadedMapStyle.addLayer(count);
    }

    // 生命周期...
}

布局文件只有个mapview就不贴出来了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值