gpsLayer.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { calibratedLonLatToWorldTile } from '../../utils/projection'
  2. import { worldToScreen, type CameraState } from '../camera/camera'
  3. import { type MapLayer, type LayerRenderContext } from './mapLayer'
  4. import { type MapScene } from '../renderer/mapRenderer'
  5. import { type ScreenPoint } from './trackLayer'
  6. function buildVectorCamera(scene: MapScene): CameraState {
  7. return {
  8. centerWorldX: scene.exactCenterWorldX,
  9. centerWorldY: scene.exactCenterWorldY,
  10. viewportWidth: scene.viewportWidth,
  11. viewportHeight: scene.viewportHeight,
  12. visibleColumns: scene.visibleColumns,
  13. rotationRad: scene.rotationRad,
  14. }
  15. }
  16. export class GpsLayer implements MapLayer {
  17. projectPoint(scene: MapScene): ScreenPoint {
  18. const camera = buildVectorCamera(scene)
  19. const worldPoint = calibratedLonLatToWorldTile(scene.gpsPoint, scene.zoom, scene.gpsCalibration, scene.gpsCalibrationOrigin)
  20. return worldToScreen(camera, worldPoint, false)
  21. }
  22. getPulseRadius(pulseFrame: number): number {
  23. return 18 + 6 * (0.5 + 0.5 * Math.sin(pulseFrame / 6))
  24. }
  25. draw(context: LayerRenderContext): void {
  26. const { ctx, scene, pulseFrame } = context
  27. const gpsScreenPoint = this.projectPoint(scene)
  28. const pulse = this.getPulseRadius(pulseFrame)
  29. ctx.save()
  30. ctx.beginPath()
  31. ctx.fillStyle = 'rgba(33, 158, 188, 0.22)'
  32. ctx.arc(gpsScreenPoint.x, gpsScreenPoint.y, pulse, 0, Math.PI * 2)
  33. ctx.fill()
  34. ctx.beginPath()
  35. ctx.fillStyle = '#21a1bc'
  36. ctx.arc(gpsScreenPoint.x, gpsScreenPoint.y, 9, 0, Math.PI * 2)
  37. ctx.fill()
  38. ctx.beginPath()
  39. ctx.strokeStyle = '#ffffff'
  40. ctx.lineWidth = 3
  41. ctx.arc(gpsScreenPoint.x, gpsScreenPoint.y, 13, 0, Math.PI * 2)
  42. ctx.stroke()
  43. ctx.fillStyle = '#0b3d4a'
  44. ctx.font = 'bold 16px sans-serif'
  45. ctx.textAlign = 'left'
  46. ctx.textBaseline = 'bottom'
  47. ctx.fillText('GPS', gpsScreenPoint.x + 14, gpsScreenPoint.y - 12)
  48. ctx.restore()
  49. }
  50. }