Flutter MapBox如何为集群添加onClick地图缩放事件?
Flutter MapBox 集群点击缩放实现方案
核心思路
集群是GeoJSON生成的特殊Feature,会自带point_count属性,我们可以通过监听地图要素点击事件,判断点击对象是否为集群,再执行缩放逻辑。
具体实现步骤
监听要素点击事件
使用controller.onFeatureTapped监听所有可交互要素的点击,回调会返回点击的图层ID、对应的Feature对象和点击坐标。识别集群要素
判断Feature的properties中是否包含point_count字段,若包含则说明点击的是集群。执行缩放逻辑
获取集群的经纬度坐标,结合当前地图缩放等级计算目标缩放等级(比如当前等级+1,或直接设置为clusterMaxZoom - 1确保集群展开),最后调用moveCamera完成地图缩放。
修改后的完整代码示例
Future<void> addGeojsonCluster() async { var geojson = { "type": "FeatureCollection", "crs": { "type": "name", "properties": { "name": "pois" } }, "features": [ for(var marker in markers){ "type" : "Feature", "properties" : {"id" : marker.title}, "geometry": {"type" : "Point", "coordinates" : [marker.longitude, marker.latitude] } }, ] }; await controller.addSource( "poi", GeojsonSourceProperties( data: geojson, cluster: true, clusterMaxZoom: 14, // Max zoom to cluster points on clusterRadius: 50, // Radius of each cluster when clustering points (defaults to 50) ) ); // 确保集群圆圈图层开启交互 await controller.addLayer( "poi", "poi-circles", const CircleLayerProperties( circleColor: [ Expressions.step, [Expressions.get, 'point_count'], '#51bbd6', //blue 100, '#f1f075', //yellow 750, '#f28cb1' //pink ], circleRadius: [ Expressions.step, [Expressions.get, 'point_count'], 20, 100, 30, 750, 40 ]), enableInteraction: true, ); await controller.addSymbolLayer( "poi", "unclustered-point", const SymbolLayerProperties( textField: [Expressions.get, "id"], textHaloWidth: 1, textSize: 12.5, textHaloColor: '#ffffff', textOffset: [ Expressions.literal, [0, 2] ], iconImage: "images/mapbox_circle_marker.png", iconSize: 2, iconAllowOverlap: true, textAllowOverlap: true, textColor: '#000000', textHaloBlur: 1, ), filter: [ '!', ['has', 'point_count'] ], enableInteraction: true, ); // 集群数字层开启交互,点击数字也能触发缩放 await controller.addLayer( "poi", "poi-count", const SymbolLayerProperties( textField: [Expressions.get, 'point_count_abbreviated'], textFont: ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'], textSize: 12, ), enableInteraction: true, ); // 添加集群点击缩放逻辑 controller.onFeatureTapped.add((layerId, feature, point) { // 判断是否为集群要素 if (feature.properties.containsKey('point_count')) { // 解析集群坐标(GeoJSON格式为[经度, 纬度],需转换为LatLng) final coords = feature.geometry['coordinates'] as List<double>; final clusterLatLng = LatLng(coords[1], coords[0]); // 获取当前相机位置,计算目标缩放等级 controller.getCameraPosition().then((camera) { // 方案1:当前缩放等级+1,逐步展开集群 final targetZoom = camera.zoom + 1; // 方案2:直接缩放到集群解散的前一级(clusterMaxZoom -1) // final targetZoom = 13; controller.moveCamera(CameraUpdate.newLatLngZoom(clusterLatLng, targetZoom)); }); } }); }
补充说明
- 如果只想监听集群圆圈图层的点击,可以改用
controller.onCircleTapped,但需要指定监听的图层ID为poi-circles,不如onFeatureTapped通用(后者能覆盖集群数字层的点击)。 - 确保所有涉及集群的图层都设置了
enableInteraction: true,否则点击事件不会触发。
内容的提问来源于stack exchange,提问作者Rémy Albanese
相关产品推荐
相关产品推荐

