Skip to content

feat(eng-view): overhaul engineer view with track map, weather graph, responsive layout#237

Merged
ashwin-nat merged 15 commits intoashwin-nat:hotfix-v3.3.0from
PettableCat:feat/engineer-view
Apr 25, 2026
Merged

feat(eng-view): overhaul engineer view with track map, weather graph, responsive layout#237
ashwin-nat merged 15 commits intoashwin-nat:hotfix-v3.3.0from
PettableCat:feat/engineer-view

Conversation

@PettableCat
Copy link
Copy Markdown

@PettableCat PettableCat commented Apr 12, 2026

📝 Description

Overhauls the engineer view with a live track map, weather forecast graph, and responsive layout.

Key changes:

  • New eng-view-trackmap.html page with real-time driver position rendering on SVG track maps
  • trackMap.js: SVG loading, driver dot positioning via affine-transformed coordinates
  • weatherGraph.js: canvas-based weather forecast timeline with temperature/rain curves
  • engView.js: responsive grid layout, auto-refresh, session-aware data fetching
  • Pre-generated SVG track maps for F1 2023, 2024, 2025 seasons (25+ circuits each)
  • Affine transform coefficients per circuit (svg_transforms.json) for coordinate mapping
  • Backend: new /track-map endpoint in telemetry_web_server.py

📂 Type of change

  • Bug fix 🐞
  • New feature 🚀
  • Refactor 🔨
  • Documentation 📚
  • Tests ✅
  • Other:

🧪 Backend Test Reports (required for Python/backend changes)

✅ Integration Tests

  • All integration tests pass
  • Attach test command/output:
$ poetry run python tests/integration_test/runner.py

Files processed:        31
Telemetry sent:         31
Telemetry failed:       0
Endpoint checks passed: 806
Endpoint checks failed: 0
Telemetry success rate: 100.0%
Endpoint success rate:  100.0%
Total execution time: 44:03.297

To run the integration test

poetry run python tests/integration_test/runner.py

🧱 lib/ Directory Changes

  • This PR modifies or adds files under lib/
  • I have updated or added unit tests to reflect those changes

Explain your test updates here:

N/A — changes are in apps/frontend/, apps/backend/, and assets/track-maps/ only.

📋 General Checklist

  • I have read the CONTRIBUTING guide
  • My code follows project style conventions
  • All new and existing tests pass
  • I have added relevant documentation/comments
  • I have reviewed my changes and believe they are ready to merge

Screenshots:
eng-view-v4
track-map-fullscreen

… responsive layout

Major redesign of the Engineer View for race engineers:

Engineer View UI:
- Responsive breakpoint system (compact/standard/expanded) with
  DrawerManager for context drawers on narrow viewports
- AG Grid integration with sortable/filterable columns, collapse-
  toggle per card section, and localStorage persistence
- Aggregated tyre wear cell renderers, multi-line driver info cells
- Weather table with session-grouped display and auto-refresh

Track Map (new):
- SVG + Canvas hybrid rendering: sharp SVG track outlines with Canvas
  driver-dot overlay — supports zoom/pan with mouse wheel and drag
- Affine world→SVG coordinate transforms via per-game-year
  svg_transforms.json files
- Tooltip on hover, pinned popup on click, team-color coded dots
- Fullscreen track map page at /eng-view/trackmap
- Track SVGs reorganized from flat assets/track-maps/ into versioned
  subdirectories (f1_2023, f1_2024, f1_2025) with transform data

Weather Graph (new):
- Chart.js-based weather forecast visualization
- Session-type grouping with deduplication by time-offset

Shared utilities (utils.js):
- escapeHtml() for XSS-safe innerHTML insertions
- getF1TeamColor() — official F1 team color lookup
- groupWeatherSamplesBySessionType() — deduplicate by time-offset
- getAdjacentPositions() — reference-row aware instead of player-only

Backend:
- /eng-view/trackmap route for fullscreen track map page

All 660 unit tests green.
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @PettableCat, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Re-scanned from a live qualifying session to fix incorrect rotation.
Regenerated svg_transforms.json to match the re-scanned Bahrain SVG.
Driver dot positions now align with the corrected track outline.
@PettableCat
Copy link
Copy Markdown
Author

