Android地图—— Mapbox 10.3.0 聚类标签实现

Mapbox的初始化配置请见这个文章:Android地图—— Mapbox 10.3.0 接入与基础使用

我们知道,mapbox显示地图是利用多个 layers 组装而成,比如water layer等。mapbox支持我们添加更多的layer用于自定义用途,这里我们用layer来展示大量的标记。
以下例子实现了新建layer展示标记,并实现标记随地图缩放聚合、以及用户点击交互的功能。
具体的实现我参考了这个博主的代码:MapBoxMap 之 SymbolLayer实现标记聚合,在其基础上进行了10.3.0版本的适配,以及添加了点击标记的交互,这里的实现仅为个人尝试,可能有更好的实现方法。(注:由于官网已有kotlin的实现示例,这里将以java作为示例编写语言)
效果图先行:
在这里插入图片描述
以下文章主要为原理解释,非完整代码展示,建议搭配本文示例程序的代码食用:

1. 基础知识概念

首先明确以下几个概念:

Sources:

地图源,包含要添加到地图中的所有元素描述,以及他们的地理坐标信息。
主要参数:
id: sources的独特标识;
type: 当前sources的类别,类别决定了source中的元素是怎么样的。type的不同也决定了source应该包含什么其他参数;
关于source 不同type包含的参数说明:
https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/

Layers:

样式层,用于决定Sources中的元素在地图上的显示样式。
主要参数:
id: layers的独特标识;
type: layers的类别,不同的type有不同的样式展现形式。
source: 该layer是哪个源中的。
filter: Expression表达式,根据各种条件判断当前layer是否展示。
Layers的更多参数说明:
https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/

一个sources可以对应一个或多个layers,这取决于你想以多少种不同形式展示你的数据。

关于source和layers的官方解释:
https://docs.mapbox.com/android/maps/guides/styles/work-with-layers/

要实现一个具有聚合标记物功能,且标记物可自定义样式的图层,我们应该选择sources类型为geojson,layers类型我们则选择样式最丰富的symbol。

2. source初始化并添加到style中:

定义source-id:

private static final String CLUSTER_SOURCE_ID = "cluster-source-id";

初始化例子1:
例子1为在使用 mMapboxMap.loadStyleUri() 方法拿到加载完毕的 mStyle 后,再去添加 source 的方法。
以下代码我们在常规初始化的基础上添加了对 参数 clusterProperties 的设置(该参数可以自定义聚合标记物所包含的特征值,用于一些个性化设置),我们定义了一个 first_item_id 属性,保存了在聚合标记物对象集合中各标记物之间最小的id值,这是为了方便我们后面设置 聚合对象的显示 做准备。

        //添加地图源 type:GeoJson
        {
   
            JSONObject clusterProperties = new JSONObject();
            try {
   
                clusterProperties.put("first_item_id",
                        new JSONArray(Expression.min(Expression.toNumber(Expression.get("id"))).toJson()));
            } catch (JSONException e) {
   
                e.printStackTrace();
            }
            Log.d(TAG, clusterProperties.toString());
            JSONObject jsonObject = new JSONObject();
            try {
   
                jsonObject.put("type","geojson");
                jsonObject.put("data","");      // 初始数据为空
                jsonObject.put("cluster",true);  // 启用聚合功能
                jsonObject.put("clusterRadius",30);
                jsonObject.put("clusterProperties",clusterProperties); // 聚合对象包含的特征
            } catch (JSONException e) {
   
                e.printStackTrace();
            }
//            Log.d(TAG, jsonObject.toString());
            Expected<String, Value> out = Value.fromJson(jsonObject.toString());
            Expected<String, None> success = mStyle.addStyleSource(CLUSTER_SOURCE_ID,
                    Objects.requireNonNull(out.getValue()));
            Log.d(TAG,"[initClusterLayers]source create: " +
                    (success.isError() ? success.getError() : "success"));
        }

初始化例子2:
例子1我们直接生成了一个关于 GenJsonSource 的JSON表达式,通过 styleaddStyleSource() 方法添加到 style 中。
MapBox也提供了直接构造一个GenJson类型Source的方法:

GeoJsonSource geoJsonSource = new GeoJsonSource.Builder(CLUSTER_SOURCE_ID)
        .data("")
        .cluster(true)
        .clusterRadius(30)
        .build();

通过这个方法生成的 GenJsonSource 需要在载入地图style前,添加到 StyleExtensionImpl.Builder() 构建的 StyleExtension ,再通过 mMapboxMap.loadStyle() 方法传入这个 StyleExtension 对象去加载地图Style。

