3

我的应用程序将数据(包括坐标和其他信息)存储在本地数据库中。由于数据点的数量,该应用程序使用集群在 iOS 上使用 Mapbox 显示数据。一些标记样式基于数据,可以在运行中更改。地图设置为:

// fetch data from DB
let dataArray: [MyData] = fetchData()

// build features from data array
var features = [MGLPointFeature]()
dataArray.forEach({ (data) in
   let feature = MGLPointFeature()
   feature.identifier = data.id
   feature.coordinate = CLLocationCoordinate2D(latitude: data.lat, longitude: data.lng)
   // our attributes
   feature.attributes = [
      "amount": data.amount
      "marked": false
   ]
   features.append(feature)
})

// make and add source
let source = MGLShapeSource(identifier: "MySourceId", features: features, options: [
   .clustered: true
])
style.addSource(source)

// regular marker layer
let layer = MGLSymbolStyleLayer(identifier: "unclustered", source: source)
layer.iconImageName = NSExpression(forConstantValue: "MyIcon")
layer.text = NSExpression(forKeyPath: "amount")
layer.iconScale = NSExpression(forMGLConditional: NSPredicate(format: "%@ == true", NSExpression(forKeyPath: "marked")), trueExpression: NSExpression(forConstantValue: 2.0), falseExpression: NSExpression(forConstantValue: 1.0))
layer.predicate = NSPredicate(format: "cluster != YES")
style.addLayer(layer)

// point_count layers
...

上面的代码被简化以帮助更清楚地说明这个概念。使用 MGLPoint 数组是因为数据存储在 DB 中,因此我们没有 GeoJSON 文件或 URL。使用 MGLShapeSource 是因为需要集群,这就是我在示例中找到的。使用将“特征”作为参数的 MGLShapeSource 构造函数,因为这是与我拥有的数据匹配的构造函数。常规标记层设置为根据 iconScale 中“标记”属性的值显示不同大小的图标。

在运行期间,“marked”属性的值会发生变化(例如,当一个标记被点击时),相应的图标的大小需要更新以反映“marker”值的变化。但是,我无法弄清楚如何更改标记属性值。MGPShapeSource 仅显示对形状和 URL 的访问,这两者都不是我初始化源的特征数组。我需要访问构建源的特征数组,更改标记值,并更新标记图标。

我考虑过在每次数据更改时重新制作源。但是由于涉及的标记数量,这将表现不佳。另外,我相信我还需要重新制作所有样式层,因为它们是用实际的源对象构建的,这会使性能变得更糟。

我需要帮助弄清楚如何在运行时更改 MGLShapeSource 中 MGLPointFeature 的属性值并更新地图。

4

1 回答 1

5

我没有找到接近我所希望的解决方案,但我确实找到了比每次都重新制作所有东西更好的东西。

在要素属性值更改时,我没有重新制作所有内容,包括源和所有图层,而是使用 MGLPointFeature 数组更新源的形状。我确实必须重新制作 MGLPointFeature 数组,但是我可以用这个数组制作一个 MGLShapeCollectionFeature 并将其设置为现有源的形状。这样,现有层也不需要更改。就像是:

// build features from data array
...same as in original question, but with updated feature.attributes values as needed.

// look for existing source and update it if found; otherwise, make a new source
if let existingSource = style.source(withIdentifier: "MySourceId") {
   // update data
   guard let shapeSource = existingSource as? MGLShapeSource else {
      throw <some_error>
   }
   shapeSource.shape = MGLShapeCollectionFeature(shapes: features)
} else {
   // make new (same as original post)
   let source = MGLShapeSource(identifier: "MySourceId", features: features, options: [.clustered: true])
   style.addSource(source)
}
于 2021-03-02T00:58:14.910 回答