Note: Some of the F1 2025 SVG track maps were committed with incorrect rotation/orientation. Currently re-scanning all tracks from live telemetry — Bahrain and Jeddah are already fixed, the rest will follow. Will commit the updated SVGs + affine transforms tomorrow probably.

@ashwin-nat
Copy link
Copy Markdown
Owner

please add screenshots to the PR description

@PettableCat
Copy link
Copy Markdown
Author

please add screenshots to the PR description

Done.

@PettableCat
Copy link
Copy Markdown
Author

All 27 F1 2025 track maps have been re-scanned from live telemetry and the affine transform coefficients recomputed. Pushed in 548b1de.

@ashwin-nat
Copy link
Copy Markdown
Owner

couple of questions.

  1. why do we need separate svg's for f1 24 and f1 25? the tracks and layouts have not changed
  2. why do we need separate svg's for regular and reverse layouts? The only differences I've seen are slightly different start/finish line positions and sector markers (neither of which are being rendered)

@PettableCat
Copy link
Copy Markdown
Author

Good questions! So I actually compared the raw telemetry coordinates between F1 24 and F1 25 for all shared tracks, and it turns out the world coordinates are genuinely different between game versions. Miami is the most extreme — about 43 meters average deviation, even after trying to align them optimally. Suzuka has a 137m offset, Imola is shifted and rotated ~1.75°, Melbourne and Bahrain are off by 5-6m as well.

Since the affine transforms for SVG rendering are computed from those world coordinates, even a few meters of shift breaks the mapping. And going forward, tracks like Singapore had a completely different layout before F1 23, so the per-year folders will be needed there too.

As for the reverse layouts — you're right that the geometry is mostly the same, but I'd rather keep them for completeness. The start/finish positions do differ, and if we ever render sector markers or start lines down the road, they'll already be there.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New security issues found

Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
Comment thread apps/frontend/js/trackMap.js Outdated
@ashwin-nat
Copy link
Copy Markdown
Owner

Code Review — feat(eng-view): overhaul engineer view with track map, weather graph, responsive layout

Overview

Major addition: live SVG+Canvas track map, Chart.js weather graph, full responsive layout with drawer system (mobile), and tyre temperature / damage colour coding for the engineer view. Also fixes spectator-mode relevance filtering and deduplicates weather samples by time-offset.


✅ What's Good

  • All CDN resources in eng-view.html now have integrity + crossorigin SRI attributes — solid improvement.
  • Track map tooltip content in trackMap.js properly calls escapeHtml() before using innerHTML.
  • WeatherGraph and TrackMap are clean ES6 classes with clear constructor/update/destroy lifecycle.
  • Affine-transform approach for coordinate mapping is elegant and well-documented.
  • groupWeatherSamplesBySessionType deduplication fix (last-write-wins via Map) is correct and well-commented.
  • Spectator-mode fix in getRelevantRaceTableRows properly separates race-ended from the ref-row check.
  • transform: translateX(100%) for slide-in panels is more GPU-friendly than animating right.
  • DrawerManager moves the track map DOM node into the drawer (rather than duplicating it) — avoids two live canvases.
  • Weather display toggle persisted to localStorage is a nice UX touch.

🔒 Security Issues

escape: false without sanitization (engView.js — tyre temp + damage cell renderers)
These class names come from internal lookup tables so they're safe today, but the escape: false path means any future caller passing user-derived input would silently get raw HTML. Add a comment at the call-site or restructure the API to use safe DOM methods.

container.innerHTML = '' used as a clear (DrawerManager, TrackMap.clear(), _setupTrackView())
The cleared content is trusted internal DOM so not a direct XSS risk, but textContent = '' or replaceChildren() is the safer and more consistent habit — WeatherGraph._createChart already uses textContent correctly.

btn.innerHTML = '<i class="bi bi-chevron-down"></i>' (engView.js:initCardCollapseToggles)
Static string, safe, but createElement + classList.add avoids the innerHTML pattern entirely.

api_key in <meta> tag (eng-view.html)
Storing an API key in a <meta> tag exposes it to any JS on the page (including injected content). If this key is sensitive, consider passing it only to the specific fetch call that needs it, not in page metadata.


