Mapbox iOS 聚类有效,但圆形样式层和数字层不是 appearing/reflecting 聚类的标记密度
Mapbox iOS clustering works, but circle style layer and numbers layer aren't appearing/reflecting the marker density of the cluster
我正在使用 Mapbox 创建一个 iOS 应用程序。该应用程序向我的 API 发出一个请求,即 returns 在地图的边界框中以 JSON 格式发生的一些事件。
我以前没有使用聚类,所以一些地图注释只是覆盖了其他的。我正在使用 this Mapbox tutorial 从 GeoJSON 文件创建一个 MGLShapeCollectionFeature
,从形状收集功能创建一个 MGLShapeSource
,然后创建一个标记层作为 MGLSymbolStyleLayer
,一个圆层作为 MGLCircleStyleLayer
,一个数字层作为 MGLSymbolStyleLayer
。标记图层在地理上显示每个单独的事件,圆形图层和数字图层一起表示每个集群的标记计数。
最终产品应该类似于 Mapbox 示例:
This is the GeoJSON file that the example uses 在世界地图上显示集群海港。
以下是该示例用于将所述 GeoJSON 转换为相关源和图层以填充地图的相关代码:
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
会创建图层正在被转换的源创建了 from/populating 地图。所以我从这个 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")
然后我从 'source' 创建图层并将它们添加到我的地图样式中。
// 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
并且海港在集群时仍显示 circle/numbers 层。
所以,我觉得自己像个白痴。
问题出在 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])
我认为,因为一些标记在与另一个标记重叠时会消失,所以它们正在聚类,但未显示聚类层。它们没有聚集,我猜形状源只能知道它们何时与另一个重叠,并相应地消失。 仅仅因为它们消失并不意味着它们聚集在一起。
我正在使用 Mapbox 创建一个 iOS 应用程序。该应用程序向我的 API 发出一个请求,即 returns 在地图的边界框中以 JSON 格式发生的一些事件。
我以前没有使用聚类,所以一些地图注释只是覆盖了其他的。我正在使用 this Mapbox tutorial 从 GeoJSON 文件创建一个 MGLShapeCollectionFeature
,从形状收集功能创建一个 MGLShapeSource
,然后创建一个标记层作为 MGLSymbolStyleLayer
,一个圆层作为 MGLCircleStyleLayer
,一个数字层作为 MGLSymbolStyleLayer
。标记图层在地理上显示每个单独的事件,圆形图层和数字图层一起表示每个集群的标记计数。
最终产品应该类似于 Mapbox 示例:
This is the GeoJSON file that the example uses 在世界地图上显示集群海港。
以下是该示例用于将所述 GeoJSON 转换为相关源和图层以填充地图的相关代码:
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
会创建图层正在被转换的源创建了 from/populating 地图。所以我从这个 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")
然后我从 'source' 创建图层并将它们添加到我的地图样式中。
// 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
并且海港在集群时仍显示 circle/numbers 层。
所以,我觉得自己像个白痴。
问题出在 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])
我认为,因为一些标记在与另一个标记重叠时会消失,所以它们正在聚类,但未显示聚类层。它们没有聚集,我猜形状源只能知道它们何时与另一个重叠,并相应地消失。 仅仅因为它们消失并不意味着它们聚集在一起。