如何使用symbolmanager在mapbox中执行聚类?

时间:2019-07-25 10:16:51

标签: java android mapbox markerclusterer

我正在尝试使用mapbox库及其注释插件在应用程序中进行聚类。在开发的应用程序中,必须使用单击处理程序并为每个标记设置属性(角度,图标,颜色等),因此使用SymbolLayer的选项会立即消失。我想到的唯一几乎可行的解决方案是使用SymbolManager创建一个图层,并尝试用SymbolLayer图层覆盖它(据我所知,它具有聚类功能,与SymbolManager不同,尽管这是同一件事)。该解决方案的缺点是各层的重叠是不正确的。例如,可能是簇已经出现,标记还没有消失,反之亦然。而且,簇没有与标记完全重叠。谁面对这个任务,告诉我您是如何解决的?我的解决方案如下所示。预先谢谢你!

public class MainActivity extends AppCompatActivity {
    MapView mMapView;
    MapboxMap mMapboxMap;

    private SymbolManager symbolManager;
    private List<Symbol> markers;
    private CarGroup mCarData;

    Style mStyle;
    private static final String TAG = "MainActivity";
    final Float textOffset[] = { 0f, -2.5f };
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Mapbox.getInstance(this, getString(R.string.token));
        setContentView(R.layout.activity_main);

        mMapView = findViewById(R.id.mapView);
        mMapView.onCreate(savedInstanceState);
        mMapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
            this.mMapboxMap = mapboxMap;
            this.mStyle = style;
            style.addImage("ic_marker", BitmapManager.generateBitmap(this, R.drawable.ic_marker), true);
            style.addImage("circle", BitmapManager.generateBitmap(this, R.drawable.circle), true);
            symbolManager = new SymbolManager(mMapView, mMapboxMap, style, "1");
            symbolManager.setIconRotationAlignment("map");
            symbolManager.setTextIgnorePlacement(true);
            markers = new ArrayList<>();

