Map: OSM provider - Add route calculation and rendering - #35108
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Failed route calculations currently create phantom routes and fire misleading route-added events.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds callback-driven OSM route calculation and OpenLayers vector rendering, including projection-aware bounds and antimeridian handling.
Changes:
- Adds route parsing, rendering, styling, lifecycle handling, and viewport fitting.
- Registers required OpenLayers vector APIs.
- Expands unit tests, mocks, and Storybook coverage.
File summaries
| File | Description |
|---|---|
osmTests.js |
Tests OSM route behavior and lifecycle. |
openLayersMock.js |
Mocks vector layers, features, geometry, and styles. |
openlayers.register.js |
Registers OpenLayers vector dependencies. |
provider.dynamic.osm.ts |
Implements route calculation and provider integration. |
provider.dynamic.osm.test.ts |
Tests route-aware bounds. |
provider.dynamic.osm.route.ts |
Parses routes and normalizes longitudes. |
provider.dynamic.osm.route.test.ts |
Tests route parsing and longitude handling. |
provider.dynamic.osm.openlayers.utils.ts |
Extends OpenLayers interfaces and validation. |
provider.dynamic.osm.openlayers.utils.test.ts |
Updates API validation fixtures. |
provider.dynamic.osm.openlayers.ts |
Renders and disposes vector routes. |
provider.dynamic.osm.engine.ts |
Adds route contracts to the engine API. |
routes.ts |
Provides static Storybook route data. |
OSMMap.stories.tsx |
Demonstrates configurable OSM routes. |
Review details
- Files reviewed: 13/13 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Remove-only updates leave auto-adjusted viewports stale, and missing routing configuration can produce duplicate warnings.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 13/13 changed files
- Comments generated: 2
- Review effort level: Balanced
EugeniyKiyashko
left a comment
There was a problem hiding this comment.
14. Minor - general comment. packages/devextreme/js/ui/map.d.ts:409 is not part of this diff, so this one cannot be anchored to a line.
calculateRoute?: (params: CalculateOsmRouteInfo) => PromiseLike<OsmRouteResult> does not allow undefined, although the implementation and the tests support "no result", while calculateLocation right next to it does allow undefined. The implementation also accepts a plain, non-promise return value, which the type does not. Worth aligning to OsmRouteResult | undefined and possibly allowing a non-promise return.
| return this._renderRoute(options).then((routeObject) => { | ||
| if (routeObject.engineRoute) { | ||
| this._routes.push({ ...routeObject, options }); | ||
| this._fireRouteAddedAction({ options, originalRoute: routeObject.instance }); | ||
| } |
There was a problem hiding this comment.
4. Important. A failed route is not stored in _routes and fires neither onRouteAdded nor onRouteRemoved, but it stays in option('routes'). This is better than google, which stores a dummy object and raises onRouteAdded anyway, and the choice is deliberate and covered by tests. Two consequences, though:
- a visible difference in public behaviour between providers;
option('routes')and what is actually drawn diverge, and the application only learns about it from the console.
This needs an explicit line in the provider documentation. It is also worth discussing whether onRouteAdded should fire with originalRoute: undefined, so an application can react to the skip.
There was a problem hiding this comment.
agree that this should be documented, will notify the doc team
| if (previousProjection !== projection) { | ||
| this._routeSource?.getFeatures().forEach((feature) => { | ||
| feature.getGeometry()?.transform(previousProjection, projection); | ||
| }); | ||
| } |
There was a problem hiding this comment.
10. Minor. The geometry is transformed in place. Markers recover on their own because their position is recomputed from latitude and longitude every time, but routes do not: calling setUserProjection() after routes have been added leaves them in the old coordinate system, and there is no change:view event in that case.
Keeping the original waypoints on the route handle and rebuilding the geometry would be more robust. It would also avoid accumulating error from repeated transforms: latitude of 90 degrees, which getRouteLocations allows, is clamped to about 85.05 in EPSG:3857.
There was a problem hiding this comment.
currently, we assume that the global user projection is configured before map initialization
a separate sync mechanism will is needed if we allow changing projection at runtime, keeping the original coordinates would not solve this case. Let's keep this as is and wait for user feedback
| const locations: MapLocation[] = []; | ||
| for (const coordinate of coordinates) { | ||
| if (!Array.isArray(coordinate) | ||
| || (isGeoJson ? coordinate.length < 2 : coordinate.length !== 2) |
There was a problem hiding this comment.
11. Minor. The two formats are checked with different strictness: GeoJSON positions may carry extra components (length of at least two, elevation ignored), while tuples must have exactly two. Because of that, a result made of [lat, lng, elevation] tuples drops the whole route. One rule for both would be more predictable - either both tolerate extra components, or neither does.
There was a problem hiding this comment.
our tuple contract is [lat, lng], and GeoJSON allows a third altitude coordinate, we do not use it
let's keep these checks and document the coordinate order and altitude handling :)
There was a problem hiding this comment.
🟢 Approval recommended
The implementation is cohesive and supported by extensive validation, lifecycle, projection, and integration coverage.
Review details
- Files reviewed: 16/16 changed files
- Comments generated: 0 new
- Review effort level: Balanced
we handle Synchronous results are also tolerated internally, but this does not need to expand the public contract. Unlike |
538f332
into
feature/26_2_osm-provider-for-dxmap/main
No description provided.