Кластеризация Mapbox iOS работает, но слой в стиле круга и слой чисел не отображаются / не отражают плотность маркеров кластера

Я использую Mapbox для создания приложения для iOS. Приложение получает запрос к моему API, который возвращает ряд событий, происходящих в ограничивающей рамке карты в формате JSON.

Раньше я не использовал кластеризацию, поэтому некоторые аннотации к карте просто закрывали другие. Я использую это руководство по Mapbox, которое создает MGLShapeCollectionFeature из файла GeoJSON, создает MGLShapeSource из функции сбора фигур, а затем создает слой маркера как MGLSymbolStyleLayer, слой круга как MGLCircleStyleLayer и слой чисел как MGLSymbolStyleLayer. Слой маркеров показывает каждое отдельное событие географически, слой круга и слой чисел объединяются, чтобы представить количество маркеров в каждом кластере.

Конечный продукт должен быть похож на пример Mapbox:

введите описание изображения здесь

Это файл GeoJSON, который в примере используется для отображения кластерных морских портов на карте мира.

Ниже приведен соответствующий код, который в примере используется для преобразования указанного 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)

Это формат GeoJSON, в котором мои события возвращаются из моего API как. Это форматирование должно быть правильным, поскольку 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 created успешно создает источник, из которого создаются слои / заполняется карта. Итак, я создаю MGLShapeSource из этого MGLShapeCollectionFeature:

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")

Затем я создаю слои из «источника» и добавляю их к стилю моей карты.

// 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, потому что я пытался загрузить морские порты GeoJSON из примера Mapbox как MGLShapeCollectionFeature, а морские порты по-прежнему показывают круг / нумерация слоев при кластеризации.


person David Chopin    schedule 17.04.2019    source источник
comment
Могу я вам с этим помочь? пожалуйста, поделитесь исходным кодом ..   -  person Mehul Mistri    schedule 19.04.2019
comment
@MehulMistri ты здесь из проекта фрилансера? Я думаю, что предоставленного кода должно быть достаточно, чтобы повторить проблему   -  person David Chopin    schedule 19.04.2019
comment
Уважаемый, я не из проекта фрилансера, я всегда проверяю новые вопросы .. Если вы думаете, что я могу вам помочь, то предоставьте исходный код .. Это поможет :)   -  person Mehul Mistri    schedule 19.04.2019
comment
@MehulMistri, вам нужен весь код для этого конкретного контроллера представления?   -  person David Chopin    schedule 19.04.2019
comment
Мне нужен полный исходный код   -  person Mehul Mistri    schedule 19.04.2019
comment
@MehulMistri Я могу добавить вас в проект GitHub?   -  person David Chopin    schedule 19.04.2019
comment
Было бы здорово, но здесь конец дня, я могу помочь тебе завтра   -  person Mehul Mistri    schedule 19.04.2019
comment
@MehulMistri Я свяжусь с вами завтра, спасибо!   -  person David Chopin    schedule 19.04.2019
comment
@MehulMistri, дайте мне знать, если у вас сегодня будет свободное время, чтобы взглянуть на это   -  person David Chopin    schedule 20.04.2019


Ответы (1)


Так что чувствую себя идиотом.

Проблема была в 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])

Я подумал, что, поскольку некоторые из маркеров исчезали всякий раз, когда они перекрывались с другим маркером, они кластеризовались, но слой кластера не отображался. Они не были кластеризованы, я предполагаю, что источники форм просто могут знать, когда они перекрываются с другим, и соответственно исчезнут. То, что они исчезают, не означает, что они сгруппированы.

person David Chopin    schedule 20.04.2019