]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/assets/js/searchpage.js
detail page: add permalink, equivalent to https://github.com/openstreetmap/Nominatim...
[nominatim-ui.git] / src / assets / js / searchpage.js
1
2 /*********************************************************
3 * FORWARD/REVERSE SEARCH PAGE
4 *********************************************************/
5
6
7 function display_map_position(mouse_lat_lng){
8
9     html_mouse = "mouse position " + (mouse_lat_lng ? [mouse_lat_lng.lat.toFixed(5), mouse_lat_lng.lng.toFixed(5)].join(',') : '-');
10     html_click = "last click: " + (last_click_latlng ? [last_click_latlng.lat.toFixed(5),last_click_latlng.lng.toFixed(5)].join(',') : '-');
11
12     html_center = 
13         "map center: " + 
14         map.getCenter().lat.toFixed(5) + ',' + map.getCenter().lng.toFixed(5) +
15         " <a target='_blank' href='" + map_link_to_osm() + "'>view on osm.org</a>";
16
17     html_zoom = "map zoom: " + map.getZoom();
18
19     html_viewbox = "viewbox: " + map_viewbox_as_string();
20
21     $('#map-position-inner').html([html_center,html_zoom,html_viewbox,html_click,html_mouse].join('<br/>'));
22
23     var reverse_params = {
24         // lat: map.getCenter().lat.toFixed(5),
25         // lon: map.getCenter().lng.toFixed(5),
26         // zoom: 2,
27         // format: 'html'
28     }
29     $('#switch-to-reverse').attr('href', 'reverse.html?' + $.param(reverse_params));
30
31     $('input#use_viewbox').trigger('change');
32 }
33
34
35
36
37 function init_map_on_search_page(is_reverse_search, nominatim_results, request_lat, request_lon, init_zoom) {
38
39     map = new L.map('map', {
40         // center: [nominatim_map_init.lat, nominatim_map_init.lon],
41         // zoom:   nominatim_map_init.zoom,
42         attributionControl: (get_config_value('Map_Tile_Attribution') && get_config_value('Map_Tile_Attribution').length),
43         scrollWheelZoom:    true, // !L.Browser.touch,
44         touchZoom:          false,
45     });
46
47
48     L.tileLayer(get_config_value('Map_Tile_URL'), {
49         noWrap: true, // otherwise we end up with click coordinates like latitude -728
50         // moved to footer
51         attribution: (get_config_value('Map_Tile_Attribution') || null ) //'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
52     }).addTo(map);
53
54     // console.log(Nominatim_Config);
55
56     map.setView([request_lat, request_lon], init_zoom);
57
58     var osm2 = new L.TileLayer(get_config_value('Map_Tile_URL'), {minZoom: 0, maxZoom: 13, attribution: (get_config_value('Map_Tile_Attribution') || null )});
59     var miniMap = new L.Control.MiniMap(osm2, {toggleDisplay: true}).addTo(map);
60
61     if (is_reverse_search) {
62         // We don't need a marker, but an L.circle instance changes radius once you zoom in/out
63         var cm = L.circleMarker([request_lat, request_lon], { radius: 5, weight: 2, fillColor: '#ff7800', color: 'red', opacity: 0.75, clickable: false});
64         cm.addTo(map);
65     }
66
67     var MapPositionControl = L.Control.extend({
68         options: {
69             position: 'topright'
70         },
71         onAdd: function (map) {
72             var container = L.DomUtil.create('div', 'my-custom-control');
73
74             $(container).text('show map bounds').addClass('leaflet-bar btn btn-sm btn-default').on('click', function(e){
75                 e.preventDefault();
76                 e.stopPropagation();
77                 $('#map-position').show();
78                 $(container).hide();
79             });
80             $('#map-position-close a').on('click', function(e){
81                 e.preventDefault();
82                 e.stopPropagation();
83                 $('#map-position').hide();
84                 $(container).show();
85             });
86
87             return container;
88         }
89     });
90
91     map.addControl(new MapPositionControl());
92
93
94
95
96
97     function update_viewbox_field(){
98         // hidden HTML field
99         $('input[name=viewbox]').val( $('input#use_viewbox').prop('checked') ? map_viewbox_as_string() : '');
100     }
101
102     map.on('move', function(e) {
103         display_map_position();
104         update_viewbox_field();
105     });
106
107     map.on('mousemove', function(e) {
108         display_map_position(e.latlng);
109     });
110
111     map.on('click', function(e) {
112         last_click_latlng = e.latlng;
113         display_map_position();
114     });
115
116     map.on('load', function(e){
117         display_map_position();
118     });
119
120
121     $('input#use_viewbox').on('change', function(){
122         update_viewbox_field();
123     });
124
125
126
127
128     function get_result_element(position){
129         return $('.result').eq(position);
130     }
131     function marker_for_result(result){
132         return L.marker([result.lat,result.lon], {riseOnHover:true,title:result.name });
133     }
134     function circle_for_result(result){
135         return L.circleMarker([result.lat,result.lon], { radius: 10, weight: 2, fillColor: '#ff7800', color: 'blue', opacity: 0.75, clickable: !is_reverse_search});
136     }
137
138     var layerGroup = new L.layerGroup().addTo(map);
139     function highlight_result(position, bool_focus){
140         var result = nominatim_results[position];
141         if (!result){ return }
142         var result_el = get_result_element(position);
143
144         $('.result').removeClass('highlight');
145         result_el.addClass('highlight');
146
147         layerGroup.clearLayers();
148
149         if (result.lat){
150             var circle = circle_for_result(result);
151             circle.on('click', function(){
152                 highlight_result(position);
153             });
154             layerGroup.addLayer(circle);            
155         }
156         if (result.boundingbox){
157
158             var bounds = [[result.boundingbox[0]*1,result.boundingbox[2]*1], [result.boundingbox[1]*1,result.boundingbox[3]*1]];
159             map.fitBounds(bounds);
160
161             if (result.geojson && result.geojson.type.match(/(Polygon)|(Line)/) ){
162
163                 var geojson_layer = L.geoJson(
164                     parse_and_normalize_geojson_string(result.geojson),
165                     {
166                         // http://leafletjs.com/reference-1.0.3.html#path-option
167                         style: function(feature) {
168                             return { interactive: false, color: 'blue' }; 
169                         }
170                     }
171                 );
172                 layerGroup.addLayer(geojson_layer);
173             }
174             // else {
175             //     var layer = L.rectangle(bounds, {color: "#ff7800", weight: 1} );
176             //     layerGroup.addLayer(layer);
177             // }
178         }
179         else {
180             var result_coord = L.latLng(result.lat, result.lon);
181             if ( result_coord ){
182                 if ( is_reverse_search ){
183                     // console.dir([result_coord, [request_lat, request_lon]]);
184                     // make sure the search coordinates are in the map view as well
185                     map.fitBounds([result_coord, [request_lat, request_lon]], {padding: [50,50], maxZoom: map.getZoom()});
186
187                     // better, but causes a leaflet warning
188                     // map.panInsideBounds([[result.lat,result.lon], [nominatim_map_init.lat,nominatim_map_init.lon]], {animate: false});
189                 }
190                 else {
191                     map.panTo(result_coord, result.zoom || get_config_value('Map_Default_Zoom'));
192                 }
193             }
194         }
195         if (bool_focus){
196             $('#map').focus();
197         }
198     }
199
200
201     $('.result').on('click', function(e){
202         highlight_result($(this).data('position'), true);
203     });
204
205     if ( is_reverse_search ){
206         map.on('click', function(e){
207             $('form input[name=lat]').val( e.latlng.lat);
208             $('form input[name=lon]').val( e.latlng.lng);
209             $('form').submit();
210         });
211
212         $('#switch-coords').on('click', function(e){
213             e.preventDefault();
214             e.stopPropagation();
215             var lat = $('form input[name=lat]').val();
216             var lon = $('form input[name=lon]').val();
217             $('form input[name=lat]').val(lon);
218             $('form input[name=lon]').val(lat);
219             $('form').submit();
220         });
221     }
222
223     highlight_result(0, false);
224
225     // common mistake is to copy&paste latitude and longitude into the 'lat' search box
226     $('form input[name=lat]').on('change', function(){
227         var coords = $(this).val().split(',');
228         if (coords.length == 2) {
229             $(this).val(L.Util.trim(coords[0]));
230             $(this).siblings('input[name=lon]').val(L.Util.trim(coords[1]));
231         }
232     });
233 };
234
235
236
237
238
239
240
241 jQuery(document).ready(function(){
242
243     if ( !$('#search-page,#reverse-page').length ){ return; }
244     
245     var is_reverse_search = !!( $('#reverse-page').length );
246     var endpoint = is_reverse_search ? 'reverse' : 'search';
247
248
249     var search_params = new URLSearchParams(location.search);
250
251     // return view('search', [
252     //     'sQuery' => $sQuery,
253     //     'bAsText' => '',
254     //     'sViewBox' => '',
255     //     'aSearchResults' => $aSearchResults,
256     //     'sMoreURL' => 'example.com',
257     //     'sDataDate' => $this->fetch_status_date(),
258     //     'sApiURL' => $url
259     // ]);
260
261
262     if (is_reverse_search) {
263         var api_request_params = {
264             // lat: typeof(search_params.get('lat') !== 'undefined') ? search_params.get('lat') : get_config_value('Map_Default_Lat'),
265             // lon: typeof(search_params.get('lon') !== 'undefined') ? search_params.get('lon') : get_config_value('Map_Default_Lon'),
266             lat: search_params.get('lat'),
267             lon: search_params.get('lon'),
268             zoom: (search_params.get('zoom') !== '' ? search_params.get('zoom') : get_config_value('Map_Default_Zoom')),
269             format: 'jsonv2'
270         }
271
272         var context = {
273             // aPlace: aPlace,
274             fLat: api_request_params.lat,
275             fLon: api_request_params.lon,
276             iZoom: (search_params.get('zoom') !== '' ? api_request_params.zoom : undefined)
277         };
278
279
280         if (api_request_params.lat && api_request_params.lon) {
281
282             fetch_from_api('reverse', api_request_params, function(aPlace){
283
284                 if (aPlace.error) {
285                     aPlace = null;
286                 }
287
288                 context.aPlace = aPlace;
289
290                 render_template($('main'), 'reversepage-template', context);
291
292                 init_map_on_search_page(is_reverse_search, [aPlace], api_request_params.lat, api_request_params.lon, api_request_params.zoom);
293
294                 update_data_date();
295             });
296         } else {
297             render_template($('main'), 'reversepage-template', context);
298
299             init_map_on_search_page(is_reverse_search, [], get_config_value('Map_Default_Lat'), get_config_value('Map_Default_Lon'), get_config_value('Map_Default_Zoom'));
300         }
301
302     } else {
303         var api_request_params = {
304             q: search_params.get('q'),
305             polygon_geojson: search_params.get('polygon_geojson') ? 1 : 0,
306             viewbox: search_params.get('viewbox'),
307             format: 'jsonv2'
308         };
309
310         var context = {
311             // aSearchResults: aResults,
312             sQuery: api_request_params.q,
313             sViewBox: '',
314             env: Nominatim_Config,
315             sMoreURL: ''
316         };
317
318         if (api_request_params.q) {
319
320             fetch_from_api('search', api_request_params, function(aResults){
321
322                 context.aSearchResults = aResults;
323
324                 render_template($('main'), 'searchpage-template', context);
325
326                 init_map_on_search_page(is_reverse_search, aResults, get_config_value('Map_Default_Lat'), get_config_value('Map_Default_Lon'), get_config_value('Map_Default_Zoom'));
327
328                 $('#q').focus();
329
330                 update_data_date();
331             });
332         } else {
333             render_template($('main'), 'searchpage-template', context);
334
335             init_map_on_search_page(is_reverse_search, [], get_config_value('Map_Default_Lat'), get_config_value('Map_Default_Lon'), get_config_value('Map_Default_Zoom'));
336         }
337
338
339     }
340 });
341
342
343
344