Custom data - support coordinateProperties
Followup from the recent PMTiles / Vector Tiles work: #1016
Our custom data layer supports various formats but they all end up converted into GeoJSON.
Sometimes - we end up with an extra data element called coordinateProperties. This is an extension of GeoJSON that's not really standard but is still widely recognized.
https://github.com/mapbox/geojson-coordinate-properties
The gist of it is: for each coordinate in the Array, you can look up a corresponding bunch of properties that go with that coordinate in another Array. It's pretty common for any kind of workout data:
Anyway we shouldn't just do the [object Object] thing here - we should actually make nodes that have those properties.
@voscarmv - prospective issue for you to work on!
@bhousel can you supply a dataset URL with some of this data? I would like to get oscar started with this.
This one includes some extra trackpoint data for the elevation values: https://rapideditor.org/rapid#background=Bing&gpx=https://sonny.7thposition.com/osm/escarpment_trail.gpx
Oscar- here are some code pointers for you to look at.
Background
The data URL Bryan provided has the following shape in XML:
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="Garmin Connect" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<script/>
<metadata>
<link href="connect.garmin.com">
<text>Garmin Connect</text>
</link>
<time>2014-07-27T13:25:06.000Z</time>
</metadata>
<trk>
<name>Escarpment Trail Run</name>
<trkseg>
<trkpt lon="-74.1896016150713" lat="42.312879441305995">
<ele>547.5999755859375</ele>
<time>2014-07-27T13:25:06.000Z</time>
</trkpt>
<trkpt lon="-74.18951326981187" lat="42.31288396753371">
<ele>559.5999755859375</ele>
<time>2014-07-27T13:25:10.000Z</time>
</trkpt>
<trkpt lon="-74.18948912993073" lat="42.31287952512503">
<ele>555.4000244140625</ele>
<time>2014-07-27T13:25:11.000Z</time>
</trkpt>
... GPX data continues
</trkseg>
</trk>
This data is processed by Rapid's custom-data processor and converted to GeoJSON. You won't see coordinateProperties mentioned anywhere in Rapid's code because this processing is done by a third-party module: @tmcw's togeojson module, imported like this:
import { gpx, kml } from '@tmcw/togeojson';
This module takes the gpx track above, ingests the <ele> and <time> tags for each point, and then puts them in a separate CoordinateProperties blob on the geoJSON as per the spec Bryan linked, along with the track name, type, and time the track was saved.
This results in the undesirable display of the 'tags' data up above, where the coordinateProperties is just getting toString() called on it, hence the [object Object] display.
This problem is interesting because coordinateProperties is a special-case blob of data.
If you run Rapid in the debugger, and set a breakpoint at https://github.com/facebook/Rapid/blob/main/modules/ui/sections/raw_tag_editor.js#L163 you will see the rowData being fed to the ui renderer in the sidebar- the coordinate Properties is 700+ entries, one for each 'point' in the GPX track.
The Task
So, the answer here is not to render all 700 points' worth of data in the tag editor- the data would run off the screen. The answer is actually to render the individual points on the map, along with the way that's already being rendered. Then, we must give each of those points the coordinateProperty entry that corresponds to it.
Therefore, we need to do the following:
-
[ ] Stop rendering 'coordinateProperties' as a top-level tag when the custom data entity is clicked on. You may be tempted to add some code right in https://github.com/facebook/Rapid/blob/main/modules/ui/sections/raw_tag_editor.js to do this, but instead we should prevent the coordinateProperties data from being bound to the way and sent to the renderer in the first place.
-
[ ]
-
[ ] Start rendering individual points in the custom data layer [modules/pixi/PixiLayerCustomData.js]. (https://github.com/facebook/Rapid/blob/main/modules/pixi/PixiLayerCustomData.js)
To get you started, we already do render some points in the custom data renderer- but only if they are provided as a Point or MultiPoint geojson type: https://github.com/facebook/Rapid/blob/main/modules/pixi/PixiLayerCustomData.js#L96
You can start by extracting the points out of the track and just rendering them as points as well-don't worry about the coordProperties for this step.
- [ ] once you get the points to render, we'll need to attach the coordinate properties data to them. You'll need to augment the points you're asking the renderer to display, and also bind the custom data from the coordinateProperties to each point. This should, in theory, display the individual
-[ ] Finally, once you have the point data rendering with the coordinateProperties, see if you can figure out how to make the points rendering conditional on hover/select like the OSM ways already are. Vid:
https://github.com/facebook/Rapid/assets/1887955/79d2ddf6-e9e4-47a8-af79-c1a2da4e2033
See how the points are only revealed when hovered over in the OSM way? Instead of just always rendering every custom data node, we should do the same thing. See if you can figure out how the pixiLayerOSMData.js file conditionally renders the node data on hover, then implement some similar logic in your renderer for the custom data.
related: https://github.com/openstreetmap/iD/pull/11636 This sort of sidesteps the issue by stringifying the data.