8d04efd5f7a4bb19af540d5de470dc848f3f9233
[rails.git] / app / assets / javascripts / index / query.js
1 OSM.Query = function(map) {
2   var queryButton = $(".control-query .control-button"),
3     uninterestingTags = ['source', 'source_ref', 'source:ref', 'history', 'attribution', 'created_by', 'tiger:county', 'tiger:tlid', 'tiger:upload_uuid'],
4     marker;
5
6   queryButton.on("click", function (e) {
7     e.preventDefault();
8     e.stopPropagation();
9
10     if (queryButton.hasClass("active")) {
11       disableQueryMode();
12
13       OSM.router.route("/");
14     } else {
15       enableQueryMode();
16     }
17   });
18
19   $("#sidebar_content")
20     .on("mouseover", ".query-results li", function () {
21       var geometry = $(this).data("geometry")
22       if (geometry) map.addLayer(geometry);
23       $(this).addClass("selected");
24     })
25     .on("mouseout", ".query-results li", function () {
26       var geometry = $(this).data("geometry")
27       if (geometry) map.removeLayer(geometry);
28       $(this).removeClass("selected");
29     });
30
31   function interestingFeature(feature) {
32     if (feature.tags) {
33       for (var key in feature.tags) {
34         if (uninterestingTags.indexOf(key) < 0) {
35           return true;
36         }
37       }
38     }
39
40     return false;
41   }
42
43   function featurePrefix(feature) {
44     var tags = feature.tags;
45     var prefix = "";
46
47     if (tags.boundary === "administrative") {
48       prefix = I18n.t("geocoder.search_osm_nominatim.admin_levels.level" + tags.admin_level)
49     } else {
50       var prefixes = I18n.t("geocoder.search_osm_nominatim.prefix");
51
52       for (var key in tags) {
53         var value = tags[key];
54
55         if (prefixes[key]) {
56           if (prefixes[key][value]) {
57             return prefixes[key][value];
58           } else {
59             var first = value.substr(0, 1).toUpperCase(),
60               rest = value.substr(1).replace(/_/g, " ");
61
62             return first + rest;
63           }
64         }
65       }
66     }
67
68     if (!prefix) {
69       prefix = I18n.t("javascripts.query." + feature.type);
70     }
71
72     return prefix;
73   }
74
75   function featureName(feature) {
76     var tags = feature.tags;
77
78     if (tags["name"]) {
79       return tags["name"];
80     } else if (tags["ref"]) {
81       return tags["ref"];
82     } else if (tags["addr:housenumber"] && tags["addr:street"]) {
83       return tags["addr:housenumber"] + " " + tags["addr:street"];
84     } else {
85       return "#" + feature.id;
86     }
87   }
88
89   function featureLink(feature) {
90     if (feature.type === "area") {
91       if (feature.id >= 3600000000) {
92         var id = feature.id - 3600000000;
93
94         return "/browse/relation/" + id;
95       } else if (feature.id >= 2400000000) {
96         var id = feature.id - 2400000000;
97
98         return "/browse/way/" + id;
99       } else {
100         return "/browse/node/" + feature.id;
101       }
102     } else {
103       return "/browse/" + feature.type + "/" + feature.id;
104     }
105   }
106
107   function featureGeometry(feature, nodes) {
108     var geometry;
109
110     if (feature.type === "node") {
111       geometry = L.circleMarker([feature.lat, feature.lon]);
112     } else if (feature.type === "way") {
113       geometry = L.polyline(feature.nodes.map(function (node) {
114         return nodes[node];
115       }));
116     }
117
118     return geometry;
119   }
120
121   function runQuery(query, $section) {
122     var $ul = $section.find("ul");
123
124     $ul.empty();
125     $section.show();
126
127     $section.find(".loader").oneTime(1000, "loading", function () {
128       $(this).show();
129     });
130
131     $.ajax({
132       url: "http://overpass-api.de/api/interpreter",
133       method: "GET",
134       data: {
135         data: "[timeout:5][out:json];" + query,
136       },
137       success: function(results) {
138         var nodes = {};
139
140         $section.find(".loader").stopTime("loading").hide();
141
142         results.elements.forEach(function (element) {
143           if (element.type === "node") {
144             nodes[element.id] = [element.lat, element.lon];
145           }
146         });
147
148         for (var i = 0; i < results.elements.length; i++) {
149           var element = results.elements[i];
150
151           if (interestingFeature(element)) {
152             var $li = $("<li>")
153               .data("geometry", featureGeometry(element, nodes))
154               .appendTo($ul);
155             var $p = $("<p>")
156               .addClass("inner12 search_results_entry clearfix")
157               .text(featurePrefix(element) + " ")
158               .appendTo($li);
159
160             $("<a>")
161               .attr("href", featureLink(element))
162               .text(featureName(element))
163               .appendTo($p);
164           }
165         }
166       }
167     });
168   }
169
170   function queryOverpass(lat, lng) {
171     var latlng = L.latLng(lat, lng),
172       around = "around:10.0," + lat + "," + lng,
173       features = "(node(" + around + ");way(" + around + ");relation(" + around + "))",
174       nearby = "((" + features + ";way(bn));node(w));out;",
175       isin = "(is_in(" + lat + "," + lng + ");>);out;";
176
177     $("#sidebar_content .query-intro")
178       .hide();
179
180     if (marker) {
181       marker.setLatLng(latlng).addTo(map);
182     } else {
183       marker = L.circle(latlng, 10, { clickable: false }).addTo(map);
184     }
185
186     $(document).everyTime(75, "fadeQueryMarker", function (i) {
187       if (i == 10) {
188         map.removeLayer(marker);
189       } else {
190         marker.setStyle({
191           opacity: 0.5 - i * 0.05,
192           fillOpacity: 0.2 - i * 0.02
193         });
194       }
195     }, 10);
196
197     runQuery(nearby, $("#query-nearby"));
198     runQuery(isin, $("#query-isin"));
199   }
200
201   function clickHandler(e) {
202     var precision = OSM.zoomPrecision(map.getZoom()),
203       lat = e.latlng.lat.toFixed(precision),
204       lng = e.latlng.lng.toFixed(precision);
205
206     OSM.router.route("/query?lat=" + lat + "&lon=" + lng);
207   }
208
209   function enableQueryMode() {
210     queryButton.addClass("active");
211     map.on("click", clickHandler);
212     $(map.getContainer()).addClass("query-active");
213   }
214
215   function disableQueryMode() {
216     if (marker) map.removeLayer(marker);
217     $(map.getContainer()).removeClass("query-active");
218     map.off("click", clickHandler);
219     queryButton.removeClass("active");
220   }
221
222   var page = {};
223
224   page.pushstate = page.popstate = function(path) {
225     OSM.loadSidebarContent(path, function () {
226       page.load(path);
227     });
228   };
229
230   page.load = function(path) {
231     var params = querystring.parse(path.substring(path.indexOf('?') + 1));
232
233     queryOverpass(params.lat, params.lon);
234     enableQueryMode();
235
236     return map.getState();
237   };
238
239   page.unload = function() {
240     disableQueryMode();
241   };
242
243   return page;
244 };