map update on any focus change #111

Closed
opened 2026-05-11 00:09:26 +00:00 by maxtkc · 0 comments
Owner

Summary

Currently the map only updates for route and stop page navigations. Three page types — home, service, and timetable — do not trigger any map update, and the agency page wires to a no-op. This means navigating via breadcrumbs or clicking services/timetables leaves the map frozen at whatever was last focused. The fix is to add a focusFeed() method to MapController (clear highlights + fit all stops), wire it for home and service pages, call highlightRoute(route_id) for timetable pages, and fix the agency implementation which already has a highlightAgencyRoutes() method that was never connected.

Key tradeoff: highlightAgencyRoutes() in MapController (line 724) has a loop bug — it calls this.highlightRoute() per agency route, and each call invokes clearHighlights() first, so only the last route ends up highlighted. This needs to be fixed as part of wiring agency support.

Relevant Context

What Where
Page switch dispatch src/modules/page-content-renderer.ts:219renderPage() switch
Home render (no map call) src/modules/page-content-renderer.ts:278renderHome()
Agency render (broken no-op) src/modules/page-content-renderer.ts:481renderAgency() calls focusOnAgency()
Route render (works) src/modules/page-content-renderer.ts:492renderRoute() calls highlightRoute()
Timetable render (no map call) src/modules/page-content-renderer.ts:636renderTimetable()
Service render (no map call) src/modules/page-content-renderer.ts:668renderService()
mapController interface src/modules/page-content-renderer.ts:103–115
MapController public methods src/modules/map-controller.ts:474–611
fitMapToData() (private) src/modules/map-controller.ts:430
highlightAgencyRoutes() (buggy loop) src/modules/map-controller.ts:724
Agency no-op adapter src/modules/browse-navigation.ts:535highlightAgencyOnMap()
mapController adapter (browse) src/modules/browse-navigation.ts:317–326

Phase 1: Add focusFeed() to MapController and wire home/service pages

Goal: when the user lands on the home or service page (by navigation or breadcrumb), the map should clear any current highlight and fit bounds to show all GTFS data — the "feed view".

  • In src/modules/map-controller.ts, make fitMapToData() public (rename or add a thin public wrapper focusFeed()):
    public focusFeed(): void {
      this.clearHighlights();
      this.fitMapToData();
    }
    
  • Add focusFeed: () => void to the mapController interface in src/modules/page-content-renderer.ts (near line 110).
  • In renderHome() (page-content-renderer.ts:278), add as the first line:
    this.dependencies.mapController.focusFeed();
    
  • In renderService() (page-content-renderer.ts:668), add before the return:
    this.dependencies.mapController.focusFeed();
    
  • Add focusFeed: () => void to the mapController adapter in src/modules/browse-navigation.ts (near line 317):
    focusFeed: () => this.mapController.focusFeed(),
    

Notes: Also had to add focusFeed to the private mapController field type (line 61) and the constructor parameter type (line 199) in browse-navigation.ts — both inline structural types needed updating to match the new public method.

Gotcha: fitMapToData() is a no-op if no stops are loaded (guard is already in place). This is fine — if the feed is empty, no map movement is expected.


Phase 2: Wire timetable pages to highlight the route

Goal: navigating to a timetable page (route + service combination) should highlight and fly to the route, same as the route page.

  • In renderTimetable() (page-content-renderer.ts:636), add before the return:
    this.dependencies.mapController.highlightRoute(route_id);
    
    (highlightRoute is already in the interface — no interface change needed.)

Gotcha: highlightRoute is already defined in the mapController dependency interface. No new wiring needed in browse-navigation.


Phase 3: Fix agency map focus

Goal: navigating to an agency page should highlight all routes for that agency and fit the map to them.

Step A — fix the highlightAgencyRoutes loop bug in src/modules/map-controller.ts:724:

The current loop calls this.highlightRoute() per route, and each invocation calls clearHighlights() first, so only the last route is ever highlighted. Replace with a direct call to routeRenderer?.highlightRoutes() (plural):

  • Rewrite highlightAgencyRoutes() to:
    1. Call this.clearHighlights() once.
    2. Collect all route_ids for the agency.
    3. Call this.routeRenderer?.highlightRoutes(agencyRouteIds) (plural — already used in highlightStop).
    4. Call this.fitToRoutes(agencyRouteIds).

Step B — connect the no-op in src/modules/browse-navigation.ts:535:

  • Change highlightAgencyOnMap() from a no-op to:
    highlightAgencyOnMap(agency_id: string) {
      this.mapController?.highlightAgencyRoutes(agency_id);
    }
    

Gotcha: highlightAgencyRoutes guards on agencyRoutes.length === 0 and returns early — safe to call with any agency_id. fitToRoutes also guards on coordinates.length > 0.


Original Issue

  • Even when the change is in the breadcrumbs
  • Even when a service is selected (services are under the feed, so we should unfocus/focus on feed)
  • Maybe more? Does this make sense?
