-
-
Notifications
You must be signed in to change notification settings - Fork 786
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
GeoJSON Feature properties stringified in map events #1325
Comments
I think there was a similar issue related to ids of geojson features. |
Thanks @HarelM, could you point me to the direction of investigation? I'm not familiar with the codebase. I've already looked through the code of GeoJSON sources and workers but couldn't spot anything obviously wrong. |
Geojson source and worker would be my guess as well... |
Does this not be because of the fact that originally geojson (see geojson.org) defines so called ‘ OpenGIS Simple Features Implementation Specification’ features, in which properties almost always is a table like (not tree like) structure? |
GeoJSON.js supports object properties just fine: https://codepen.io/sergey-shishkin/pen/gOegopW. |
- variables are indexed with normailzed name - feature data panel proto - time variables are indexed and retrieve from GeoJson nested props - see maplibre/maplibre-gl-js#1325
The serialize/deserialize implementations seem fishy to me.
Edit: I missed the obvious; this does rest on the structured clone algorithm but it does more work to maintain object classes. It still looks like a footgun in places (like as a side effect, it implicitly guts the buffers of the source object). I would look at the custom deserializer of |
I am facing the same problem and I have to confess that it took me awhile to understand that was Maplibre who was "stringifying" the Edit: Any object inside properties are being serialized. |
@HarelM @rotu I have been trying to debug this issue but it is bit more complex than I initially thought. I might be wrong but the issue here seems to come from loadVTLayers(): {[_: string]: VectorTileLayer} {
if (!this.vtLayers) {
this.vtLayers = new vt.VectorTile(new Protobuf(this.rawTileData)).layers;
this.sourceLayerCoder = new DictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']);
}
return this.vtLayers;
} The On line 203 feature is serialized: const sourceLayerName = this.sourceLayerCoder.decode(sourceLayerIndex);
const sourceLayer = this.vtLayers[sourceLayerName];
const feature = sourceLayer.feature(featureIndex); All objects inside properties are returned as stringified: I am not sure how to approach for a solution as it seems to be in a mapbox library. Maybe a function to try to deserialize the properties in |
Ahh, that's interesting. |
@HarelM That sound good, I have just worked in a workaround, tell me what do you think? import vt from '@mapbox/vector-tile';
export function deserializeFeature(feature: vt.VectorTileFeature) {
if (!feature || Object.keys(feature.properties).length === 0) {
return feature;
}
for (const key in feature.properties) {
if (typeof feature.properties[key] === 'string') {
try {
feature.properties[key] = JSON.parse(feature.properties[key] as string);
} catch (e) {
continue;
}
}
}
return feature;
} This actually works and I will probably need to implement this in my project so I can make it work. But with this code GeoJSONFeature already returns all objects. It can be more detailed and check if there is an object inside the string but I am not sure about performance though. |
@guimochila I use a similar approach but use superjson to ensure function serializeFeature(f: Feature): Feature {
return {
...f,
properties: {
...f.properties,
_json: superjson.stringify(f.properties),
},
};
}
function deserializeFeature(f: Feature): Feature {
const json = f.properties._json as string;
if (!json) return f;
const properties = superjson.parse(json) as FeatureProperties;
f.properties = Object.assign({}, f.properties, properties);
return f;
}
This is likely not the most efficient way though. |
@shishkin That looks nice, however I agree with you this is maybe not the most efficient way and I guess the issue still in the |
I am just wondering if this is really a bug in |
From my point of view, serialization and deserialization should always be symmetric - if you can serialize an object with properties without an error saying it's not supported then deserializing it back should return a clone of the original object. |
@HarelM, |
Well... 5 days isn't a lot to wait (although I agree this repo isn't very active). |
@HarelM @guimochila |
The main question here is if someone would like to fork and maintain it, otherwise, we'll be in the same situation, but with a fork... |
No worries! |
Apologies for leaving https://github.com/mapbox/vector-tile-js unmaintained for so long — I revived and modernized it recently (see v2.0 and plans for v3). Regarding the issue at hand — unfortunately, this is limited not by encoding/decoding but by the Vector Tile Specification itself. The MVT spec doesn't have a way of encoding nested properties. Perhaps the new MRT format could address this. |
maplibre-gl-js version: 2.1.9
browser: Chromium 101.0.4951.64
Steps to Trigger Behavior
typeof e.features[0].properties.foo
Link to Demonstration
https://codepen.io/sergey-shishkin/pen/YzazqxO
Expected Behavior
Event feature
properties
should have same structure as original data source.Actual Behavior
Event feature
properties
turned to strings.The text was updated successfully, but these errors were encountered: