-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
performance degrades with multiple sources vs a single source #1484
Comments
Did some experiments with this a while back. The performance issues we saw were primarily related to number of unique layers, not number of sources. Could be this in your case as well. Lots of geoJSON sources mainly affected tile parsing speed iirc, but we didn't see much performance degradation on desktop until we reached 200+ mb of added geoJSON data. For making a choropleth, I'd recommend you add the data as a single geoJSON source (if it is huge, serve it as .mbtiles) – and then create as few layers as possible (one for each color) and set the layer filter on the fly for each color. Also, if you want/need a livable mobile experience – try to stick with less than 120 layers in total. We're seeing consistent crashing on iPhone 6 after tipping 150. Don't even want to think about whats happening on older iOS devices. Android devices fares a lot better in general. |
Oh, @kristfal interesting. That's worth investing more. How where you able to create multiple layers for a single geojson source? Would love to give that a try, just don't see how that's possible. From what I've observed (checkout the flame graph in the second screenshot above), a lot of time is spent in |
@vicapow Can you use a URL in the |
@vicapow Call addlayer after you add source. Here is a generic method I use for adding, updating and removing geoJSON data and styles. Using Polymer data bindings, hence one argument. Object structure looks like this: {
"layers": {
"layer1": {
"id": "layer1",
"type": "line",
"interactive": true,
"source": "geoJSON",
"paint": {
"line-color": "#7EC4ED",
"line-width": 5,
"line-opacity": 0.3
}
},
"layer2": {
"id": "layer2",
"type": "line",
"interactive": true,
"source": "geoJSON",
"paint": {
"line-color": "#7EC4ED",
"line-width": 5,
"line-opacity": 0.3
}
}
},
"source": "geoJSON",
"data": {
"type": "FeatureCollection",
"features": [
{
(...)
}
]
}
} Method: /**Add, update or remove geoJSON data and layers
*/
setGeoJSON: function (object) {
var ls = object,
sourceObj
// Remove existing layers if present
Object.keys(ls.layers).forEach(function (key) {
try {
this.mgl.removeLayer(Object.keys(ls.layers)[i]);
} catch (err) {
// No layers to remove. Improvement: If mgl exposes getlayer, use if instead of try.
}
});
// Remove existing source if present.
if (this.mgl.getSource(ls.source)){
this.mgl.removeSource(ls.source);
}
// Update source and set style if data is present.
if (ls.data !== null) {
// Set new source
sourceObj = new mapboxgl.GeoJSONSource({
data: ls.data
});
this.mgl.addSource(ls.source, sourceObj);
// Set new layers
this.mgl.batch(function (batch) {
Object.keys(ls.layers).forEach(function (key) {
batch.addLayer(ls.layers[key]);
});
});
}
} |
Oh, I see it is using it for |
@jfirebaugh The method was made in mind for adding/removing one source at the time along with multiple styles, no other reason – otherwise I'd add batch for When it comes to On a side note: try/catch feels quite cheap. Would be great to expose getLayer. |
@kristfal In your example snippet, how is that enough information to know what feature to use? Is the layer ID also used to find the associated feature in the feature collection? |
@vicapow Ah, yes, forgot to detail that part. Expanded continuation of last example: Pass along properties in the geoJSON object. "data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[
10.63881115057565,
59.9132451089657
],
[
10.63893210143842,
59.91327620582647
]
]
},
"properties": {
"id": "55d44052d1b00f4d38dbb446"
}
}
]
} Set style filters that matches the properties: "layer2": {
"id": "layer2",
"type": "line",
"interactive": true,
"source": "geoJSON",
"filter": [
"==",
"id",
"55d44052d1b00f4d38dbb446"
],
"paint": {
"line-color": "#7EC4ED",
"line-width": 5,
"line-opacity": 0.3
}
} You can update filters afterwards with setFilter. If you want to update multiple layers at the same time, be sure to use the batch API if you can. It is a lot faster than iterating. |
@kristfal You mention serving a layer as .mbtiles which sounds interesting to me. The advantage would be that just data in the viewport is 'served' right? How would that work exactly? I suppose following components are needed!?:
Did you manage to get this working? |
Hey @musicformellons,
|
Using multiple sources instead of just one, produces a notice impact on performance. The use case is for creating a choropleth so might not be relevant once data drive styles lands.
Single Source
### Multiple Sources
The text was updated successfully, but these errors were encountered: