don't let users select areas bigger than allowed
[rails.git] / app / views / browse / start.rjs
1 page.replace_html :sidebar_title, 'Browse'
2 page.replace_html :sidebar_content, :partial => 'start'
3 page << <<EOJ
4     
5     var gml, sf, objList, currentFeature, featureList;
6     OpenLayers.Feature.Vector.style['default'].strokeWidth = 3;
7     OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
8     
9     function start() {
10         openSidebar({ onclose: stopBrowse });
11         var vectors = new OpenLayers.Layer.Vector();
12     
13         box = new OpenLayers.Control.DrawFeature(vectors, OpenLayers.Handler.RegularPolygon, { 
14           handlerOptions: {
15             sides: 4,
16             snapAngle: 90,
17             irregular: true,
18             persist: true,
19             callbacks: { done: endDrag }
20           }
21         });
22         map.addControl(box);
23         map.events.register("moveend", map, validateLinks);
24         map.events.triggerEvent("moveend");
25     }
26     
27     function stopBrowse() {
28         if (gml) {
29             gml.destroy();
30             gml = null; 
31         } 
32         if (sf) {   
33             sf.destroy();  
34             sf = null;
35         } 
36         if (currentFeature) {
37             currentFeature.destroy(); 
38             currentFeature = null; 
39         } 
40         map.events.unregister("moveend", map, validateLinks);
41     }
42     
43     function startDrag() {
44       $("drag_box").innerHTML='Drag a box on the map to select an area';
45        box.activate(); 
46        return false;
47     };
48     $("drag_box").onclick = startDrag;
49     
50     function useMap() {
51         var bounds = map.getExtent();
52         setBounds(bounds);
53         getData(bounds);
54         return false;
55     }
56     $("use_map").onclick = useMap;
57     
58     function endDrag(bbox) {
59         var bounds = bbox.getBounds();
60         setBounds(bounds);
61         box.deactivate();
62         getData(bounds);
63         $("drag_box").innerHTML = "Manually select a different area";
64     }
65     
66     function displayFeatureWarning() {
67         var div = document.createElement("div");
68         var p = document.createElement("p");
69         p.appendChild(document.createTextNode("You have loaded an area which contains " + featureList.length + " features. In general, some browsers may not cope well with displaying this quantity of data. Generally, browsers work best at displaying less than 100 features at a time: doing anything else may make your browser slow/unresponsive. If you are sure you want to display this data, you may do so by clicking the button below.")); 
70         div.appendChild(p);
71         var input = document.createElement("input");
72         input.type = "submit";
73         input.value = "Load Data";
74         input.onclick = loadFeatureList;
75         div.appendChild(input); 
76         $("object").innerHTML="";
77         $("object").appendChild(div);
78     }
79     
80     function loadFeatureList() {
81         gml.addFeatures(featureList);
82         gml.events.triggerEvent("loadend");
83     }    
84
85     function customDataLoader(request) { 
86         var doc = request.responseXML;
87         
88         if (!doc || !doc.documentElement) {
89             doc = request.responseText;
90         }
91         
92         var options = {};
93         
94         OpenLayers.Util.extend(options, this.formatOptions);
95         if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
96             options.externalProjection = this.projection;
97             options.internalProjection = this.map.getProjectionObject();
98         }    
99         
100         var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
101         var features = gml.read(doc);
102         if (!this.maxFeatures || features.length <= this.maxFeatures) {
103             this.addFeatures(features);
104             this.events.triggerEvent("loadend");
105             featureList = []; 
106         } else {
107             featureList = features;
108             displayFeatureWarning();
109         }
110     }
111
112     function getData(bounds) {
113         
114         bounds.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
115         var size = bounds.getWidth() * bounds.getHeight(); 
116         if (size > 0.25) {
117             $("status").innerHTML = "Unable to load: Bounding box size of " + size + " is too large. (Must be smaller than 0.25)"; 
118             return;
119         }
120
121         var url = "/api/0.5/map?bbox="+bounds.toBBOX();
122         
123         $("status").innerHTML = "Loading...";
124         if (!gml) {
125             var def = OpenLayers.Feature.Vector.style['default'];
126             var style = new OpenLayers.Style();
127             style.addRules([new OpenLayers.Rule( 
128               {'symbolizer': 
129                 {"Polygon": {'fillColor': '#ff0000', 'strokeColor': '#ff0000'},
130                  "Line": {'fillColor': '#ffff00', 'strokeColor': '#000000', strokeOpacity: '0.4'},
131                  "Point": {'fillColor': '#00ff00', 'strokeColor': '#00ff00'}}
132               }
133             )]);
134             gml = new OpenLayers.Layer.GML("Data",url, 
135                     {format: OpenLayers.Format.OSM, formatOptions: {checkTags: true},
136                      maxFeatures: 100, requestSuccess: customDataLoader,
137                      styleMap: new OpenLayers.StyleMap({'default': style, 'select': {'strokeColor': '#0000ff'}})
138                     }
139             );
140             gml.events.register("loadend", gml, dataLoaded );
141             map.addLayer(gml);
142             
143             sf = new OpenLayers.Control.SelectFeature(gml, {'onSelect': onFeatureSelect});
144             sf.handler.stopDown = false;
145             sf.handler.stopUp = false;
146             map.addControl(sf);
147             sf.activate();
148              
149         } else {
150             gml.setUrl(url);
151         }
152
153         currentFeature = null;
154     }
155     
156     function dataLoaded() { 
157         $("status").innerHTML = "Loaded " + this.features.length + " features. (<a href='"+ this.url+"'>API</a>)";
158         
159         objList = document.createElement("ul");
160         for (var i = 0; i < this.features.length; i++) {
161             var feature = this.features[i]; 
162             
163             // Type, for linking
164             var type ="way";
165             if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
166                 type = "node";
167             }   
168             var nice_name = type.substr(0,1).toUpperCase() + type.substr(1,type.length); 
169             var li = document.createElement("li");
170             li.appendChild(document.createTextNode(nice_name + " "));
171             
172             // Link, for viewing in the tab
173             var link = document.createElement("a");
174             link.href =  "/browse/" + type + "/" + feature.osm_id; 
175             var name = feature.attributes.name || feature.osm_id;
176             link.appendChild(document.createTextNode(name));
177             link.feature = feature;
178             link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
179             li.appendChild(link);
180
181             objList.appendChild(li);
182         }
183         $("object").innerHTML = "";
184         $("object").appendChild(objList); 
185     }
186     
187     function viewFeatureLink() {
188         var layer = this.feature.layer;
189         for (var i = 0; i < layer.selectedFeatures.length; i++) {
190             var f = layer.selectedFeatures[i]; 
191             layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
192         }
193         onFeatureSelect(this.feature);
194         map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
195         return false;
196     }
197     
198     function loadObjList() {
199         $("object").innerHTML="";
200         $("object").appendChild(objList);
201         return false;
202     }
203       
204     function onFeatureSelect(feature) {
205         // Unselect previously selected feature
206         if (currentFeature) {
207           currentFeature.layer.drawFeature(
208             currentFeature, currentFeature.layer.styleMap.createSymbolizer(currentFeature, "default")
209           );
210         }
211
212         // Redraw in selected style
213         feature.layer.drawFeature(
214           feature, feature.layer.styleMap.createSymbolizer(feature, "select")
215         );
216
217         // If the current object is the list, don't innerHTML="", since that could clar it.   
218         if ($("object").firstChild == objList) { 
219             $("object").removeChild(objList);
220         } else { 
221             $("object").innerHTML = "";
222         }   
223         
224         // Create a link back to the object list
225         var div = document.createElement("div");
226         var link = document.createElement("a");
227         link.href="#";
228         link.onclick = loadObjList;
229         link.appendChild(document.createTextNode("Back to Object List"));
230         div.appendChild(link)
231         $("object").appendChild(div);    
232         
233         // Now the list of attributes
234         var ul = document.createElement("ul");
235         var type = "way";
236         if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
237             type = "node";
238         }    
239         var li = document.createElement("li");
240         var link = document.createElement("a");   
241         link.href =  "/browse/"+type+"/"+feature.osm_id;
242         link.appendChild(document.createTextNode(feature.osm_id));
243         li.appendChild(link);
244         ul.appendChild(li);
245         for (var key in feature.attributes) {
246             var li = document.createElement("li");
247             var b = document.createElement("b");
248             b.appendChild(document.createTextNode(key));
249             li.appendChild(b);
250             li.appendChild(document.createTextNode(": " + feature.attributes[key]));
251             ul.appendChild(li);
252         }
253         $("object").appendChild(ul);
254         
255         // Stash the currently drawn feature
256         currentFeature = feature; 
257     }   
258     
259     function setBounds(bounds) {
260       var epsg4326 = new OpenLayers.Projection("EPSG:4326");
261       var decimals = Math.pow(10, Math.floor(map.getZoom() / 3));
262
263       bounds = bounds.clone().transform(map.getProjectionObject(), epsg4326);
264
265       $("minlon").innerHTML = Math.round(bounds.left * decimals) / decimals;
266       $("minlat").innerHTML = Math.round(bounds.bottom * decimals) / decimals;
267       $("maxlon").innerHTML = Math.round(bounds.right * decimals) / decimals;
268       $("maxlat").innerHTML = Math.round(bounds.top * decimals) / decimals;
269     }
270     function validateLinks() {
271         var bounds = this.getExtent();
272         bounds = bounds.clone().transform(map.getProjectionObject(), epsg4326);
273
274         if (bounds.getWidth() * bounds.getHeight() > 0.25) {
275           $("use_map").style.display = "none";
276         } else {
277           $("use_map").style.display = "inline";
278         }  
279     }
280     start();
281 EOJ