我正在使用 Mapbox 创建一个 iOS 应用程序。应用程序向我的 API 发出请求,以 JSON 格式返回 map 边界框内发生的许多事件。
我以前没有使用聚类,所以一些 map 注释只是覆盖了其他的。我正在使用 this Mapbox tutorial它从 GeoJSON 文件创建一个 MGLShapeCollectionFeature
,从形状集合特征创建一个 MGLShapeSource
,然后创建一个标记层作为 MGLSymbolStyleLayer
,一个圆圈层作为 MGLCircleStyleLayer
,数字层作为 MGLSymbolStyleLayer
。标记图层在地理上显示每个单独的事件,圆圈图层和数字图层一起表示每个集群的标记计数。
最终产品应该类似于 Mapbox 示例:
This is the GeoJSON file that the example uses在世界地图上显示集群海港。
以下是该示例用于将所述 GeoJSON 转换为相关源和图层以填充 map 的相关代码:
let url = URL(fileURLWithPath: Bundle.main.path(forResource: "ports", ofType: "geojson")!)
let source = MGLShapeSource(identifier: "clusteredPorts",
url: url,
options: [.clustered: true, .clusterRadius: icon.size.width])
style.addSource(source)
// Use a template image so that we can tint it with the `iconColor` runtime styling property.
style.setImage(icon.withRenderingMode(.alwaysTemplate), forName: "icon")
// Show unclustered features as icons. The `cluster` attribute is built into clustering-enabled
// source features.
let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
ports.iconImageName = NSExpression(forConstantValue: "icon")
ports.iconColor = NSExpression(forConstantValue: UIColor.darkGray.withAlphaComponent(0.9))
ports.predicate = NSPredicate(format: "cluster != YES")
style.addLayer(ports)
// Color clustered features based on clustered point counts.
let stops = [
20: UIColor.lightGray,
50: UIColor.orange,
100: UIColor.red,
200: UIColor.purple
]
// Show clustered features as circles. The `point_count` attribute is built into
// clustering-enabled source features.
let circlesLayer = MGLCircleStyleLayer(identifier: "clusteredPorts", source: source)
circlesLayer.circleRadius = NSExpression(forConstantValue: NSNumber(value: Double(icon.size.width) / 2))
circlesLayer.circleOpacity = NSExpression(forConstantValue: 0.75)
circlesLayer.circleStrokeColor = NSExpression(forConstantValue: UIColor.white.withAlphaComponent(0.75))
circlesLayer.circleStrokeWidth = NSExpression(forConstantValue: 2)
circlesLayer.circleColor = NSExpression(format: "mgl_step:from:stops:(point_count, %@, %@)", UIColor.lightGray, stops)
circlesLayer.predicate = NSPredicate(format: "cluster == YES")
style.addLayer(circlesLayer)
// Label cluster circles with a layer of text indicating feature count. The value for
// `point_count` is an integer. In order to use that value for the
// `MGLSymbolStyleLayer.text` property, cast it as a string.
let numbersLayer = MGLSymbolStyleLayer(identifier: "clusteredPortsNumbers", source: source)
numbersLayer.textColor = NSExpression(forConstantValue: UIColor.white)
numbersLayer.textFontSize = NSExpression(forConstantValue: NSNumber(value: Double(icon.size.width) / 2))
numbersLayer.iconAllowsOverlap = NSExpression(forConstantValue: true)
numbersLayer.text = NSExpression(format: "CAST(point_count, 'NSString')")
numbersLayer.predicate = NSPredicate(format: "cluster == YES")
style.addLayer(numbersLayer)
This is the GeoJSON format that my events are being returned from my API as .这种格式应该是正确的,因为 Mapbox 正在接受它并根据其数据创建一个 MGLShapeCollectionFeature
。
我的代码与 Mapbox 示例中的代码非常相似。我首先创建 GeoJSON 文件
//geoJson is my GeoJSON file as [String: Any]
var shapes: MGLShapeCollectionFeature!
if let data = try? JSONSerialization.data(withJSONObject: geoJson, options: .prettyPrinted) {
do {
shapes = try MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
} catch {
print(error.localizedDescription)
}
}
我知道此 GeoJSON 正在被转换为 MGLShapeCollectionFeature
,因为如果不转换,应用程序会崩溃,而成功创建的 MGLShapeCollectionFeature
创建了正在创建图层的源来自/填充 map 。所以我从这个 MGLShapeCollectionFeature
创建了一个 MGLShapeSource
:
let marker = UIImage(named: "redPin")?.resize(targetSize: CGSize(width: 25, height: 25))
let source = MGLShapeSource(identifier: "clusteredPoints", shape: shapes, options: [.clustered: true, .clusterRadius: 0.5])
self.mapStyle!.addSource(source)
// Use a template image so that we can tint it with the `iconColor` runtime styling property.
self.mapStyle!.setImage(marker!, forName: "marker")
然后我从“源”创建图层并将它们添加到我的 map 样式中。
// Show unclustered features as icons. The `cluster` attribute is built into clustering-enabled
// source features.
let events = MGLSymbolStyleLayer(identifier: "events", source: source)
events.iconImageName = NSExpression(forConstantValue: "marker")
events.iconColor = NSExpression(forConstantValue: UIColor.darkGray.withAlphaComponent(0.9))
events.predicate = NSPredicate(format: "cluster != YES")
self.mapStyle!.addLayer(events)
// Color clustered features based on clustered point counts.
let stops = [
5: UIColor.lightGray,
10: UIColor.orange,
20: UIColor.red,
30: UIColor.purple
]
// Show clustered features as circles. The `point_count` attribute is built into
// clustering-enabled source features.
let circlesLayer = MGLCircleStyleLayer(identifier: "clusteredEvents", source: source)
circlesLayer.circleRadius = NSExpression(forConstantValue: NSNumber(value: Double(self.mapStyle!.image(forName: "marker")!.size.width) / 2))
circlesLayer.circleOpacity = NSExpression(forConstantValue: 0.75)
circlesLayer.circleStrokeColor = NSExpression(forConstantValue: UIColor.white.withAlphaComponent(0.75))
circlesLayer.circleStrokeWidth = NSExpression(forConstantValue: 2)
circlesLayer.circleColor = NSExpression(format: "mgl_step:from:stops:(point_count, %@, %@)", UIColor.lightGray, stops)
circlesLayer.predicate = NSPredicate(format: "cluster == YES")
self.mapStyle!.addLayer(circlesLayer)
// Label cluster circles with a layer of text indicating feature count. The value for
// `point_count` is an integer. In order to use that value for the
// `MGLSymbolStyleLayer.text` property, cast it as a string.
let numbersLayer = MGLSymbolStyleLayer(identifier: "clusteredEventsNumbers", source: source)
numbersLayer.textColor = NSExpression(forConstantValue: UIColor.white)
numbersLayer.textFontSize = NSExpression(forConstantValue: NSNumber(value: Double(self.mapStyle!.image(forName: "marker")!.size.width) / 2))
numbersLayer.iconAllowsOverlap = NSExpression(forConstantValue: true)
numbersLayer.text = NSExpression(format: "CAST(point_count, 'NSString')")
numbersLayer.predicate = NSPredicate(format: "cluster == YES")
self.mapStyle!.addLayer(numbersLayer)
所以代码本质上是完全一样的,只是输入的 GeoJSON 不同。然而,当事件标记聚集时,圆圈层和数字层并没有出现。见下文:
我知道问题不在于 Mapbox 示例的源是从 URL 加载的,而我的实现的源是从 MGLShapeCollectionFeature
加载的,因为我已经尝试加载 Mapbox 示例的海港GeoJSON 作为 MGLShapeCollectionFeature
并且海港在集群时仍然显示圆圈/数字层。
最佳答案
所以,我觉得自己像个白痴。
问题出在 MGLShapeSource 中:
MGLShapeSource(identifier: "clusteredPoints", shape: shapes, options: [.clustered: true, .clusterRadius: 0.5])
无论出于何种原因,我一直在摆弄 clusterRadius,并将其设置为 0.5,我认为它以点为单位。请注意,该示例使用标记的宽度来确定簇半径。
let source = MGLShapeSource(identifier: "clusteredPorts",
url: url,
options: [.clustered: true, .clusterRadius: icon.size.width])
我认为,因为一些标记在与另一个标记重叠时会消失,所以它们正在聚类,但未显示聚类层。它们没有聚集,我猜形状源只能知道它们何时与另一个重叠,并相应地消失。 仅仅因为它们消失并不意味着它们聚集在一起。
关于ios - Mapbox iOS 集群有效,但圆形样式层和数字层未出现/反射(reflect)集群的标记密度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55735834/