PageSourceSearch

https://arcovara.ee/modules/mod_arcosearch/assets/keydragzoom.js

js arcovara.ee collected 2026-10-02 05:45:43 UTC 20,317 bytes, 560 lines download raw bytes

1/**
2 * @name Key Drag Zoom for V3
3 * @version 1.0
4 * @author: Nianwei Liu [nianwei at gmail dot com] & Gary Little [gary at luxcentral dot com]
5 * @fileoverview This library adds a drag zoom capability to a Google map.
6 *  When drag zoom is enabled, holding down a user-defined hot key <code>(shift | ctrl | alt)</code>
7 *  while dragging a box around an area of interest will zoom the map
8 *  to that area when the hot key is released. 
9 *  Only one line of code is needed: <code>google.maps.Map.enableKeyDragZoom();</code>
10 *  <p>
11 *  Note that if the map's container has a border around it, the border widths must be specified
12 *  in pixel units (or as thin, medium, or thick). This is required because of an MSIE limitation.
13 *  <p>NL: 2009-05-28: initial port to core API V3.
14 */
15/*!
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *       http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 */
29(function () {
30  /*jslint browser:true */
31   /*global google */
32  /**
33   * Converts 'thin', 'medium', and 'thick' to pixel widths
34   * in an MSIE environment. Not called for other browsers
35   * because getComputedStyle() returns pixel widths automatically.
36   * @param {String} widthValue
37   */ 
38  var toPixels = function (widthValue) {
39    var px;
40    switch (widthValue) {
41    case 'thin':
42      px = "2px";
43      break;
44    case 'medium':
45      px = "4px";
46      break;
47    case 'thick':
48      px = "6px";
49      break;
50    default:
51      px = widthValue;
52    }
53    return px;
54  };
55 /**
56  * Get the widths of the borders of an HTML element.
57  *
58  * @param {Object} h  HTML element
59  * @return {Object} widths object (top, bottom left, right)
60  */
61  var getBorderWidths = function (h) {
62    var computedStyle;
63    var bw = {};
64    if (document.defaultView && document.defaultView.getComputedStyle) {
65      computedStyle = h.ownerDocument.defaultView.getComputedStyle(h, "");
66      if (computedStyle) {
67        // The computed styles are always in pixel units (good!)
68        bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0;
69        bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
70        bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0;
71        bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0;
72        return bw;
73      }
74    } else if (document.documentElement.currentStyle) { // MSIE
75      if (h.currentStyle) {
76        // The current styles may not be in pixel units so try to convert (bad!)
77        bw.top = parseInt(toPixels(h.currentStyle.borderTopWidth), 10) || 0;
78        bw.bottom = parseInt(toPixels(h.currentStyle.borderBottomWidth), 10) || 0;
79        bw.left = parseInt(toPixels(h.currentStyle.borderLeftWidth), 10) || 0;
80        bw.right = parseInt(toPixels(h.currentStyle.borderRightWidth), 10) || 0;
81        return bw;
82      }
83    }
84    // Shouldn't get this far for any modern browser
85    bw.top = parseInt(h.style["border-top-width"], 10) || 0;
86    bw.bottom = parseInt(h.style["border-bottom-width"], 10) || 0;
87    bw.left = parseInt(h.style["border-left-width"], 10) || 0;
88    bw.right = parseInt(h.style["border-right-width"], 10) || 0;
89    return bw;
90  };
91
92  /**
93   * Get the position of the mouse relative to the document.
94   * @param {Object} e  Mouse event
95   * @return {Object} left & top position
96   */
97  var getMousePosition = function (e) {
98    var posX = 0, posY = 0;
99    e = e || window.event;
100    if (typeof e.pageX !== "undefined") {
101      posX = e.pageX;
102      posY = e.pageY;
103    } else if (typeof e.clientX !== "undefined") {
104      posX = e.clientX +
105      (typeof document.documentElement.scrollLeft !== "undefined" ? document.documentElement.scrollLeft : document.body.scrollLeft);
106      posY = e.clientY +
107      (typeof document.documentElement.scrollTop !== "undefined" ? document.documentElement.scrollTop : document.body.scrollTop);
108    }
109    return {
110      left: posX,
111      top: posY
112    };
113  };
114
115  /**
116   * Get the position of an HTML element relative to the document.
117   * @param {Object} h  HTML element
118   * @return {Object} left & top position
119   */
120  var getElementPosition = function (h) {
121    var posX = h.offsetLeft;
122    var posY = h.offsetTop;
123    var parent = h.offsetParent;
124    // Add offsets for all ancestors in the hierarchy
125    while (parent !== null) {
126      // Adjust for scrolling elements which may affect the map position.
127      //
128      // See http://www.howtocreate.co.uk/tutorials/javascript/browserspecific
129      //
130      // "...make sure that every element [on a Web page] with an overflow
131      // of anything other than visible also has a position style set to
132      // something other than the default static..."
133      if (parent !== document.body && parent !== document.documentElement) {
134        posX -= parent.scrollLeft;
135        posY -= parent.scrollTop;
136      }
137      posX += parent.offsetLeft;
138      posY += parent.offsetTop;
139      parent = parent.offsetParent;
140    }
141    return {
142      left: posX,
143      top: posY
144    };
145  };
146  /**
147   * Set the properties of an object to those from another object.
148   * @param {Object} obj target object
149   * @param {Object} vals source object
150   */
151  var setVals = function (obj, vals) {
152    if (obj && vals) {
153      for (var x in vals) {
154        if (vals.hasOwnProperty(x)) {
155          obj[x] = vals[x];
156        }
157      }
158    }
159    return obj;
160  };
161  /**
162   * Set the opacity. If op is not passed in, this function just performs an MSIE fix.
163   * @param {Node} div
164   * @param {Number} op (0-1)
165   */
166  var setOpacity = function (div, op) {
167    if (typeof op !== 'undefined') {
168      div.style.opacity = op;
169    }
170    if (typeof div.style.opacity !== 'undefined') {
171      div.style.filter = "alpha(opacity=" + (div.style.opacity * 100) + ")";
172    }
173  };
174    
175  /**
176   * @name KeyDragZoomOptions
177   * @class This class represents the optional parameter passed into <code>google.maps.Map.enableDragBoxZoom</code>.
178   * @property {String} [key] the hot key to hold down to activate a drag zoom, <code>shift | ctrl | alt</code>.
179   * The default is <code>shift</code>.
180   * @property {Object} [boxStyle] the css style of the zoom box.
181   * The default is <code>
181{border: 'thin solid #FF0000'}</code>.
182   * Border widths must be specified in pixel units (or as thin, medium, or thick).
183   * @property {Object} [paneStyle] the css style of the pane which overlays the map when a drag zoom is activated.
184   * The default is <code>{backgroundColor: 'white', opacity: 0.0, cursor: 'crosshair'}</code>.
185   */
186  /**
187   * @name DragZoom
188   * @class This class represents a drag zoom object for a map. The object is activated by holding down the hot key.
189   * This object is created when <code>google.maps.Map.enableKeyDragZoom</code> is called; it cannot be created directly.
190   * Use <code>google.maps.Map.getDragZoomObject</code> to gain access to this object in order to attach event listeners.
191   * @param {google.maps.Map} map
192   * @param {KeyDragZoomOptions} opt_zoomOpts
193   */
194  function DragZoom(map, opt_zoomOpts) {
195    var ov = new google.maps.OverlayView();
196    var me = this;
197    ov.onAdd = function () {
198      me.init_(map, opt_zoomOpts);
199    };
200    ov.draw = function () {
201    };
202    ov.onRemove = function () {
203    };
204    ov.setMap(map);
205    this.prjov_ = ov;
206  }
207  /**
208   * Init the tool. 
209   * @param {google.maps.Map} map
210   * @param {KeyDragZoomOptions} opt_zoomOpts
211   */
212  DragZoom.prototype.init_ = function (map, opt_zoomOpts) {
213    this.map_ = map;
214    opt_zoomOpts = opt_zoomOpts || {};
215    this.key_ = opt_zoomOpts.key || 'shift';
216    this.key_ = this.key_.toLowerCase();
217    this.borderWidths_ = getBorderWidths(this.map_.getDiv());//Container());
218    this.paneDiv_ = document.createElement("div");
219    this.paneDiv_.onselectstart = function () {
220      return false;
221    };
222    // default style
223    setVals(this.paneDiv_.style, {
224      backgroundColor: 'white',
225      opacity: 0.0,
226      cursor: 'crosshair'
227    });
228    // allow overwrite 
229    setVals(this.paneDiv_.style, opt_zoomOpts.paneStyle);
230    // stuff that cannot be overwritten
231    setVals(this.paneDiv_.style, {
232      position: 'absolute',
233      overflow: 'hidden',
234      zIndex: 10001,
235      display: 'none'
236    });
237    if (this.key_ === 'shift') { // Workaround for Firefox Shift-Click problem
238      this.paneDiv_.style.MozUserSelect = "none";
239    }
240    setOpacity(this.paneDiv_);
241    // An IE fix: if the background is transparent, it cannot capture mousedown events
242    if (this.paneDiv_.style.backgroundColor === 'transparent') {
243      this.paneDiv_.style.backgroundColor = 'white';
244      setOpacity(this.paneDiv_, 0);
245    }
246    this.map_.getDiv().appendChild(this.paneDiv_);//Container()
247    this.boxDiv_ = document.createElement('div');
248    setVals(this.boxDiv_.style, {
249      border: 'thin solid #FF0000'
250    });
251    setVals(this.boxDiv_.style, opt_zoomOpts.boxStyle);
252    setVals(this.boxDiv_.style, {
253      position: 'absolute',
254      display: 'none'
255    });
256    setOpacity(this.boxDiv_);
257    this.map_.getDiv().appendChild(this.boxDiv_);
258    this.boxBorderWidths_ = getBorderWidths(this.boxDiv_);
259    var me = this;
260    this.keyDownListener_ = google.maps.event.addDomListener(document, 'keydown',  function (e) {
261      me.onKeyDown_(e);
262    });
263    this.keyUpListener_ = google.maps.event.addDomListener(document, 'keyup', function (e) {
264      me.onKeyUp_(e);
265    }); 
266    this.mouseDownListener_ = google.maps.event.addDomListener(this.paneDiv_, 'mousedown', function (e) {
267      me.onMouseDown_(e);
268    });
269    this.mouseDownListenerDocument_ = google.maps.event.addDomListener(document, 'mousedown', function (e) {
270      me.onMouseDownDocument_(e);
271    });
272    this.mouseMoveListener_ = google.maps.event.addDomListener(document, 'mousemove', function (e) {
273      me.onMouseMove_(e);
274    });
275    this.mouseUpListener_ = google.maps.event.addDomListener(document, 'mouseup', function (e) {
276      me.onMouseUp_(e); 
277    });
278  
279    this.hotKeyDown_ = false;
280    this.dragging_ = false;
281    this.startPt_ = null;
282    this.endPt_ = null;
283    this.boxMaxX_ = null;
284    this.boxMaxY_ = null;
285    this.mousePosn_ = null;
286    this.mapPosn_ = getElementPosition(this.map_.getDiv());
287    this.mouseDown_ = false;
288  };
289 
290  /**
291   * Returns true if the hot key is being pressed when an event occurs.
292   * @param {Event} e
293   * @return {Boolean}
294   */
295  DragZoom.prototype.isHotKeyDown_ = function (e) {
296    var isHot;
297    e = e || window.event;
298    isHot = (e.shiftKey && this.key_ === 'shift') || (e.altKey && this.key_ === 'alt') || (e.ctrlKey && this.key_ === 'ctrl');
299    if (!isHot) {
300      // Need to look at keyCode for Opera because it
301      // doesn't set the shiftKey, altKey, ctrlKey properties
302      // unless a non-modifier event is being reported.
303      //
304      // See http://cross-browser.com/x/examples/shift_mode.php
305      // Also see http://unixpapa.com/js/key.html
306      switch (e.keyCode) {
307      case 16:
308        if (this.key_ === 'shift') {
309          isHot = true;
310        }
311        break;
312      case 17:
313        if (this.key_ === 'ctrl') {
314          isHot = true;
315        }
316        break;
317      case 18:
318        if (this.key_ === 'alt') {
319          isHot = true;
320        }
321        break;
322      }
323    }
324    return isHot;
325  };
326  
327  /**
328   * Checks if the mouse is on top of the map. The position is captured 
329   * in onMouseMove_.
330   * @return true if mouse is on top of the map div.
331   */
332  DragZoom.prototype.isMouseOnMap_ = function () {
333    var mousePos = this.mousePosn_;
334    if (mousePos) {
335      var mapPos = this.mapPosn_;
336      var mapDiv = this.map_.getDiv();
337      return mousePos.left > mapPos.left && mousePos.left < mapPos.left + mapDiv.offsetWidth &&
338      mousePos.top > mapPos.top && mousePos.top < mapPos.top + mapDiv.offsetHeight;
339    } else {
340      // if user never moved mouse
341      return false;
342    }
343  };
344  
345  /**
346   * Show or hide the overlay pane, depending on whether the mouse is over the map.
347   */
348  DragZoom.prototype.setPaneVisibility_ = function () {
349    if (this.map_ && this.hotKeyDown_ && this.isMouseOnMap_()) {
350      var mapDiv = this.map_.getDiv();
351      this.paneDiv_.style.left = 0 + 'px';
352      this.paneDiv_.style.top = 0 + 'px';
353      this.paneDiv_.style.width = mapDiv.offsetWidth - (this.borderWidths_.left + this.borderWidths_.right) + 'px';
354      this.paneDiv_.style.height = mapDiv.offsetHeight - (this.borderWidths_.top + this.borderWidths_.bottom) + 'px';
355      this.paneDiv_.style.display = 'block';
356      this.boxMaxX_ = parseInt(this.paneDiv_.style.width, 10) - (this.boxBorderWidths_.left + this.boxBorderWidths_.right);
357      this.boxMaxY_ = parseInt(this.paneDiv_.style.height, 10) - (this.boxBorderWidths_.top + this.boxBorderWidths_.bottom);
358    } else {
359      this.paneDiv_.style.display = 'none';
360    }
361  };
362  /**
363   * Handle key down. Activate the tool only if the mouse is on top of the map.
364   * @param {Event} e
365   */
366  DragZoom.prototype.onKeyDown_ = function (e) {
367    var me = this;
368    if (this.map_ && !this.hotKeyDown_ && this.isHotKeyDown_(e)) {
369      me.hotKeyDown_ = true;
370      me.setPaneVisibility_();
371     /**
372       * This event is fired when the hot key is pressed. 
373       * @name DragZoom#activate
374       * @event
375       */
376      google.maps.event.trigger(me, 'activate');
377    }
378  };
379  /**
380   * Get the <code>google.maps.Point</code> of the mouse position.
381   * @param {Object} e
382   * @return {google.maps.Point} point
383   * @private
384   */
385  DragZoom.prototype.getMousePoint_ = function (e) {
386    var mousePosn = getMousePosition(e);
387    var p = new google.maps.Point();
388    p.x = mousePosn.left - this.mapPosn_.left - this.borderWidths_.left;
389    p.y = mousePosn.top - this.mapPosn_.top - this.borderWidths_.top;
390    p.x = Math.min(p.x, this.boxMaxX_);
391    p.y = Math.min(p.y, this.boxMaxY_);
392    p.x = Math.max(p.x, 0);
393    p.y = Math.max(p.y, 0);
394    return p;
395  };
396  /**
397   * Handle mouse down.
398   * @param {Event} e
399   */
400  DragZoom.prototype.onMouseDown_ = function (e) {
401    if (this.map_ && this.hotKeyDown_) {
402      this.mapPosn_ = getElementPosition(this.map_.getDiv());
403      this.dragging_ = true;
404      this.startPt_ = this.endPt_ = this.getMousePoint_(e);
405      var prj = this.prjov_.getProjection();
406      var latlng = prj.fromDivPixelToLatLng(this.startPt_);
407      /**
408       * This event is fired when the drag operation begins. 
409       * @name DragZoom#dragstart
410       * @param {GLatLng} startLatLng
411       * @event
412       */
413      google.maps.event.trigger(this, 'dragstart', latlng);
414    }
415  };
416  /**
417   * Handle mouse down at the document level.
418   * @param {Event} e
419   */
420  DragZoom.prototype.onMouseDownDocument_ = function (e) {
421    this.mouseDown_ = true;
422  };
423  /**
424   * Handle mouse move.
425   * @param {Event} e
426   */
427  DragZoom.prototype.onMouseMove_ = function (e) {
428    this.mousePosn_ = getMousePosition(e);
429    if (this.dragging_) {
430      this.endPt_ = this.getMousePoint_(e);
431      var left = Math.min(this.startPt_.x, this.endPt_.x);
432      var top = Math.min(this.startPt_.y, this.endPt_.y);
433      var width = Math.abs(this.startPt_.x - this.endPt_.x);
434      var height = Math.abs(this.startPt_.y - this.endPt_.y);
435      this.boxDiv_.style.left = left + 'px';
436      this.boxDiv_.style.top = top + 'px';
437      this.boxDiv_.style.width = width + 'px';
438      this.boxDiv_.style.height = height + 'px';
439      this.boxDiv_.style.display = 'block';
440      /**
441       * This event is repeatedly fired while the user drags the box. The southwest and northeast
442       * point are passed as parameters of type <code>google.maps.Point</code> (for performance reasons),
443       * relative to the map container. Note: the event listener is responsible 
444       * for converting Pixel to LatLng, if necessary.
445       * @name DragZoom#drag 
446       * @param {google.maps.Point} southwestPixel
447       * @param {google.maps.Point} northeastPixel
448       * @event
449       */
450      google.maps.event.trigger(this, 'drag', new google.maps.Point(left, top + height), new google.maps.Point(left + width, top)); 
451    } else if (!this.mouseDown_) {
452      this.setPaneVisibility_();
453    }
454  };
455  /**
456   * Handle mouse up.
457   * @param {Event} e
458   */
459  DragZoom.prototype.onMouseUp_ = function (e) {
460    this.mouseDown_ = false;
461    if (this.dragging_) {
462      var left = Math.min(this.startPt_.x, this.endPt_.x);
463      var top = Math.min(this.startPt_.y, this.endPt_.y);
464      var width = Math.abs(this.startPt_.x - this.endPt_.x);
465      var height = Math.abs(this.startPt_.y - this.endPt_.y);
466      var prj = this.prjov_.getProjection();
467      // 2009-05-29: since V3 does not have fromContainerPixel, 
468      //needs find offset here
469      var containerPos = getElementPosition(this.map_.getDiv());
470      var mapPanePos = getElementPosition(this.prjov_.getPanes().mapPane);
471      left = left + (containerPos.left - mapPanePos.left);
472      top = top + (containerPos.top - mapPanePos.top);
473      var sw = prj.fromDivPixelToLatLng(new google.maps.Point(left, top + height));
474      var ne = prj.fromDivPixelToLatLng(new google.maps.Point(left + width, top));
475      var bnds = new google.maps.LatLngBounds(sw, ne);
476      this.map_.fitBounds(bnds);
477      this.dragging_ = false;
478      this.boxDiv_.style.display = 'none';
479      /**
480       * This event is fired when the drag operation ends. 
481       * Note that the event is not fired if the hot key is released before the drag operation ends.
482       * @name DragZoom#dragend
483       * @param {GLatLngBounds} newBounds
484       * @event
485       */
486      google.maps.event.trigger(this, 'dragend', bnds);
487    }
488  };
489 
490  /**
491   * Handle key up.
492   * @param {Event} e
493   */
494  DragZoom.prototype.onKeyUp_ = function (e) {
495    if (this.map_ && this.hotKeyDown_) {
496      this.hotKeyDown_ = false;
497      this.dragging_ = false;
498      this.boxDiv_.style.display = 'none';
499      this.paneDiv_.style.display = "none";
500      /**
501       * This event is fired while the user release the key
502       * @name DragZoom#deactivate 
503       * @event
504       */
505      google.maps.event.trigger(this, 'deactivate'); 
506    }
507  };
508  
509  
510
511            
512  /**
513   * @name google.maps.Map
514   * @class These are new methods added to the Google Maps API's
515   * <a href  = 'http://code.google.com/apis/maps/documentation/v3/reference.html#Map'>Map</a>
516   * class.
517   */
518  /**
519   * Enable drag zoom. The user can zoom to an area of interest by holding down the hot key
520   * <code>(shift | ctrl | alt )</code> while dragging a box around the area. 
521   * @param {KeyDragZoomOptions} opt_zoomOpts
522   */
523  
524  google.maps.Map.prototype.enableKeyDragZoom = function (opt_zoomOpts) {
525    this.dragZoom_ = new DragZoom(this, opt_zoomOpts);
526  };
527  /**
528   * Disable drag zoom.
529   */
530  google.maps.Map.prototype.disableKeyDragZoom = function () {
531    var d = this.dragZoom_;
532    if (d) {
533      google.maps.event.removeListener(d.mouseDownListener_);
534      google.maps.event.removeListener(d.mouseDownListenerDocument_);
535      google.maps.event.removeListener(d.mouseMoveListener_);
536      google.maps.event.removeListener(d.mouseUpListener_);
537      google.maps.event.removeListener(d.keyUpListener_);
538      google.maps.event.removeListener(d.keyDownListener_);
539      this.getDiv().removeChild(d.boxDiv_);
540      this.getDiv().removeChild(d.paneDiv_);
541      this.dragZoom_ = null;
542    }
543  };
544  /**
545   * Returns true if the drag zoom feature has been enabled.
546   * @return {Boolean}
547   */
548  google.maps.Map.prototype.keyDragZoomEnabled = function () {
549    return this.dragZoom_ !== null;
550  };
551  /**
552   * Returns the DragZoom object which is created when <code>google.maps.Map.enableKeyDragZoom</code> is called.
553   * With this object you can use <code>google.maps.event.addListener</code> to attach event listeners
554   * for the 'activate', 'deactivate', 'dragstart', 'drag', and 'dragend' events.
555   * @return {DragZoom}
556   */
557  google.maps.Map.prototype.getDragZoomObject = function () {
558    return this.dragZoom_;
559  };
560})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.