]> git.openstreetmap.org Git - nominatim.git/blob - website/js/nominatim-ui.js
d631e7aa4861db4a63f54fa5715287f52e4e4686
[nominatim.git] / website / js / nominatim-ui.js
1 var map;
2 var last_click_latlng;
3
4 function parse_and_normalize_geojson_string(raw_string){
5     // normalize places the geometry into a featurecollection, similar to
6     // https://github.com/mapbox/geojson-normalize
7     var parsed_geojson = {
8         type: "FeatureCollection",
9         features: [
10             {
11                 type: "Feature",
12                 geometry: JSON.parse(raw_string),
13                 properties: {}
14             }
15         ]
16     };
17     return parsed_geojson;
18 }
19
20 jQuery(document).ready(function(){
21
22     if ( !$('#search-page,#reverse-page').length ){ return; }
23     
24     var is_reverse_search = !!( $('#reverse-page').length );
25
26     $('#q').focus();
27
28     map = new L.map('map', {
29                 attributionControl: (nominatim_map_init.tile_attribution && nominatim_map_init.tile_attribution.length),
30                 scrollWheelZoom:    true, // !L.Browser.touch,
31                 touchZoom:          false
32             });
33
34     L.tileLayer(nominatim_map_init.tile_url, {
35         // moved to footer
36         attribution: (nominatim_map_init.tile_attribution || null ) //'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
37     }).addTo(map);
38
39     map.setView([nominatim_map_init.lat, nominatim_map_init.lon], nominatim_map_init.zoom);
40
41     var osm2 = new L.TileLayer(nominatim_map_init.tile_url, {minZoom: 0, maxZoom: 13, attribution: (nominatim_map_init.tile_attribution || null )});
42     var miniMap = new L.Control.MiniMap(osm2, {toggleDisplay: true}).addTo(map);
43
44     if ( is_reverse_search ){
45         // We don't need a marker, but an L.circle instance changes radius once you zoom in/out
46         var cm = L.circleMarker([nominatim_map_init.lat,nominatim_map_init.lon], { radius: 5, weight: 2, fillColor: '#ff7800', color: 'red', opacity: 0.75, clickable: false});
47         cm.addTo(map);
48     }
49
50     var MapPositionControl = L.Control.extend({
51             options: {
52                     position: 'topright'
53             },
54
55             onAdd: function (map) {
56                     var container = L.DomUtil.create('div', 'my-custom-control');
57
58                     $(container).text('show map bounds').addClass('leaflet-bar btn btn-sm btn-default').on('click', function(e){
59                         e.preventDefault();
60                         e.stopPropagation();
61                         $('#map-position').show();
62                         $(container).hide();
63                     });
64                     $('#map-position-close a').on('click', function(e){
65                         e.preventDefault();
66                         e.stopPropagation();
67                         $('#map-position').hide();
68                         $(container).show();
69                     });
70
71                     return container;
72             }
73     });
74
75     map.addControl(new MapPositionControl());
76
77
78     function display_map_position(mouse_lat_lng){
79
80         if (mouse_lat_lng) {
81             mouse_lat_lng = map.wrapLatLng(mouse_lat_lng);
82         }
83         html_mouse = "mouse position " + (mouse_lat_lng ? [mouse_lat_lng.lat.toFixed(5), mouse_lat_lng.lng.toFixed(5)].join(',') : '-');
84         html_click = "last click: " + (last_click_latlng ? [last_click_latlng.lat.toFixed(5),last_click_latlng.lng.toFixed(5)].join(',') : '-');
85
86         html_center = 
87             "map center: " + 
88             map.getCenter().lat.toFixed(5) + ',' + map.getCenter().lng.toFixed(5) +
89             " <a target='_blank' href='" + map_link_to_osm() + "'>view on osm.org</a>";
90
91         html_zoom = "map zoom: " + map.getZoom();
92
93         html_viewbox = "viewbox: " + map_viewbox_as_string();
94
95         $('#map-position-inner').html([html_center,html_zoom,html_viewbox,html_click,html_mouse].join('<br/>'));
96
97         var center_lat_lng = map.wrapLatLng(map.getCenter());
98         var reverse_params = {
99             lat: center_lat_lng.lat.toFixed(5),
100             lon: center_lat_lng.lng.toFixed(5),
101             zoom: map.getZoom(),
102             format: 'html'
103         }
104         $('#switch-to-reverse').attr('href', 'reverse.php?' + $.param(reverse_params));
105
106         $('input#use_viewbox').trigger('change');
107     }
108
109     function update_viewbox_field(){
110         // hidden HTML field
111         $('input[name=viewbox]').val( $('input#use_viewbox').prop('checked') ? map_viewbox_as_string() : '');
112     }
113
114     map.on('move', function(e) {
115         display_map_position();
116         update_viewbox_field();
117     });
118
119     map.on('mousemove', function(e) {
120         display_map_position(e.latlng);
121     });
122
123     map.on('click', function(e) {
124         last_click_latlng = e.latlng;
125         display_map_position();
126     });
127
128     map.on('load', function(e){
129         display_map_position();
130     });
131
132
133     $('input#use_viewbox').on('change', function(){
134         update_viewbox_field();
135     });
136
137
138
139     function map_viewbox_as_string() {
140         var bounds = map.getBounds();
141         var west = bounds.getWest();
142         var east = bounds.getEast();
143
144         if ((east - west) >= 360) { // covers more than whole planet
145             west = map.getCenter().lng-179.999;
146             east = map.getCenter().lng+179.999;
147         }
148         east = L.latLng(77, east).wrap().lng;
149         west = L.latLng(77, west).wrap().lng;
150
151         return [
152             west.toFixed(5), // left
153             bounds.getNorth().toFixed(5), // top
154             east.toFixed(5), // right
155             bounds.getSouth().toFixed(5) // bottom
156         ].join(',');
157     }
158     function map_link_to_osm(){
159         return "https://openstreetmap.org/#map=" + map.getZoom() + "/" + map.getCenter().lat + "/" + map.getCenter().lng;
160     }
161
162     function get_result_element(position){
163         return $('.result').eq(position);
164     }
165     function marker_for_result(result){
166         return L.marker([result.lat,result.lon], {riseOnHover:true,title:result.name });
167     }
168     function circle_for_result(result){
169         return L.circleMarker([result.lat,result.lon], { radius: 10, weight: 2, fillColor: '#ff7800', color: 'blue', opacity: 0.75, clickable: !is_reverse_search});
170     }
171
172     var layerGroup = new L.layerGroup().addTo(map);
173     function highlight_result(position, bool_focus){
174         var result = nominatim_results[position];
175         if (!result){ return }
176         var result_el = get_result_element(position);
177
178         $('.result').removeClass('highlight');
179         result_el.addClass('highlight');
180
181         layerGroup.clearLayers();
182
183         if (result.lat){
184             var circle = circle_for_result(result);
185             circle.on('click', function(){
186                 highlight_result(position);
187             });
188             layerGroup.addLayer(circle);            
189         }
190         if (result.aBoundingBox){
191
192             var bounds = [[result.aBoundingBox[0]*1,result.aBoundingBox[2]*1], [result.aBoundingBox[1]*1,result.aBoundingBox[3]*1]];
193             map.fitBounds(bounds);
194
195             if (result.asgeojson && result.asgeojson.match(/(Polygon)|(Line)/) ){
196
197                 var geojson_layer = L.geoJson(
198                     parse_and_normalize_geojson_string(result.asgeojson),
199                     {
200                         // http://leafletjs.com/reference-1.0.3.html#path-option
201                         style: function(feature) {
202                             return { interactive: false, color: 'blue' }; 
203                         }
204                     }
205                 );
206                 layerGroup.addLayer(geojson_layer);
207             }
208             else {
209                 // var layer = L.rectangle(bounds, {color: "#ff7800", weight: 1} );
210                 // layerGroup.addLayer(layer);
211             }
212         }
213         else {
214             var result_coord = L.latLng(result.lat, result.lon);
215             if ( result_coord ){
216                 if ( is_reverse_search ){
217                     // make sure the search coordinates are in the map view as well
218                     map.fitBounds([result_coord, [nominatim_map_init.lat,nominatim_map_init.lon]], {padding: [50,50], maxZoom: map.getZoom()});
219
220                     // better, but causes a leaflet warning
221                     // map.panInsideBounds([[result.lat,result.lon], [nominatim_map_init.lat,nominatim_map_init.lon]], {animate: false});
222                 }
223                 else {
224                     map.panTo(result_coord, result.zoom || nominatim_map_init.zoom);
225                 }
226             }
227         }
228
229         // var crosshairIcon = L.icon({
230         //  iconUrl:     'images/crosshair.png',
231         //  iconSize:    [12, 12],
232         //  iconAnchor:  [6, 6],
233         // });
234         // var crossMarker = new L.Marker([result.lat,result.lon], { icon: crosshairIcon, clickable: false});
235         // layerGroup.addLayer(crossMarker);
236
237
238
239         if (bool_focus){
240             $('#map').focus();
241         }
242     }
243
244
245     $('.result').on('click', function(e){
246         highlight_result($(this).data('position'), true);
247     });
248
249     if ( is_reverse_search ){
250         map.on('click', function(e){
251             $('form input[name=lat]').val( e.latlng.lat);
252             $('form input[name=lon]').val( e.latlng.wrap().lng);
253             $('form').submit();
254         });
255
256         $('#switch-coords').on('click', function(e){
257             e.preventDefault();
258             e.stopPropagation();
259             var lat = $('form input[name=lat]').val();
260             var lon = $('form input[name=lon]').val();
261             $('form input[name=lat]').val(lon);
262             $('form input[name=lon]').val(lat);
263             $('form').submit();
264         });
265     } else {
266         var search_params = new URLSearchParams(location.search);
267         var viewbox = search_params.get('viewbox');
268         if (viewbox) {
269             var coords = viewbox.split(','); // <x1>,<y1>,<x2>,<y2>
270             var bounds = L.latLngBounds([coords[1], coords[0]], [coords[3], coords[2]]);
271             L.rectangle(bounds, {color: "#69d53e", weight: 3, dashArray: '5 5', opacity: 0.8, fill: false}).addTo(map);
272         }
273     }
274
275     highlight_result(0, false);
276
277     // common mistake is to copy&paste latitude and longitude into the 'lat' search box
278     $('form input[name=lat]').on('change', function(){
279         var coords = $(this).val().split(',');
280         if (coords.length == 2) {
281             $(this).val(L.Util.trim(coords[0]));
282             $(this).siblings('input[name=lon]').val(L.Util.trim(coords[1]));
283         }
284     });
285
286 });
287
288
289 jQuery(document).ready(function(){
290
291     if ( !$('#details-index-page').length ){ return; }
292
293     $('#form-by-type-and-id,#form-by-osm-url').on('submit', function(e){
294         e.preventDefault();
295
296         var val = $(this).find('input[type=edit]').val();
297         var matches = val.match(/^\s*([NWR])(\d+)\s*$/i);
298
299         if (!matches) {
300             matches = val.match(/\/(relation|way|node)\/(\d+)\s*$/);
301         }
302
303         if (matches) {
304             $(this).find('input[name=osmtype]').val(matches[1].charAt(0).toUpperCase());
305             $(this).find('input[name=osmid]').val(matches[2]);
306             $(this).get(0).submit();
307         } else {
308             alert('invalid input');
309         }
310     });
311 });
312
313 jQuery(document).ready(function(){
314
315     if ( !$('#details-page').length ){ return; }
316
317
318         map = new L.map('map', {
319                     // center: [nominatim_map_init.lat, nominatim_map_init.lon],
320                     // zoom:   nominatim_map_init.zoom,
321                     attributionControl: (nominatim_map_init.tile_attribution && nominatim_map_init.tile_attribution.length),
322                     scrollWheelZoom:    true, // !L.Browser.touch,
323                     touchZoom:          false,
324                 });
325
326
327         L.tileLayer(nominatim_map_init.tile_url, {
328             // moved to footer
329             attribution: (nominatim_map_init.tile_attribution || null ) //'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
330         }).addTo(map);
331
332         var layerGroup = new L.layerGroup().addTo(map);
333
334         var circle = L.circleMarker([nominatim_result.lat,nominatim_result.lon], { radius: 10, weight: 2, fillColor: '#ff7800', color: 'blue', opacity: 0.75});
335         map.addLayer(circle);
336
337         if ( nominatim_result.asgeojson ){
338
339             var geojson_layer = L.geoJson(
340                 parse_and_normalize_geojson_string(nominatim_result.asgeojson),
341                 {
342                     // http://leafletjs.com/reference-1.0.3.html#path-option
343                     style: function(feature) {
344                         return { interactive: false, color: 'blue' }; 
345                     }
346                 }
347             );
348             map.addLayer(geojson_layer);
349             map.fitBounds(geojson_layer.getBounds());
350         } else {
351             map.setView([nominatim_result.lat,nominatim_result.lon],10);
352         }
353
354         var osm2 = new L.TileLayer(nominatim_map_init.tile_url, {minZoom: 0, maxZoom: 13, attribution: (nominatim_map_init.tile_attribution || null )});
355         var miniMap = new L.Control.MiniMap(osm2, {toggleDisplay: true}).addTo(map);
356
357
358 });
359