Customize requestSuccess to limit number of features actually drawn on the map
[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     }
24     
25     function stopBrowse() {
26         if (gml) {
27             gml.destroy();
28             gml = null; 
29         } 
30         if (sf) {   
31             sf.destroy();  
32             sf = null;
33         } 
34         if (currentFeature) {
35             currentFeature.destroy(); 
36             currentFeature = null; 
37         } 
38     }
39     
40     function startDrag() {
41       $("drag_box").innerHTML='Drag a box on the map to select an area';
42        box.activate(); 
43        return false;
44     };
45     $("drag_box").onclick = startDrag;
46     
47     function useMap() {
48         var bounds = map.getExtent();
49         setBounds(bounds);
50         getData(bounds);
51         return false;
52     }
53     $("use_map").onclick = useMap;
54     
55     function endDrag(bbox) {
56         var bounds = bbox.getBounds();
57         setBounds(bounds);
58         box.deactivate();
59         getData(bounds);
60         $("drag_box").innerHTML = "Manually select a different area";
61     }
62     function displayFeatureWarning() {
63         var div = document.createElement("div");
64         var p = document.createElement("p");
65         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.")); 
66         div.appendChild(p);
67         var input = document.createElement("input");
68         input.type = "submit";
69         input.value = "Load Data";
70         input.onclick = loadFeatureList;
71         div.appendChild(input); 
72         $("object").innerHTML="";
73         $("object").appendChild(div);
74     }
75     
76     function loadFeatureList() {
77         gml.addFeatures(featureList);
78         gml.events.triggerEvent("loadend");
79     }    
80
81     function customDataLoader(request) { 
82         var doc = request.responseXML;
83         
84         if (!doc || !doc.documentElement) {
85             doc = request.responseText;
86         }
87         
88         var options = {};
89         
90         OpenLayers.Util.extend(options, this.formatOptions);
91         if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
92             options.externalProjection = this.projection;
93             options.internalProjection = this.map.getProjectionObject();
94         }    
95         
96         var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
97         var features = gml.read(doc);
98         if (!this.maxFeatures || features.length <= this.maxFeatures) {
99             this.addFeatures(features);
100             this.events.triggerEvent("loadend");
101             featureList = []; 
102         } else {
103             featureList = features;
104             displayFeatureWarning();
105         }
106     }
107
108     function getData(bounds) {
109         $("status").innerHTML = "Loading...";
110         
111         bounds.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
112         var url = "/api/0.5/map?bbox="+bounds.toBBOX();
113         
114         if (!gml) {
115             var def = OpenLayers.Feature.Vector.style['default'];
116             var style = new OpenLayers.Style();
117             style.addRules([new OpenLayers.Rule( 
118               {'symbolizer': 
119                 {"Polygon": {'fillColor': '#ff0000', 'strokeColor': '#ff0000'},
120                  "Line": {'fillColor': '#ffff00', 'strokeColor': '#000000', strokeOpacity: '0.4'},
121                  "Point": {'fillColor': '#00ff00', 'strokeColor': '#00ff00'}}
122               }
123             )]);
124             gml = new OpenLayers.Layer.GML("Data",url, 
125                     {format: OpenLayers.Format.OSM, formatOptions: {checkTags: true},
126                      maxFeatures: 100, requestSuccess: customDataLoader,
127                      styleMap: new OpenLayers.StyleMap({'default': style, 'select': {'strokeColor': '#0000ff'}})
128                     }
129             );
130             gml.events.register("loadend", gml, dataLoaded );
131             map.addLayer(gml);
132             
133             sf = new OpenLayers.Control.SelectFeature(gml, {'onSelect': onFeatureSelect});
134             map.addControl(sf);
135             sf.activate();
136         } else {
137             gml.setUrl(url);
138         }
139
140         currentFeature = null;
141     }
142     
143     function dataLoaded() { 
144         $("status").innerHTML = "Loaded " + this.features.length + " features. (<a href='"+ this.url+"'>API</a>)";
145         
146         objList = document.createElement("ul");
147         for (var i = 0; i < this.features.length; i++) {
148             var feature = this.features[i]; 
149             
150             // Type, for linking
151             var type ="way";
152             if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
153                 type = "node";
154             }   
155             var nice_name = type.substr(0,1).toUpperCase() + type.substr(1,type.length); 
156             var li = document.createElement("li");
157             li.appendChild(document.createTextNode(nice_name + " "));
158             
159             // Link, for viewing in the tab
160             var link = document.createElement("a");
161             link.href =  "/browse/" + type + "/" + feature.osm_id; 
162             var name = feature.attributes.name || feature.osm_id;
163             link.appendChild(document.createTextNode(name));
164             link.feature = feature;
165             link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
166             li.appendChild(link);
167
168             objList.appendChild(li);
169         }
170         $("object").innerHTML = "";
171         $("object").appendChild(objList); 
172     }
173     
174     function viewFeatureLink() {
175         var layer = this.feature.layer;
176         for (var i = 0; i < layer.selectedFeatures.length; i++) {
177             var f = layer.selectedFeatures[i]; 
178             layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
179         }
180         onFeatureSelect(this.feature);
181         map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
182         return false;
183     }
184     
185     function loadObjList() {
186         $("object").innerHTML="";
187         $("object").appendChild(objList);
188         return false;
189     }
190       
191     function onFeatureSelect(feature) {
192         // Unselect previously selected feature
193         if (currentFeature) {
194           currentFeature.layer.drawFeature(
195             currentFeature, currentFeature.layer.styleMap.createSymbolizer(currentFeature, "default")
196           );
197         }
198
199         // Redraw in selected style
200         feature.layer.drawFeature(
201           feature, feature.layer.styleMap.createSymbolizer(feature, "select")
202         );
203
204         // If the current object is the list, don't innerHTML="", since that could clar it.   
205         if ($("object").firstChild == objList) { 
206             $("object").removeChild(objList);
207         } else { 
208             $("object").innerHTML = "";
209         }   
210         
211         // Create a link back to the object list
212         var div = document.createElement("div");
213         var link = document.createElement("a");
214         link.href="#";
215         link.onclick = loadObjList;
216         link.appendChild(document.createTextNode("Back to Object List"));
217         div.appendChild(link)
218         $("object").appendChild(div);    
219         
220         // Now the list of attributes
221         var ul = document.createElement("ul");
222         var type = "way";
223         if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
224             type = "node";
225         }    
226         var li = document.createElement("li");
227         var link = document.createElement("a");   
228         link.href =  "/browse/"+type+"/"+feature.osm_id;
229         link.appendChild(document.createTextNode(feature.osm_id));
230         li.appendChild(link);
231         ul.appendChild(li);
232         for (var key in feature.attributes) {
233             var li = document.createElement("li");
234             var b = document.createElement("b");
235             b.appendChild(document.createTextNode(key));
236             li.appendChild(b);
237             li.appendChild(document.createTextNode(": " + feature.attributes[key]));
238             ul.appendChild(li);
239         }
240         $("object").appendChild(ul);
241         
242         // Stash the currently drawn feature
243         currentFeature = feature; 
244     }   
245     
246     function setBounds(bounds) {
247       var epsg4326 = new OpenLayers.Projection("EPSG:4326");
248       var decimals = Math.pow(10, Math.floor(map.getZoom() / 3));
249
250       bounds = bounds.clone().transform(map.getProjectionObject(), epsg4326);
251
252       $("minlon").innerHTML = Math.round(bounds.left * decimals) / decimals;
253       $("minlat").innerHTML = Math.round(bounds.bottom * decimals) / decimals;
254       $("maxlon").innerHTML = Math.round(bounds.right * decimals) / decimals;
255       $("maxlat").innerHTML = Math.round(bounds.top * decimals) / decimals;
256     }
257
258     start();
259 EOJ