Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility to get current map style state #1982

Closed
averas opened this issue Jan 23, 2016 · 19 comments · Fixed by #2063
Closed

Possibility to get current map style state #1982

averas opened this issue Jan 23, 2016 · 19 comments · Fixed by #2063

Comments

@averas
Copy link
Contributor

averas commented Jan 23, 2016

I'm probably using a non-supported way to pass styles between two map instances using map.style.stylesheet which works quite good. The obvious problem with this approach is that I don't get any sources or layers that were added programmatically to the map. Could the API be extended with a getStyle() method which returns the current effective style including sources and layers added programmatically? Essentially I want to be able to do map2.setStyle(map1.getStyle())...

@ryanbaumann
Copy link
Contributor

+1, this would be great.

Currently for each new map element that I create or switch styles + layers between, I need to:

  1. map.setStyle(newstyle)
  2. Start a for loop for each source/layer from the old map style
  3. map.addSource(source1...n from old map)
  4. map.addLayer(layer1...n from old map)
  5. End loop

If that could be condensed into one function call, that would be much more succinct and simple from a user perspective.

Not sure if the WebGL canvas limits this or not (reusing layer objects between canvases).

@indus
Copy link
Contributor

indus commented Jan 25, 2016

👍 Providing free combinations of mapbox "baselayers" (dark, bright, etc) and custom overlays (scene1, scene2, scene3, etc) to the user gives me the same need. Loading a complete fresh style is as ugly as removing and adding only the custom sources and layers to the style in the moment.

I think some sort of bundeling/grouping for Layers and Sources would be a nice solution (e.g. map.removeSources({group:'myCustomOverlay'}))
Or lets call them StyleFraments. A combination of layers and sources that could be added or removed to/from the "basestyle".

@lucaswoj
Copy link
Contributor

Could you give a more thorough description of your use case? Why can't you create a full stylesheet including the basemap and your custom layers (i.e. in Mapbox Studio)?

  • a Map#getStyle method is a feature I'd be willing to consider
  • an API for overlaying a style over another style is a feature I'd be willing to consider

@indus
Copy link
Contributor

indus commented Jan 25, 2016

I'm using mapbox-gl-js to make a showcase app for a gis service of my company. In the moment there are 3 showcases (think of them as locations or scenes), each with 4-6 timesteps. Every timestep has at least one raster dataset (satellite image) and a bunch of vector data (with symbols, labels, and of course all kind of GeoJSON data). Within a scene the vector data may or may not be similar. So every timestep comes with 10-20 mapbox style layers and 2-5 sources.
The user of course should be able to switch between the scenes and also the timesteps. And it would be nice to switch the "baselayer" independent (the OSM vector tiles provided by MB: dark, light, etc.). Because there will be more showcases in the future I need a system that scales well. Having baselayer x scene x timesteps complete stylesheets feels wrong to me and also would give me more flickering when switching between them. So I deliver a "StyleFragment" for every dataset that has to be combined with the current selected basestyle in the client (a loop over addSource and addLayer). But I also have to tear the active stylesheet apart when the user changes the scene or timestep (a loop over removeSource and removeLayer that filters stuff of the baselayer out). Both is possible but not in a very nice way.
I think a seperation in Baselayer/Overlay, custom grouping of layers and sources or something like StyleFragments (like DocumentFragments in the DOM) would be a nice feature to adress this issues.

@lucaswoj
Copy link
Contributor

This ticket is getting a little off track. Please try to focus on a single feature request, StyleFragments or a getEffectiveStyle API.

I think the solution to your use case that best fits with our roadmap is to make all map mutations (adding layers, changing basemap, etc) to an external stylesheet object and use the (planned) "smartSetStyle" API #1341 to smoothly update your map.

@indus
Copy link
Contributor

indus commented Jan 25, 2016

Sorry for hijacking this issue...#1341 is what i was searching for. But it is closed? And the "folloups" is discussing dynamic data and not dynamic styles...

@lucaswoj
Copy link
Contributor

You're right.

Closing -- let's revisit diffing setStyle once the constants situation in v8 resolves. That may make it easier to generate JSON from internal objects. -- #1348 (comment)

This comment suggests we should re-open a "setStyle" diffing issue.

@lucaswoj
Copy link
Contributor

Opened a new ticket at #1989

@lucaswoj
Copy link
Contributor

I'm going to call both StyleFragments and getEffectiveStyle "wontfix"es for now. Please move discussion about a smarter setStyle to #1989

@averas
Copy link
Contributor Author

averas commented Jan 26, 2016

@lucaswoj The reason why I wanted to get/copy the map state was that I currently use the map as the "master" for my current style state.

