mapbox / mapbox-gl-native

Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL
https://mapbox.com/mobile
Other
4.37k stars 1.33k forks source link

Add and modify individual features in a GeoJSON source on the fly #6177

Open 1ec5 opened 8 years ago

1ec5 commented 8 years ago

In order for the runtime styling API to have parity with the annotation API, it needs to be possible to modify a GeoJSON source more granularly. #6159 tracks making MGLGeoJSONSource’s data mutable, but the developer would still need to set the source’s entire data in one shot. That’s a dealbreaker for the most common use cases of point annotations. For example:

With the annotation API, each of these cases (except for #6160) is straightforward – just a line of code. By contrast, with the runtime styling API, the developer needs to obtain the entire source data, mutate it, then feed the result back into the source every time a modification is needed. This can be terribly inconvenient, not to mention less performant than dealing with annotations.

Per https://github.com/mapbox/mapbox-gl-native/issues/5626#issuecomment-232391207, no core support is planned for granular GeoJSON modification, so it’d be up to MGLGeoJSONSource itself to handle the source data mutation and feed the result back into the underlying source object. Hopefully performance won’t be an issue with that approach.

/cc @incanus @jfirebaugh @frederoni

rmnblm commented 7 years ago

Just came across this issue because I was in need for this feature.

While looking for a workaround, I faced other problems: I tried to exchange the whole GeoJSON source. First I removed the old GeoJSON source with mapView.style().remove(geoJSONSource) followed by creating a new instance of MGLGeoJSONSource with the updated .geojson file. Then I added it with mapView.style().add(geoJSONSource). I'm pretty sure that this will be a performance issue with a huge .geojson file, when only a few points have been updated.

Another problem: The MapView doesn't re-render itself after updating the source, only when I drag the map around the updated GeoJSON source is visible. I fixed this with a little workaround because I couldn't find any update() or reload() method.

let currentCenter = mapView.centerCoordinate
let newCenter = CLLocationCoordinate2D(latitude: currentCenter.latitude + 0.000001, longitude: currentCenter.longitude)
mapView.centerCoordinate = newCenter
mapView.centerCoordinate = currentCenter

exchange_source

1ec5 commented 7 years ago

I'm pretty sure that this will be a performance issue with a huge .geojson file, when only a few points have been updated.

Yes, that’s the point I was trying to make in https://github.com/mapbox/mapbox-gl-native/issues/5626#issuecomment-231545691. Since support for incremental GeoJSON source updates isn’t planned in core, we’d have to implement this important functionality at the SDK level. So whatever performance issues you see with your implementation (serializing and deserializing the entire GeoJSON structure, for instance) will unfortunately remain.

The MapView doesn't re-render itself after updating the source, only when I drag the map around the updated GeoJSON source is visible.

We just released v3.4.0-alpha.5, which contains #6201. Does that address the problem?

1ec5 commented 7 years ago

MGLPointAnnotation and MGLMultiPoint (MGLPolyline, MGLPolygon) can both be mutable. When the developer adds an MGLPointFeature, MGLPolylineFeature, or MGLPolygonFeature to a MGLGeoJSONSource, they may expect the source to update automatically as the geometry changes, not just when individual features are added and removed. That would require something similar to the key-value observation in MGLMapView that we added in #3835 and #6565. MGLGeoJSONSource would have to keep all the MGLFeature objects around, just as MGLMapView does for annotations, and regenerate the entire mbgl GeoJSON structure any time anything changes. To reduce overhead, we could rely on feature identifiers, when present, to modify only the affected part of the GeoJSON structure.

rmnblm commented 7 years ago

Just read your comment @1ec5. Based on your previous comment this can (must?) be done at the SDK level so it's something I'm confident to resolve and find a solution. Are there any more ideas in your head which may help me?

1ec5 commented 7 years ago

I'm hearing that a solution down in mbgl is no longer off the table, but that it's a difficult proposition. An SDK-level solution is needed anyways if we're to track changes within an MGLFeature object.

We just released beta 1, which has #6524, which should make the task here quite a bit easier.

boundsj commented 7 years ago

@rmnblm @1ec5 just noting that I've opened https://github.com/mapbox/mapbox-gl-native/pull/6777 to address #6159. #6777 allows you to mutate the features property of MGLGeoJSONSource and that mutation will trigger map updates. However, #6777 will not attempt to monitor for and react to changes to the features themselves as discussed above.

incanus commented 7 years ago

In case you know OTOH @1ec5, is this still relevant? The way I'm seeing the current API, you can modify MGLShapeSource.shape; however it is a copy property, so likely not as efficient as desired. I dig into the current state of things if it's helpful.

1ec5 commented 7 years ago

Yes, this is still relevant. #7458 would streamline shape source updating somewhat from the perspective of application code, but the fact remains that something (whether application code or SDK code) still has to blow away the entire source and recreate it every time you want to modify any detail about an individual shape or its vertices. By contrast, you can update annotations very performantly because existing annotations are never removed in the process. This is currently a fundamental deficiency of the runtime styling API versus the annotation API.

mourner commented 5 years ago

See also https://github.com/mapbox/geojson-vt/issues/26

stale[bot] commented 5 years ago

This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.

Vhora01 commented 5 years ago

I want to fill Mapbox map with data again ,when refresh button click.i remove source and layer from map .but 'MGLRedundantSourceIdentifierException', reason: 'Source mapSource already exists' error is appeared

stale[bot] commented 4 years ago

This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.

stale[bot] commented 4 years ago

This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.