1
1
import { Component , NgZone , OnInit } from '@angular/core' ;
2
+ import { FormControl , FormGroup } from '@angular/forms' ;
2
3
import { ActivatedRoute , Router } from '@angular/router' ;
3
- import { APIService } from '@services/api.service' ;
4
+ import { LatLng as grpcLatLng } from '@grpc/google/type/latlng.pb' ;
5
+ import { SetPicturePointRequest } from '@grpc/spec.pb' ;
6
+ import { PicturesClient } from '@grpc/spec.pbsc' ;
4
7
import { PageEnvService } from '@services/page-env.service' ;
5
8
import { APIPicture , PictureService } from '@services/picture' ;
6
9
import { LatLng , LeafletMouseEvent , Map , Marker , TileLayer , icon , latLng , marker , tileLayer } from 'leaflet' ;
7
10
import { EMPTY } from 'rxjs' ;
8
- import { catchError , debounceTime , distinctUntilChanged , map , shareReplay , switchMap } from 'rxjs/operators' ;
11
+ import { catchError , debounceTime , distinctUntilChanged , map , shareReplay , startWith , switchMap } from 'rxjs/operators' ;
12
+
13
+ import { ToastsService } from '../../../../toasts/toasts.service' ;
9
14
10
15
interface MapOptions {
11
16
center : LatLng ;
12
17
leafletOptions : { center : LatLng ; layers : TileLayer [ ] ; zoom : number } ;
13
18
markers : Marker [ ] ;
14
19
}
15
20
21
+ function normalizeLat ( lat : number ) {
22
+ return Math . max ( lat , Math . min ( lat , 90 ) , - 90 ) ;
23
+ }
24
+
25
+ function normalizeLng ( lng : number ) {
26
+ lng = ( ( lng - 180 ) % 360 ) + 180 ;
27
+ return ( ( lng + 180 ) % 360 ) - 180 ;
28
+ }
29
+
16
30
function createMarker ( lat : number , lng : number ) : Marker {
17
31
return marker ( [ lat , lng ] , {
18
32
icon : icon ( {
@@ -24,13 +38,20 @@ function createMarker(lat: number, lng: number): Marker {
24
38
} ) ;
25
39
}
26
40
41
+ interface PointForm {
42
+ lat : FormControl < null | string > ;
43
+ lng : FormControl < null | string > ;
44
+ }
45
+
27
46
@Component ( {
28
47
selector : 'app-moder-pictures-place' ,
29
48
templateUrl : './place.component.html' ,
30
49
} )
31
50
export class ModerPicturesItemPlaceComponent implements OnInit {
32
- protected lat : number = NaN ;
33
- protected lng : number = NaN ;
51
+ private readonly form = new FormGroup < PointForm > ( {
52
+ lat : new FormControl < string > ( '' ) ,
53
+ lng : new FormControl < string > ( '' ) ,
54
+ } ) ;
34
55
35
56
protected readonly picture$ = this . route . paramMap . pipe (
36
57
map ( ( params ) => parseInt ( params . get ( 'id' ) || '' , 10 ) ) ,
@@ -46,9 +67,26 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
46
67
shareReplay ( 1 ) ,
47
68
) ;
48
69
49
- protected readonly map $ = this . picture$ . pipe (
70
+ protected readonly form $ = this . picture$ . pipe (
50
71
map ( ( picture ) => {
51
- const center = latLng ( 55.7423627 , 37.6786422 ) ;
72
+ let lat = null ,
73
+ lng = null ;
74
+ if ( picture && picture . point && picture . point . lat && picture . point . lng ) {
75
+ lat = picture . point . lat + '' ;
76
+ lng = picture . point . lng + '' ;
77
+ }
78
+
79
+ this . form . setValue ( { lat, lng} ) ;
80
+
81
+ return this . form ;
82
+ } ) ,
83
+ shareReplay ( 1 ) ,
84
+ ) ;
85
+
86
+ protected readonly map$ = this . form$ . pipe (
87
+ switchMap ( ( form ) => form . valueChanges . pipe ( startWith ( form . value ) ) ) ,
88
+ map ( ( formValues ) => {
89
+ let center = latLng ( 55.7423627 , 37.6786422 ) ;
52
90
53
91
const leafletOptions = {
54
92
center : center ,
@@ -60,15 +98,21 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
60
98
zoom : 8 ,
61
99
} ;
62
100
101
+ let lat = formValues . lat ? parseFloat ( formValues . lat ) : NaN ;
102
+ let lng = formValues . lng ? parseFloat ( formValues . lng ) : NaN ;
103
+
63
104
const markers : Marker [ ] = [ ] ;
64
105
65
- if ( picture && picture . point ) {
66
- this . lat = picture . point . lat ;
67
- this . lng = picture . point . lng ;
68
- if ( picture . point . lat && picture . point . lng ) {
69
- markers . push ( createMarker ( picture . point . lat , picture . point . lng ) ) ;
70
- leafletOptions . center = latLng ( picture . point . lat , picture . point . lng ) ;
71
- }
106
+ let ll = null ;
107
+ if ( ! isNaN ( lat ) && ! isNaN ( lng ) ) {
108
+ lat = normalizeLat ( lat ) ;
109
+ lng = normalizeLng ( lng ) ;
110
+ ll = latLng ( [ lat , lng ] ) ;
111
+ }
112
+ if ( ll ) {
113
+ markers . push ( createMarker ( ll . lat , ll . lng ) ) ;
114
+ center = ll ;
115
+ leafletOptions . center = ll ;
72
116
}
73
117
74
118
return { center, leafletOptions, markers} ;
@@ -81,7 +125,8 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
81
125
private readonly pictureService : PictureService ,
82
126
private readonly pageEnv : PageEnvService ,
83
127
private readonly zone : NgZone ,
84
- private readonly api : APIService ,
128
+ private readonly picturesClient : PicturesClient ,
129
+ private readonly toastService : ToastsService ,
85
130
) { }
86
131
87
132
ngOnInit ( ) : void {
@@ -95,45 +140,38 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
95
140
) ;
96
141
}
97
142
98
- protected coordsChanged ( mapOptions : MapOptions ) {
99
- const lat = this . lat ;
100
- const lng = this . lng ;
101
-
102
- const ll = isNaN ( lat ) || isNaN ( lng ) ? null : latLng ( [ lat , lng ] ) ;
103
- if ( ll ) {
104
- if ( mapOptions . markers . length ) {
105
- mapOptions . markers [ 0 ] . setLatLng ( ll ) ;
106
- } else {
107
- mapOptions . markers = [ createMarker ( ll . lat , ll . lng ) ] ;
108
- }
109
- mapOptions . center = ll ;
110
- mapOptions . leafletOptions . center = ll ;
111
- } else {
112
- mapOptions . markers = [ ] ;
113
- }
114
- }
115
-
116
- protected onMapReady ( mapOptions : MapOptions , lmap : Map ) {
143
+ protected onMapReady ( mapOptions : MapOptions , lmap : Map , form : FormGroup < PointForm > ) {
117
144
lmap . on ( 'click' , ( event : LeafletMouseEvent ) => {
118
145
this . zone . run ( ( ) => {
119
146
const ll : LatLng = event . latlng ;
120
- mapOptions . markers = [ createMarker ( ll . lat , ll . lng ) ] ;
121
- this . lat = ll . lat ;
122
- this . lng = ll . lng ;
147
+ const lat = normalizeLat ( ll . lat ) ;
148
+ const lng = normalizeLng ( ll . lng ) ;
149
+ mapOptions . markers = [ createMarker ( lat , lng ) ] ;
150
+ form . setValue ( {
151
+ lat : lat + '' ,
152
+ lng : lng + '' ,
153
+ } ) ;
123
154
} ) ;
124
155
} ) ;
125
156
}
126
157
127
- protected doSubmit ( picture : APIPicture ) {
128
- this . api
129
- . request < void > ( 'PUT' , 'picture/' + picture . id , {
130
- body : {
131
- point : {
132
- lat : this . lat ,
133
- lng : this . lng ,
134
- } ,
135
- } ,
136
- } )
158
+ protected doSubmit ( form : FormGroup < PointForm > , picture : APIPicture ) {
159
+ this . picturesClient
160
+ . setPicturePoint (
161
+ new SetPicturePointRequest ( {
162
+ pictureId : '' + picture . id ,
163
+ point : new grpcLatLng ( {
164
+ latitude : form . controls . lat . value ? parseFloat ( form . controls . lat . value ) : 0 ,
165
+ longitude : form . controls . lng . value ? parseFloat ( form . controls . lng . value ) : 0 ,
166
+ } ) ,
167
+ } ) ,
168
+ )
169
+ . pipe (
170
+ catchError ( ( response : unknown ) => {
171
+ this . toastService . handleError ( response ) ;
172
+ return EMPTY ;
173
+ } ) ,
174
+ )
137
175
. subscribe ( ( ) => {
138
176
this . router . navigate ( [ '/moder/pictures' , picture . id ] ) ;
139
177
} ) ;
0 commit comments