The reason for this is exactly what you have discussed in this thread, that I want to be able to transition between style states, and even though it would be possible to maintain a separate style object which I then manually diff and restyle my map against it would be quite an effort to implement, which you certainly know as this is pretty much what you will have to do for the transitioned Map#setStyle().

If Map#setStyle() could handle the transition I would maintain a separate style object and my need for a Map#getStyle() would vanish.

@lucaswoj
Copy link
Contributor

Sounds like we should focus our efforts on #1989 👍

@averas
Copy link
Contributor Author

averas commented Feb 3, 2016

@lucaswoj One thing I realised is that GeoJSON sources are part of the style, so replacing the entire style will also remove all sources added programmatically, unless part of the style I provide.

Even with a smart, transitioned, Map#setStyle() I see significant cost in potentially diffing large GeoJSON sources attached to the style.

In my world a clearer separation between data (sources) and presentation (layers) would be appealing.. whereas today they're part of the same semantic object (style).

@lucaswoj
Copy link
Contributor

lucaswoj commented Feb 3, 2016

Even with a smart, transitioned, Map#setStyle() I see significant cost in potentially diffing large GeoJSON sources attached to the style.

If the source data doesn't change, there will be a negligible cost to calling setStyle with it. That is, unless you're using a GeoJSON source with a very large inline data: { ... } attribute, in which case

  • you would really benefit from passing a url instead of inline data (I understand this isn't always possible)
  • you're already paying this cost if you ever call setData
  • we're looking at reducing this cost in Optimize the GeoJSON ⇢ worker transfer #1504

@averas
Copy link
Contributor Author

averas commented Feb 3, 2016

you would really benefit from passing a url instead of inline data (I understand this isn't always possible)

As you point out, providing a URL instead of an object isn't always possible. I apply tons of filtering etc. client side.

you're already paying this cost if you ever call setData

For sure! But there will certainly be times when I want to change the data without changing the style, and , more importantly, times when I want to change the style without changing the data.

Use case example:

  1. I download a GeoJSON with ~10.000 points to the browser
  2. I use Source#setData() to present the initial data set to the user
  3. The user applies some filters whereas I call Source#setData() again (at this point I do maintain an unfiltered and a filtered version of my GeoJSON)
  4. The user wants to increase the circle size of the markers

At this point I will have to fall back to Map#setPaintProperty() or, provide the entire GeoJSON again if I use Map#setStyle() (which would have to be processed again). What I really would like to do is something in the line of Map#setStyleLayers(...)..

@lucaswoj
Copy link
Contributor

lucaswoj commented Feb 3, 2016

Map#setStyleLayers(...) strikes me as a good compromise 👍

@jfirebaugh
Copy link
Contributor

I support adding a getStyle method that returns the current effective style. That seems like a useful API that's orthogonal to existing APIs.

@averas The way I'd recommend implementing your use case is:

  • For filtering, use setFilter on layers, rather than setData on the source
  • For changing the circle size, use setPaintProperty

@averas
Copy link
Contributor Author

averas commented Feb 3, 2016

@jfirebaugh

For filtering, use setFilter on layers, rather than setData on the source

setFilter is great if you only want to filter the data set for the geographical representation. I, however, often have a combination of visualisations illustrating the data set from other angels, such as charts and diagrams, which is why I mostly apply filtering higher up in the stack.

This is an example of what I do:

filters

So far setData() has not posed a limit in regards to the size of my datasets.

For changing the circle size, use setPaintProperty

Yup, and this works fine when only changing a single property, but becomes cumbersome (and slow) when I start applying several properties (especially layout properties) to tens or even hundreds of layers.
Calling setLayoutProperty(layer, "visibility", "none") on 100 layers takes 5-7 seconds to carry out. I will try and use the batch API to see if things speed up a bit.

@lucaswoj lucaswoj mentioned this issue Feb 4, 2016
3 tasks
@jfirebaugh jfirebaugh reopened this Feb 4, 2016
lucaswoj pushed a commit that referenced this issue Feb 4, 2016
lucaswoj pushed a commit that referenced this issue Feb 4, 2016
lucaswoj pushed a commit that referenced this issue Feb 4, 2016
lucaswoj pushed a commit that referenced this issue Feb 5, 2016
lucaswoj pushed a commit that referenced this issue Feb 5, 2016
lucaswoj pushed a commit that referenced this issue Feb 5, 2016
lucaswoj pushed a commit that referenced this issue Feb 5, 2016
@lucaswoj
Copy link
Contributor

lucaswoj commented Feb 5, 2016

@averas @ryanbaumann @indus This API has been added in master and should go out in a release sometime early next week 😄

@averas
Copy link
Contributor Author

averas commented Feb 5, 2016

Great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants