@@ -12,6 +12,26 @@ import Utils
1212// Fix a naming conflict with Utils's Binding
1313private typealias Binding = SwiftUI . Binding
1414
15+ private struct MapOptions : Hashable {
16+ var region : CoordinateRegion ?
17+ var size : Vec2 < Double > = . init( both: 256 )
18+ var opacity : Double = 1.0
19+ var markOutdated = false
20+ var resizeOffset : Vec2 < Double > = . zero( )
21+
22+ var sizeWithResize : Vec2 < Double > {
23+ size + resizeOffset * 2
24+ }
25+
26+ var staticMap : StaticMap {
27+ StaticMap (
28+ size: sizeWithResize. map { Int ( $0. rounded ( ) ) } ,
29+ center: region? . center,
30+ span: region? . span
31+ )
32+ }
33+ }
34+
1535private struct ResizeHandle : View {
1636 @Binding var offset : Vec2 < Double >
1737 var onSubmit : ( ) -> Void
@@ -33,17 +53,6 @@ private struct ResizeHandle: View {
3353 }
3454}
3555
36- private struct MapOptions : Hashable {
37- var size : Vec2 < Double > = . init( both: 256 )
38- var opacity : Double = 1.0
39- var markOutdated = false
40- var resizeOffset : Vec2 < Double > = . zero( )
41-
42- var sizeWithResize : Vec2 < Double > {
43- size + resizeOffset * 2
44- }
45- }
46-
4756private struct OverlayPanel : View {
4857 let errorMessage : String ?
4958 @Binding var mapOptions : MapOptions
@@ -72,11 +81,6 @@ private struct OverlayPanel: View {
7281
7382@available ( macOS 15 . 0 , * )
7483private struct ContentView : View {
75- @State private var region = MKCoordinateRegion (
76- center: . init( latitude: 51.5 , longitude: 0.0 ) ,
77- span: . init( latitudeDelta: 2 , longitudeDelta: 2 )
78- )
79-
8084 @State private var mapImage : NSImage ?
8185 @State private var mapOptions = MapOptions ( )
8286 @State private var errorMessage : String ?
@@ -89,38 +93,41 @@ private struct ContentView: View {
8993 . size ( width: mapOptions. sizeWithResize. x, height: mapOptions. sizeWithResize. y, anchor: . center)
9094
9195 ZStack ( alignment: . bottom) {
92- Map ( initialPosition: . region( region) )
93- . onMapCameraChange ( frequency: . continuous) { context in
94- let totalRegion = context. region
95- mapOptions. markOutdated = true
96- region = MKCoordinateRegion (
97- center: totalRegion. center,
98- span: MKCoordinateSpan (
99- latitudeDelta: totalRegion. span. latitudeDelta * CGFloat( mapOptions. size. y) / geometry. size. height,
100- longitudeDelta: totalRegion. span. longitudeDelta * CGFloat( mapOptions. size. x) / geometry. size. width
101- )
96+ Map ( initialPosition: . region( MKCoordinateRegion (
97+ center: . init( latitude: 51.5 , longitude: 0.0 ) ,
98+ span: . init( latitudeDelta: 2 , longitudeDelta: 2 )
99+ ) ) )
100+ . onMapCameraChange ( frequency: . continuous) { context in
101+ let totalRegion : MKCoordinateRegion = context. region
102+ mapOptions. markOutdated = true
103+ mapOptions. region = CoordinateRegion (
104+ center: Coordinates ( totalRegion. center) ,
105+ span: CoordinateSpan (
106+ latitudeDelta: . init( degrees: totalRegion. span. latitudeDelta * mapOptions. size. y / geometry. size. height) ,
107+ longitudeDelta: . init( degrees: totalRegion. span. longitudeDelta * mapOptions. size. x / geometry. size. width)
102108 )
103- scheduleStaticMapUpdate ( )
104- }
105- . overlay {
106- Group {
107- Rectangle ( )
108- . subtracting ( clipShape )
109- . fill ( . black . opacity ( 0.5 ) )
110- if let mapImage {
111- Image ( nsImage : mapImage)
112- . clipShape ( clipShape )
113- . opacity ( ( mapOptions . markOutdated ? 0.3 : 1 ) * mapOptions . opacity )
114- }
109+ )
110+ scheduleStaticMapUpdate ( )
111+ }
112+ . overlay {
113+ Group {
114+ Rectangle ( )
115+ . subtracting ( clipShape )
116+ . fill ( . black . opacity ( 0.5 ) )
117+ if let mapImage {
118+ Image ( nsImage : mapImage )
119+ . clipShape ( clipShape )
120+ . opacity ( ( mapOptions . markOutdated ? 0.3 : 1 ) * mapOptions . opacity )
115121 }
116- . allowsHitTesting ( false )
122+ }
123+ . allowsHitTesting ( false )
117124
118- let baseOffset = mapOptions. size / 2 + Vec2( both: 10 )
119- ResizeHandle ( offset: $mapOptions. resizeOffset) {
120- mapOptions. size += mapOptions. resizeOffset * 2
121- }
122- . offset ( x: baseOffset. x, y: baseOffset. y)
125+ let baseOffset = mapOptions. size / 2 + Vec2( both: 10 )
126+ ResizeHandle ( offset: $mapOptions. resizeOffset) {
127+ mapOptions. size += mapOptions. resizeOffset * 2
123128 }
129+ . offset ( x: baseOffset. x, y: baseOffset. y)
130+ }
124131 OverlayPanel ( errorMessage: errorMessage, mapOptions: $mapOptions)
125132 . padding ( )
126133 }
@@ -145,12 +152,7 @@ private struct ContentView: View {
145152 private func updateStaticMap( ) async {
146153 do {
147154 NSLog ( " Regenerating static map " )
148- let staticMap = StaticMap (
149- size: mapOptions. sizeWithResize. map { Int ( $0. rounded ( ) ) } ,
150- center: Coordinates ( region. center) ,
151- span: CoordinateSpan ( region. span)
152- )
153- let cairoImage = try await staticMap. render { logMessage in
155+ let cairoImage = try await mapOptions. staticMap. render { logMessage in
154156 NSLog ( " %@ " , logMessage)
155157 }
156158 let pngData = try cairoImage. pngEncoded ( )
0 commit comments