## Summary Currently the map only updates for route and stop page navigations. Three page types — home, service, and timetable — do not trigger any map update, and the agency page wires to a no-op. This means navigating via breadcrumbs or clicking services/timetables leaves the map frozen at whatever was last focused. The fix is to add a `focusFeed()` method to `MapController` (clear highlights + fit all stops), wire it for home and service pages, call `highlightRoute(route_id)` for timetable pages, and fix the agency implementation which already has a `highlightAgencyRoutes()` method that was never connected. **Key tradeoff**: `highlightAgencyRoutes()` in `MapController` (line 724) has a loop bug — it calls `this.highlightRoute()` per agency route, and each call invokes `clearHighlights()` first, so only the last route ends up highlighted. This needs to be fixed as part of wiring agency support. ## Relevant Context | What | Where | |------|-------| | Page switch dispatch | `src/modules/page-content-renderer.ts:219` — `renderPage()` switch | | Home render (no map call) | `src/modules/page-content-renderer.ts:278` — `renderHome()` | | Agency render (broken no-op) | `src/modules/page-content-renderer.ts:481` — `renderAgency()` calls `focusOnAgency()` | | Route render (works) | `src/modules/page-content-renderer.ts:492` — `renderRoute()` calls `highlightRoute()` | | Timetable render (no map call) | `src/modules/page-content-renderer.ts:636` — `renderTimetable()` | | Service render (no map call) | `src/modules/page-content-renderer.ts:668` — `renderService()` | | mapController interface | `src/modules/page-content-renderer.ts:103–115` | | MapController public methods | `src/modules/map-controller.ts:474–611` | | `fitMapToData()` (private) | `src/modules/map-controller.ts:430` | | `highlightAgencyRoutes()` (buggy loop) | `src/modules/map-controller.ts:724` | | Agency no-op adapter | `src/modules/browse-navigation.ts:535` — `highlightAgencyOnMap()` | | mapController adapter (browse) | `src/modules/browse-navigation.ts:317–326` | --- ## Phase 1: Add `focusFeed()` to MapController and wire home/service pages Goal: when the user lands on the home or service page (by navigation or breadcrumb), the map should clear any current highlight and fit bounds to show all GTFS data — the "feed view". - [x] In `src/modules/map-controller.ts`, make `fitMapToData()` public (rename or add a thin public wrapper `focusFeed()`): ```typescript public focusFeed(): void { this.clearHighlights(); this.fitMapToData(); } ``` - [x] Add `focusFeed: () => void` to the `mapController` interface in `src/modules/page-content-renderer.ts` (near line 110). - [x] In `renderHome()` (`page-content-renderer.ts:278`), add as the first line: ```typescript this.dependencies.mapController.focusFeed(); ``` - [x] In `renderService()` (`page-content-renderer.ts:668`), add before the return: ```typescript this.dependencies.mapController.focusFeed(); ``` - [x] Add `focusFeed: () => void` to the mapController adapter in `src/modules/browse-navigation.ts` (near line 317): ```typescript focusFeed: () => this.mapController.focusFeed(), ``` **Notes**: Also had to add `focusFeed` to the private `mapController` field type (line 61) and the constructor parameter type (line 199) in `browse-navigation.ts` — both inline structural types needed updating to match the new public method. **Gotcha**: `fitMapToData()` is a no-op if no stops are loaded (guard is already in place). This is fine — if the feed is empty, no map movement is expected. --- ## Phase 2: Wire timetable pages to highlight the route Goal: navigating to a timetable page (route + service combination) should highlight and fly to the route, same as the route page. - [x] In `renderTimetable()` (`page-content-renderer.ts:636`), add before the return: ```typescript this.dependencies.mapController.highlightRoute(route_id); ``` (`highlightRoute` is already in the interface — no interface change needed.) **Gotcha**: `highlightRoute` is already defined in the mapController dependency interface. No new wiring needed in browse-navigation. --- ## Phase 3: Fix agency map focus Goal: navigating to an agency page should highlight all routes for that agency and fit the map to them. **Step A — fix the `highlightAgencyRoutes` loop bug** in `src/modules/map-controller.ts:724`: The current loop calls `this.highlightRoute()` per route, and each invocation calls `clearHighlights()` first, so only the last route is ever highlighted. Replace with a direct call to `routeRenderer?.highlightRoutes()` (plural): - [x] Rewrite `highlightAgencyRoutes()` to: 1. Call `this.clearHighlights()` once. 2. Collect all `route_id`s for the agency. 3. Call `this.routeRenderer?.highlightRoutes(agencyRouteIds)` (plural — already used in `highlightStop`). 4. Call `this.fitToRoutes(agencyRouteIds)`. **Step B — connect the no-op** in `src/modules/browse-navigation.ts:535`: - [x] Change `highlightAgencyOnMap()` from a no-op to: ```typescript highlightAgencyOnMap(agency_id: string) { this.mapController?.highlightAgencyRoutes(agency_id); } ``` **Gotcha**: `highlightAgencyRoutes` guards on `agencyRoutes.length === 0` and returns early — safe to call with any agency_id. `fitToRoutes` also guards on `coordinates.length > 0`. --- ## Original Issue - Even when the change is in the breadcrumbs - Even when a service is selected (services are under the feed, so we should unfocus/focus on feed) - Maybe more? Does this make sense?
maxtkc self-assigned this 2026-05-11 00:09:26 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gtfs.zone/coloring-book#111
No description provided.