🐛 Code Quality Issues

Duplicate CSS across two files
.track-map-tooltip, .track-map-pinned-popup, .pinned-popup-close, .track-map-zoom-reset, .track-map-wrapper, .track-map-svg, .track-map-canvas are defined inline in eng-view-trackmap.html and in engView.css, with slightly different values (e.g. font-size: 0.8rem vs 0.85rem, zoom reset 28×28 vs 36×36). These will diverge over time.

Repeated temp/damage CSS patterns
The 5 eng-temp-* and 3 eng-dmg-* classes all share display: inline-block, border: 2px solid currentColor, border-radius: 4px with !important. A shared .eng-temp-indicator base class would remove the repetition and the !important overuse.

German comments in CSS
/* Zeile 1: ... */, /* Zeile 2: ... */ in engView.css (responsive phone section). Should be English to match the rest of the codebase.

getF1TeamColor team name variants (utils.js)
'McLaren' + 'Mclaren' (lowercase-m) and 'Red Bull Racing' + 'Red Bull' suggest compensating for inconsistent backend strings. Better to normalize the team name at the data boundary rather than duplicating entries in the lookup table.

initCardCollapseToggles() injects buttons dynamically
Toggle buttons are created via document.createElement and appended to .card-header. This is fragile if header content changes. Better to put the buttons in the HTML and control visibility via CSS.


⚡ Performance Notes

WeatherGraph destroys and recreates Chart.js on every data change
Noted as intentional (matching WeatherOverlay pattern), but chart.data.datasets[n].data = ...; chart.update() would avoid canvas teardown cost on frequent telemetry updates.

_.isEqual on every weather socket message
Lodash deep-equal runs on every update — acceptable for weather data size but worth keeping in mind.


🏗️ Architecture Issues

refDriverTeam persists across sessions (eng-view-trackmap.html inline script)
let refDriverTeam = null is only reset on page load. If the player changes (e.g. spectator switches target mid-session), the team colour dot will be stale until refresh. Clear it when circuit changes.

max-height: 500px for collapse animation (#raceStatusBody)
Hardcoded max-height for CSS transitions is fragile if content grows beyond that value. Consider a JS-driven height animation or grid-template-rows: 0fr / 1fr approach.

overflow-x: auto on body
Replacing overflow: hidden with overflow-x: auto on the body can cause double scrollbars or layout bugs on some browsers — worth verifying on iOS Safari.

.eng-view-global-stats-container > .eng-view-global-stat:last-child { grid-column: 1 / -1 }
Spanning the last stat full-width may look odd if the last item happens to be a short label. Consider making this more targeted.


Priority Summary

Priority Issue
🔴 Deduplicate CSS between eng-view-trackmap.html inline styles and engView.css
🔴 refDriverTeam stale-state in standalone trackmap page
🟡 api_key in <meta> tag — evaluate exposure risk
🟡 !important overuse in temp/damage classes — consolidate with shared base class
🟡 German comments in CSS → translate to English
🟢 innerHTML = '' → prefer replaceChildren() / textContent = ''
🟢 initCardCollapseToggles buttons → move to HTML

Overall this is a well-executed feature with good security awareness. The main structural issue is the CSS duplication between the standalone trackmap page and the main stylesheet.

Copy link
Copy Markdown
Owner

@ashwin-nat ashwin-nat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Five German comments in the block — please translate to English to match the rest of the codebase.

Comment thread apps/frontend/css/engView.css
Comment thread apps/frontend/css/engView.css
Comment thread apps/frontend/css/engView.css
Comment thread apps/frontend/css/engView.css
Comment thread apps/frontend/css/engView.css
ashwin-nat and others added 3 commits April 25, 2026 05:37
- store bound document listeners and remove them in destroy()
- extract _buildTooltipContent() to eliminate duplicate tooltip DOM code
- extract _teardown() shared by clear() and _showFallback()
- cache sorted driver array, rebuild only when updateDrivers() runs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ashwin-nat ashwin-nat merged commit ed9144a into ashwin-nat:hotfix-v3.3.0 Apr 25, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants