gpsLayer.ts 1.7 KB

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