]> git.openstreetmap.org Git - rails.git/blob - app/assets/openlayers/SimplePanZoom.js
Avoid unnecessary array allocations
[rails.git] / app / assets / openlayers / SimplePanZoom.js
1 /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for 
2  * full list of contributors). Published under the 2-clause BSD license.
3  * See license.txt in the OpenLayers distribution or repository for the
4  * full text of the license. */
5
6
7 /**
8  * @requires OpenLayers/Control/PanZoom.js
9  */
10
11 /**
12  * Class: OpenLayers.Control.PanZoomBar
13  * The PanZoomBar is a visible control composed of a
14  * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. 
15  * By default it is displayed in the upper left corner of the map as 4
16  * directional arrows above a vertical slider.
17  *
18  * Inherits from:
19  *  - <OpenLayers.Control.PanZoom>
20  */
21 OpenLayers.Control.SimplePanZoom = OpenLayers.Class(OpenLayers.Control.PanZoom, {
22
23     /** 
24      * APIProperty: zoomStopWidth
25      */
26     zoomStopWidth: 18,
27
28     /** 
29      * APIProperty: zoomStopHeight
30      */
31     zoomStopHeight: 7,
32
33     /** 
34      * Property: slider
35      */
36     slider: null,
37
38     /** 
39      * Property: sliderEvents
40      * {<OpenLayers.Events>}
41      */
42     sliderEvents: null,
43
44     /** 
45      * Property: zoombarDiv
46      * {DOMElement}
47      */
48     zoombarDiv: null,
49
50     /** 
51      * APIProperty: zoomWorldIcon
52      * {Boolean}
53      */
54     zoomWorldIcon: false,
55
56     /**
57      * APIProperty: panIcons
58      * {Boolean} Set this property to false not to display the pan icons. If
59      * false the zoom world icon is placed under the zoom bar. Defaults to
60      * true.
61      */
62     panIcons: true,
63
64     /**
65      * APIProperty: forceFixedZoomLevel
66      * {Boolean} Force a fixed zoom level even though the map has 
67      *     fractionalZoom
68      */
69     forceFixedZoomLevel: false,
70
71     /**
72      * Property: mouseDragStart
73      * {<OpenLayers.Pixel>}
74      */
75     mouseDragStart: null,
76
77     /**
78      * Property: deltaY
79      * {Number} The cumulative vertical pixel offset during a zoom bar drag.
80      */
81     deltaY: null,
82
83     /**
84      * Property: zoomStart
85      * {<OpenLayers.Pixel>}
86      */
87     zoomStart: null,
88
89     /**
90      * Constructor: OpenLayers.Control.PanZoomBar
91      */ 
92     buttons: null,
93
94     /**
95      * APIMethod: destroy
96      */
97     destroy: function() {
98
99         this._removeZoomBar();
100
101         this.map.events.un({
102             "changebaselayer": this.redraw,
103             "updatesize": this.redraw,
104             scope: this
105         });
106
107         OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
108
109         delete this.mouseDragStart;
110         delete this.zoomStart;
111     },
112     
113     /**
114      * Method: setMap
115      * 
116      * Parameters:
117      * map - {<OpenLayers.Map>} 
118      */
119     setMap: function(map) {
120         OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
121         this.map.events.on({
122             "changebaselayer": this.redraw,
123             "updatesize": this.redraw,
124             scope: this
125         });
126     },
127
128     /** 
129      * Method: redraw
130      * clear the div and start over.
131      */
132     redraw: function() {
133         if (this.div !== null) {
134             this.removeButtons();
135             this._removeZoomBar();
136         }  
137         this.draw();
138         this.moveZoomBar();
139     },
140     
141     /**
142     * Method: draw 
143     *
144     * Parameters:
145     * px - {<OpenLayers.Pixel>} 
146     */
147     draw: function(px) {
148         // initialize our internal div
149         OpenLayers.Control.prototype.draw.apply(this, arguments);
150         px = this.position.clone();
151
152         // place the controls
153         this.buttons = [];
154         var ids = ['panup', 'panleft', 'panright', 'pandown', 'zoomout', 'zoomin'];
155
156         for (var i = 0; i < ids.length; i++) {
157             var b = document.createElement('div');
158             b.id = ids[i];
159             b.action = ids[i];
160             b.className = 'button olButton';
161             this.div.appendChild(b);
162             this.buttons.push(b);
163         }
164
165         this._addZoomBar();
166         return this.div;
167     },
168
169     /** 
170     * Method: _addZoomBar
171     * 
172     * Parameters:
173     * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start.
174     */
175     _addZoomBar:function() {
176         var id = this.id + "_" + this.map.id;
177         var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
178         var slider = document.createElement('div');
179         slider.id = 'slider';
180         slider.className = 'button';
181         slider.style.cursor = 'move';
182         this.slider = slider;
183         
184         this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
185             { includeXY: true });
186         this.sliderEvents.on({
187             "touchstart": this.zoomBarDown,
188             "touchmove": this.zoomBarDrag,
189             "touchend": this.zoomBarUp,
190             "mousedown": this.zoomBarDown,
191             "mousemove": this.zoomBarDrag,
192             "mouseup": this.zoomBarUp
193         });
194         
195         var height = this.zoomStopHeight * (this.map.getNumZoomLevels());
196         
197         // this is the background image
198         var div = document.createElement('div');
199         div.className = 'button olButton';
200         div.id = 'zoombar';
201         this.zoombarDiv = div;
202         
203         this.div.appendChild(div);
204         this.startTop = 75;
205         this.div.appendChild(slider);
206
207         this.map.events.register("zoomend", this, this.moveZoomBar);
208     },
209     
210     /**
211      * Method: _removeZoomBar
212      */
213     _removeZoomBar: function() {
214         this.sliderEvents.un({
215             "touchstart": this.zoomBarDown,
216             "touchmove": this.zoomBarDrag,
217             "touchend": this.zoomBarUp,
218             "mousedown": this.zoomBarDown,
219             "mousemove": this.zoomBarDrag,
220             "mouseup": this.zoomBarUp
221         });
222         this.sliderEvents.destroy();
223         
224         this.div.removeChild(this.zoombarDiv);
225         this.zoombarDiv = null;
226         this.div.removeChild(this.slider);
227         this.slider = null;
228         
229         this.map.events.unregister("zoomend", this, this.moveZoomBar);
230     },
231     
232     /**
233      * Method: onButtonClick
234      *
235      * Parameters:
236      * evt - {Event}
237      */
238     onButtonClick: function(evt) {
239         OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments);
240         if (evt.buttonElement === this.zoombarDiv) {
241             var levels = evt.buttonXY.y / this.zoomStopHeight;
242             if (this.forceFixedZoomLevel || !this.map.fractionalZoom) {
243                 levels = Math.floor(levels);
244             } 
245             var zoom = (this.map.getNumZoomLevels() - 1) - levels; 
246             zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1);
247             this.map.zoomTo(zoom);
248         }
249     },
250     
251     /**
252      * Method: passEventToSlider
253      * This function is used to pass events that happen on the div, or the map,
254      * through to the slider, which then does its moving thing.
255      *
256      * Parameters:
257      * evt - {<OpenLayers.Event>} 
258      */
259     passEventToSlider:function(evt) {
260         this.sliderEvents.handleBrowserEvent(evt);
261     },
262     
263     /*
264      * Method: zoomBarDown
265      * event listener for clicks on the slider
266      *
267      * Parameters:
268      * evt - {<OpenLayers.Event>} 
269      */
270     zoomBarDown:function(evt) {
271         if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
272             return;
273         }
274         this.map.events.on({
275             "touchmove": this.passEventToSlider,
276             "mousemove": this.passEventToSlider,
277             "mouseup": this.passEventToSlider,
278             scope: this
279         });
280         this.mouseDragStart = evt.xy.clone();
281         this.zoomStart = evt.xy.clone();
282         this.div.style.cursor = "move";
283         // reset the div offsets just in case the div moved
284         this.zoombarDiv.offsets = null; 
285         OpenLayers.Event.stop(evt);
286     },
287     
288     /*
289      * Method: zoomBarDrag
290      * This is what happens when a click has occurred, and the client is
291      * dragging.  Here we must ensure that the slider doesn't go beyond the
292      * bottom/top of the zoombar div, as well as moving the slider to its new
293      * visual location
294      *
295      * Parameters:
296      * evt - {<OpenLayers.Event>}
297      */
298     zoomBarDrag: function(evt) {
299         if (this.mouseDragStart !== null) {
300             var deltaY = this.mouseDragStart.y - evt.xy.y;
301             var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv);
302             if ((evt.clientY - offsets[1]) > 0 && 
303                 (evt.clientY - offsets[1]) < 140) {
304                 var newTop = parseInt(this.slider.style.top, 10) - deltaY;
305                 this.slider.style.top = newTop + "px";
306                 this.mouseDragStart = evt.xy.clone();
307             }
308             // set cumulative displacement
309             this.deltaY = this.zoomStart.y - evt.xy.y;
310             OpenLayers.Event.stop(evt);
311         }
312     },
313
314     /*
315      * Method: zoomBarUp
316      * Perform cleanup when a mouseup event is received -- discover new zoom
317      * level and switch to it.
318      *
319      * Parameters:
320      * evt - {<OpenLayers.Event>}
321      */
322     zoomBarUp: function(evt) {
323         if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
324             return;
325         }
326         if (this.mouseDragStart) {
327             this.div.style.cursor = "";
328             this.map.events.un({
329                 "touchmove": this.passEventToSlider,
330                 "mouseup": this.passEventToSlider,
331                 "mousemove": this.passEventToSlider,
332                 scope: this
333             });
334             var zoomLevel = this.map.zoom;
335             zoomLevel += this.deltaY/this.zoomStopHeight;
336             zoomLevel = Math.max(Math.round(zoomLevel), 0);
337             this.map.zoomTo(zoomLevel);
338             this.mouseDragStart = null;
339             this.zoomStart = null;
340             this.deltaY = 0;
341             OpenLayers.Event.stop(evt);
342         }
343     },
344
345     /*
346     * Method: moveZoomBar
347     * Change the location of the slider to match the current zoom level.
348     */
349     moveZoomBar:function() {
350         var newTop =
351             ((this.map.getNumZoomLevels()-1) - this.map.getZoom()) *
352             this.zoomStopHeight + this.startTop;
353         this.slider.style.top = newTop + "px";
354     },
355     CLASS_NAME: "OpenLayers.Control.SimplePanZoom"
356 });