StyleExtensionImpl.Builder builder = new StyleExtensionImpl.Builder(DEFAULT_MAP_STYLE);
builder.addSource(geoJsonSource);
mMapboxMap.loadStyle(builder.build(), new Style.OnStyleLoaded() {
   
    @Override
    public void onStyleLoaded(@NotNull Style style) {
   

    }
});

3. layer初始化并添加到style中:

layer表示数据的呈现形式,在这里我们定义三个类型的layer用于展示我们的数据:

  • 单个标记物的icon展示layer
  • 聚合对象(多个标记物的集合)的icon展示layer
  • 聚合对象(多个标记物的集合)的text展示layer

如果一个对象为 聚合对象cluster ,其将包含以下几个属性:
在这里插入图片描述
除了上面四个默认属性,其还将包含你在 Source 创建时设置的 clusterProperties 中的属性值。
这里以单个标记物对象的展示的layer的初始化为例:
定义全局变量:

private static final String LAYER_ID_SINGLE_POINT = "layer-id-single-points";
private static final String POINT_COUNT = "point_count";

首先,不同的 Layer 应该在不同条件下显示(如我们上面定义的那样,单个标记物的icon展示的layer应该在标记物为 非聚合对象 的情况下展示),通过 Layer 的属性 filter,我们可以设置 Layer 的展示条件,该属性接受一个 Expression 表达式 作为输入。

根据上面所述,我们可以利用 cluster聚合对象 包含 ”point_count” 属性这一特征区分 聚合对象 和 单一对象。

如下代码所示,我们构造了一个判断当前对象是否有 ”point_count” 属性的 Express表达式 ,该表达式 当 当前对象 不含有 ”point_count” 属性时会返回 true。

该Expression的Json表达式为:

[“!”,[“has”,”point_count”]]

java构建Experssion表达式代码:

// 构造filter表达式
Expression.ExpressionBuilder filterExpression = new Expression.ExpressionBuilder("!");
filterExpression.has(POINT_COUNT);

上述构造的 expression 将传入 layerfilter 属性中,以控制该 layer 是否显示。

其次,这一层的标记物我们打算将以图像的形式展现,利用 symbol 中的 icon-image 属性即可实现,为了控制这个图像的显示特点,我们定义一个自定义的 iconLayout Json对象,来描述图像显示的属性:

JSONObject iconLayout = new JSONObject();
try {
   
    iconLayout.put("icon-ignore-placement",true); // 设置其他symbol与icon碰撞时仍显示
    iconLayout.put("icon-allow-overlap",true);	 // 设置icon与其他symbol碰撞时仍显示
} catch (JSONException e) {
   
    e.printStackTrace();
}

icon-ignore-placement 等属性值为symbol标记类型所包含的属性,更多symbol特殊属性值可参照:
https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#symbol

最后Layer的构造代码所下所示:
其中 “{” + IMAGE_ID_SINGLE_POINT_ICON + "}” 表达式,可以获取到当前单一标记物对象中属性名为 IMAGE_ID_SINGLE_POINT_ICON 的属性值。
icon-image 属性接受该表达式,以在Style中检索 通过 style.addImage() 方法传入的 与之id相匹配的图片;这样即可对拥有不同id的标记,显示不同的图片。(向style中addImage可参看第5部分)

private static final String IMAGE_ID_SINGLE_POINT_ICON = "id";
// 构造layer
JSONObject jsonObject = new JSONObject();
try {
   
    jsonObject.put("id", LAYER_ID_SINGLE_POINT);
    jsonObject.put("type","symbol")
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
引用\[3\]中的代码展示了如何使用react-mapbox-gl来实现地图搜索。在代码中,我们首先导入了ReactMapboxGl和其他必要的组件。然后,我们创建了一个Map组件,并传入了一个accessToken作为参数。接下来,我们定义了一个newStyle对象,其中包含了地图的样式和图层信息。在这个例子中,我们使用了天地图的瓦片服务作为地图的底图。然后,我们在Map组件中使用了这个newStyle作为地图的样式,并设置了地图的容器大小和中心点坐标。最后,我们在地图上添加了一个标记点,并设置了标记点的图标样式。通过这样的方式,我们可以在地图实现地图搜索功能。 #### 引用[.reference_title] - *1* *2* [react-native-mapbox-gl在RN中的使用 --工作笔记](https://blog.csdn.net/simper_boy/article/details/105654598)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [React-mapbox-gl](https://blog.csdn.net/qq_34870529/article/details/103823205)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值