import { type CameraState } from '../camera/camera' import { calibratedLonLatToWorldTile } from '../../utils/projection' import { worldToScreen } from '../camera/camera' import { type MapLayer, type LayerRenderContext } from './mapLayer' import { type MapScene } from '../renderer/mapRenderer' export interface ScreenPoint { x: number y: number } function buildVectorCamera(scene: MapScene): CameraState { return { centerWorldX: scene.exactCenterWorldX, centerWorldY: scene.exactCenterWorldY, viewportWidth: scene.viewportWidth, viewportHeight: scene.viewportHeight, visibleColumns: scene.visibleColumns, rotationRad: scene.rotationRad, } } export class TrackLayer implements MapLayer { projectPoints(scene: MapScene): ScreenPoint[] { const camera = buildVectorCamera(scene) return scene.track.map((point) => { const worldPoint = calibratedLonLatToWorldTile(point, scene.zoom, scene.gpsCalibration, scene.gpsCalibrationOrigin) return worldToScreen(camera, worldPoint, false) }) } draw(context: LayerRenderContext): void { const { ctx, scene } = context const points = this.projectPoints(scene) if (!points.length) { return } ctx.save() ctx.lineCap = 'round' ctx.lineJoin = 'round' ctx.strokeStyle = 'rgba(23, 109, 93, 0.96)' ctx.lineWidth = 6 ctx.beginPath() points.forEach((screenPoint, index) => { if (index === 0) { ctx.moveTo(screenPoint.x, screenPoint.y) return } ctx.lineTo(screenPoint.x, screenPoint.y) }) ctx.stroke() ctx.fillStyle = '#f7fbf2' ctx.strokeStyle = '#176d5d' ctx.lineWidth = 4 points.forEach((screenPoint, index) => { ctx.beginPath() ctx.arc(screenPoint.x, screenPoint.y, 10, 0, Math.PI * 2) ctx.fill() ctx.stroke() ctx.fillStyle = '#176d5d' ctx.font = 'bold 14px sans-serif' ctx.textAlign = 'center' ctx.textBaseline = 'middle' ctx.fillText(String(index + 1), screenPoint.x, screenPoint.y) ctx.fillStyle = '#f7fbf2' }) ctx.restore() } }