+
+ Laps
+ {{ racingLineAnalysis.total_laps }}
+
+
+ Best Lap
+
+ {{ racingLineAnalysis.laps.length > 0
+ ? formatLapTimeShort(Math.min(...racingLineAnalysis.laps.filter(l => l.lap_time_ms > 0).map(l => l.lap_time_ms)))
+ : '--' }}
+
+
+
+ Max Speed
+ {{ Math.round(Math.max(...racingLineAnalysis.laps.map(l => l.max_speed_kmh), 0)) }}
+ km/h
+
+
+ Frames
+ {{ racingLineAnalysis.total_frames_analyzed.toLocaleString() }}
+
+
+
- Both boundary runs (left + right) are recorded. Build the persistent track model to enable corner analysis and sector timing.
+ Both boundary runs (left + right) are recorded. Name the track and build the persistent track model to enable corner analysis and sector timing.
-
- {{ buildingTrack ? 'Building...' : 'Build Track Model' }}
-
+
+
+ {{ opt.label }}
+
+
+
+ {{ buildingTrack ? 'Building...' : 'Build Track Model' }}
+
+
Track model built successfully. View in Tracks →
diff --git a/src/views/TrackDetailView.vue b/src/views/TrackDetailView.vue
index 24042a9..6c985e5 100644
--- a/src/views/TrackDetailView.vue
+++ b/src/views/TrackDetailView.vue
@@ -17,6 +17,7 @@
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTracksStore } from '@/stores/tracks'
+import { useCanvasZoom } from '@/composables/useCanvasZoom'
import type { Corner } from '@/types'
let resizeRafId: number | null = null
@@ -33,6 +34,8 @@ const showCurvature = ref(true)
const showCorners = ref(true)
const showSectors = ref(true)
+const { zoom, onWheel, onMouseDown, onMouseMove, onMouseUp, reset: resetZoom, applyTransform } = useCanvasZoom(canvas, drawTrack)
+
onMounted(async () => {
await store.fetchTrack(game.value, trackName.value)
})
@@ -58,6 +61,9 @@ function drawTrack() {
ctx.fillStyle = '#0f1117'
ctx.fillRect(0, 0, width, height)
+ ctx.save()
+ applyTransform(ctx)
+
ctx.strokeStyle = '#1a1d27'
ctx.lineWidth = 1
for (let i = 0; i <= 10; i++) {
@@ -212,6 +218,8 @@ function drawTrack() {
ctx.arc(startX, startY, 6, 0, Math.PI * 2)
ctx.stroke()
}
+
+ ctx.restore()
}
function handleResize() {
@@ -328,6 +336,9 @@ watch([showCurvature, showCorners, showSectors], () => {
Sectors
+
+ Reset View ({{ zoom.toFixed(1) }}x)
+
Delete
@@ -350,7 +361,15 @@ watch([showCurvature, showCorners, showSectors], () => {