            handler.postDelayed(markerUpdateRunnable, 1000);
        }));
    }

    private Runnable markerUpdateRunnable = new Runnable(){
        public void run(){
            if (NetworkManager.isNetWorkAvailable(MainActivity.this)) {
                refreshCarData(116, "af821e21-caaa-4e09-975b-8df9ea52ef9d");
            } else Toast.makeText(getApplicationContext(), "Отсутствует подключение к интернету", Toast.LENGTH_SHORT).show();

            handler.postDelayed(this, 5000);
        }
    };



    private void refreshCarData(int id, String token) {
        NetworkConnector.getInstance()
                .getGlonassApi()
                .getCarData(id, token)
                .enqueue(new Callback<CarGroup>() {
                    @Override
                    public void onResponse(@NonNull Call<CarGroup> call, @NonNull Response<CarGroup> response) {
                        if (response.isSuccessful()) {
                            refreshClusteredGeoJsonSource(response);
                        }
                    }
                    @Override
                    public void onFailure(@NonNull Call<CarGroup> call, @NonNull Throwable t) {
                        refreshCarData(id, token);
                    }
                });
    }

    private void refreshClusteredGeoJsonSource(@NonNull Response<CarGroup> response) {
        mCarData = response.body();

        if (markers.size() != mCarData.getSize()) {
            symbolManager.delete(markers);
        }
        if (symbolManager.getAnnotations().size() == 0) {
            createSymbols();
        } else {
            moveSymbol();
        }
        showCluster();
    }

    private void moveSymbol() {
        Symbol symbol;
        List<Symbol> toUpdate = new ArrayList<>();
        if (markers.size() == mCarData.getSize()) {
            for (int i = 0; i < mCarData.getSize(); i++) {
                symbol = markers.get(i);
                LatLng location = mCarData.getLatLng(i);
                float rotation = mCarData.getAngle(i);
                final LatLng originalPosition = symbol.getLatLng();
                final float originalRotation = symbol.getIconRotate();
                final boolean changeLocation = originalPosition.distanceTo(location) > 0;
                final boolean changeRotation = originalRotation != rotation;

                if (symbolManager == null || symbolManager.getAnnotations().indexOfValue(symbol) < 0) {
                    return;
                }

                if (!changeLocation && !changeRotation) {
                    continue;
                }
                if (changeLocation) {
                    symbol.setLatLng(location);
                }
                if (changeRotation) {
                    symbol.setIconRotate(rotation);
                }
                toUpdate.add(symbol);
            }
            symbolManager.update(toUpdate);
        }
    }

    private void createSymbols() {
        Expression pointCount = toNumber(get("point_count"));
        int[] layers = new int[] { 0, ContextCompat.getColor(this, R.color.colorAccent) } ;

        for (int i = 0; i < mCarData.getSize(); i++) {
            String color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.gray));
            if (mCarData.isOnline(i)) {
                if (mCarData.getDrive(i) == 1) {
                    color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.mapboxGreen));
                } else {
                    color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.mapbox_blue));
                }
            }
            createSymbol(mCarData.getLatLng(i), mCarData.getAngle(i), mCarData.getNumber(i), color, "ic_marker");
            symbolManager.setFilter(all(has("point_count",  gte(pointCount, literal(layers[0])))));
        }
    }

    private void createSymbol(LatLng latLng, float angle, String number, String color,@Nullable String icon) {
        SymbolOptions symbolOptions = new SymbolOptions()
                .withLatLng(latLng)
                .withIconImage(icon)
                .withIconSize(0.8f)
                .withTextField(number)
                .withTextSize(10.0f)
                .withTextOffset(textOffset)
                .withTextHaloColor(ColorUtils.colorToRgbaString(Color.WHITE))
                .withTextHaloWidth(1f)
                .withIconColor(color)
                .withIconRotate(angle)
                .withZIndex(0)
                .setDraggable(false);
        markers.add(symbolManager.create(symbolOptions));
    }


    private void showCluster() {
        List<Feature> markerCoordinates = new ArrayList<>();
        for(int i = 0; i < mCarData.getSize(); i++) {
            markerCoordinates.add(Feature.fromGeometry(
                    Point.fromLngLat(mCarData.getLon(i), mCarData.getLat(i))));
        }
        GeoJsonSource mSource = (GeoJsonSource) mStyle.getSource("markers");
        if (mSource == null) {
            mStyle.addSource(
                    new GeoJsonSource("markers",
                            FeatureCollection.fromFeatures(markerCoordinates),
                            new GeoJsonOptions()
                                    .withCluster(true)
                                    .withTolerance(0.5f)
                                    .withClusterRadius(50)
                                    .withClusterMaxZoom(14)
                    )
            );
        } else {
            mSource.setGeoJson(FeatureCollection.fromFeatures(markerCoordinates));
        }

        int[] layers = new int[] { 0, ContextCompat.getColor(this, R.color.mapbox_blue) } ;

        for (int i = 0; i < layers.length; i++) {
            //Add clusters' circles
            CircleLayer circles = (CircleLayer) mStyle.getLayer("cluster-" + i);
            if (circles == null) {
                circles = new CircleLayer("cluster-" + i, "markers");
                circles.setProperties(
                        circleColor(layers[1]),
                        circleRadius(18f)
                );

                Expression pointCount = toNumber(get("point_count"));

                // Add a filter to the cluster layer that hides the circles based on "point_count"
                circles.setFilter(all(has("point_count"), gte(pointCount, literal(layers[0]))));
                mStyle.addLayer(circles);
            }
        }

        //Add the count labels
        SymbolLayer count = (SymbolLayer) mStyle.getLayer("count");
        if (count == null) {
            count = new SymbolLayer("count", "markers");
            count.setProperties(
                    textField(Expression.toString(get("point_count"))),
                    textSize(12f),
                    textColor(Color.WHITE),
                    textIgnorePlacement(true),
                    textAllowOverlap(true)
            );
            mStyle.addLayer(count);
        }
    }



    @Override
    public void onStart() {
        super.onStart();
        mMapView.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
        mMapView.onStop();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
    }
}

0 个答案:

没有答案