PageSourceSearch

https://brigantesnation.com/wp-content/plugins/wp-google-maps/lib/…?ver=477085c70cc8903e613105dc79b46424

js brigantesnation.com collected 2026-10-02 02:55:07 UTC 18,886 bytes, 601 lines download raw bytes

1/**
2 * Copyright 2012 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17/**
18 * @fileoverview Extends OverlayView to provide a canvas "Layer".
19 * @author Brendan Kenny
20 */
21
22/**
23 * Modification Notice 
24 * Author: WP Go Maps Development Team (CodeCabin)
25 * Date: 2024-03-13
26 * 
27 * Details:
28 * We have altered the way the canvas extension happens, allowing it to be delayed in the event that the Google Maps API is loaded in async mode
29 * this is done in order to account for the load delays when loading sub-modules from Google API's, which may cause some of this module
30 * to fail when loaded into the DOM
31 * 
32 * The solution, for the interim is to attempt the extension, and if google is not yet defined, delay this by 500ms
33 * before retrying the extension. The extension will be retried a total of 10 times at most, before it fails in it's entirety
34 * 
35 * No notice will be provided in this case, but a flag will be set on the CanvasLayer definition itself
36 */
37
38/**
39 * A map layer that provides a canvas over the slippy map and a callback
40 * system for efficient animation. Requires canvas and CSS 2D transform
41 * support.
42 * @constructor
43 * @extends google.maps.OverlayView
44 * @param {CanvasLayerOptions=} opt_options Options to set in this CanvasLayer.
45 */
46function CanvasLayer(opt_options) {
47  /**
48   * If true, canvas is in a map pane and the OverlayView is fully functional.
49   * See google.maps.OverlayView.onAdd for more information.
50   * @type {boolean}
51   * @private
52   */
53  this.isAdded_ = false;
54
55  /**
56   * If true, each update will immediately schedule the next.
57   * @type {boolean}
58   * @private
59   */
60  this.isAnimated_ = false;
61
62  /**
63   * The name of the MapPane in which this layer will be displayed.
64   * @type {string}
65   * @private
66   */
67  this.paneName_ = CanvasLayer.DEFAULT_PANE_NAME_;
68
69  /**
70   * A user-supplied function called whenever an update is required. Null or
71   * undefined if a callback is not provided.
72   * @type {?function=}
73   * @private
74   */
75  this.updateHandler_ = null;
76
77  /**
78   * A user-supplied function called whenever an update is required and the
79   * map has been resized since the last update. Null or undefined if a
80   * callback is not provided.
81   * @type {?function}
82   * @private
83   */
84  this.resizeHandler_ = null;
85
86  /**
87   * The LatLng coordinate of the top left of the current view of the map. Will
88   * be null when this.isAdded_ is false.
89   * @type {google.maps.LatLng}
90   * @private
91   */
92  this.topLeft_ = null;
93
94  /**
95   * The map-pan event listener. Will be null when this.isAdded_ is false. Will
96   * be null when this.isAdded_ is false.
97   * @type {?function}
98   * @private
99   */
100  this.centerListener_ = null;
101
102  /**
103   * The map-resize event listener. Will be null when this.isAdded_ is false.
104   * @type {?function}
105   * @private
106   */
107  this.resizeListener_ = null;
108
109  /**
110   * If true, the map size has changed and this.resizeHandler_ must be called
111   * on the next update.
112   * @type {boolean}
113   * @private
114   */
115  this.needsResize_ = true;
116
117  /**
118   * A browser-defined id for the currently requested callback. Null when no
119   * callback is queued.
120   * @type {?number}
121   * @private
122   */
123  this.requestAnimationFrameId_ = null;
124
125  var canvas = document.createElement('canvas');
126  canvas.style.position = 'absolute';
127  canvas.style.top = 0;
128  canvas.style.left = 0;
129  canvas.style.pointerEvents = 'none';
130
131  /**
132   * The canvas element.
133   * @type {!HTMLCanvasElement}
134   */
135  this.canvas = canvas;
136
137  /**
138   * The CSS width of the canvas, which may be different than the width of the
139   * backing store.
140   * @private {number}
141   */
142  this.canvasCssWidth_ = 300;
143
144  /**
145   * The CSS height of the canvas, which may be different than the height of
146   * the backing store.
147   * @private {number}
148   */
149  this.canvasCssHeight_ = 150;
150
151  /**
152   * A value for scaling the CanvasLayer resolution relative to the CanvasLayer
153   * display size.
154   * @private {number}
155   */
156  this.resolutionScale_ = 1;
157
158  /**
159   * Simple bind for functions with no args for bind-less browsers (Safari).
160   * @param {Object} thisArg The this value used for the target function.
161   * @param {function} func The function to be bound.
162   */
163  function simpleBindShim(thisArg, func) {
164    return function() { func.apply(thisArg); };
165  }
166
167  /**
168   * A reference to this.repositionCanvas_ with this bound as its this value.
169   * @type {function}
170   * @private
171   */
172  this.repositionFunction_ = simpleBindShim(this, this.repositionCanvas_);
173
174  /**
175   * A reference to this.resize_ with this bound as its this value.
176   * @type {function}
177   * @private
178   */
179  this.resizeFunction_ = simpleBindShim(this, this.resize_);
180
181  /**
182   * A reference to this.update_ with this bound as its this value.
183   * @type {function}
184   * @private
185   */
186  this.requestUpdateFunction_ = simpleBindShim(this, this.update_);
187
188  // set provided options, if any
189  if (opt_options) {
190    this.setOptions(opt_options);
191  }
192}
193
194/**
195 * A very simple way to track the extension status
196 */
197CanvasLayer.__EXTENSION_STATUS = {
198  attempts : 0,
199  max : 10,
200  delay : 500,
201  extended : false
202};
203
204/**
205 * A somewhat recursive prototype extension module developed to allow async loading within the Google Maps API
206 * 
207 * Since the original module was written some technical specifications for the Google Maps platform have changed,
208 * so by accounting for this in an admittedly rudimentary way, we can allow async loading, without changing the surround code loading order  
209*/
210function __canvasLayerPrototypeExtension(){
211  CanvasLayer.__EXTENSION_STATUS.attempts += 1;
212
213  if(typeof window.google !== 'undefined' && typeof window.google.maps !== 'undefined' && typeof window.google.maps.OverlayView !== 'undefined'){
214    /* Perform the extension, this code is unchanged from the original, and simply moved into this callable */
215    CanvasLayer.__EXTENSION_STATUS.extended = true;
216
217    if(window.google)
218      CanvasLayer.prototype = new google.maps.OverlayView();
219
220    /**
221     * The default MapPane to contain the canvas.
222     * @type {string}
223     * @const
224     * @private
225     */
226    CanvasLayer.DEFAULT_PANE_NAME_ = 'overlayLayer';
227
228    /**
229     * Transform CSS property name, with vendor prefix if required. If browser
230     * does not support transforms, property will be ignored.
231     * @type {string}
232     * @const
233     * @private
234     */
235    CanvasLayer.CSS_TRANSFORM_ = (function() {
236      var div = document.createElement('div');
237      var transformProps = [
238        'transform',
239        'WebkitTransform',
240        'MozTransform',
241        'OTransform',
242        'msTransform'
243      ];
244      for (var i = 0; i < transformProps.length; i++) {
245        var prop = transformProps[i];
246        if (div.style[prop] !== undefined) {
247          return prop;
248        }
249      }
250
251      // return unprefixed version by default
252      return transformProps[0];
253    })();
254
255    /**
256     * The requestAnimationFrame function, with vendor-prefixed or setTimeout-based
257     * fallbacks. MUST be called with window as thisArg.
258     * @type {function}
259     * @param {function} callback The function to add to the frame request queue.
260     * @return {number} The browser-defined id for the requested callback.
261     * @private
262     */
263    CanvasLayer.prototype.requestAnimFrame_ =
264        window.requestAnimationFrame ||
265        window.webkitRequestAnimationFrame ||
266        window.mozRequestAnimationFrame ||
267        window.oRequestAnimationFrame ||
268        window.msRequestAnimationFrame ||
269        function(callback) {
270          return window.setTimeout(callback, 1000 / 60);
271        };
272
273    /**
274     * The cancelAnimationFrame function, with vendor-prefixed fallback. Does not
275     * fall back to clearTimeout as some platforms implement requestAnimationFrame
276     * but not cancelAnimationFrame, and the cost is an extra frame on onRemove.
277     * MUST be called with window as thisArg.
278     * @type {function}
279     * @param {number=} requestId The id of the frame request to cancel.
280     * @private
281     */
282    CanvasLayer.prototype.cancelAnimFrame_ =
283        window.cancelAnimationFrame ||
284        window.webkitCancelAnimationFrame ||
285        window.mozCancelAnimationFrame ||
286        window.oCancelAnimationFrame ||
287        window.msCancelAnimationFrame ||
288        function(requestId) {};
289
290    /**
291     * Sets any options provided. See CanvasLayerOptions for more information.
292     * @param {CanvasLayerOptions} options The options to set.
293     */
294    CanvasLayer.prototype.setOptions = function(options) {
295      if (options.animate !== undefined) {
296        this.setAnimate(options.animate);
297      }
298
299      if (options.paneName !== undefined) {
300        this.setPaneName(options.paneName);
301      }
302
303      if (options.updateHandler !== undefined) {
304        this.setUpdateHandler(options.updateHandler);
305      }
306
307      if (options.resizeHandler !== undefined) {
308        this.setResizeHandler(options.resizeHandler);
309      }
310
311      if (options.resolutionScale !== undefined) {
312        this.setResolutionScale(options.resolutionScale);
313      }
314
315      if (options.map !== undefined) {
316        this.setMap(options.map);
317      }
318    };
319
320    /**
321     * Set the animated state of the layer. If true, updateHandler will be called
322     * repeatedly, once per frame. If false, updateHandler will only be called when
323     * a map property changes that could require the canvas content to be redrawn.
324     * @param {boolean} animate Whether the canvas is animated.
325     */
326    CanvasLayer.prototype.setAnimate = function(animate) {
327      this.isAnimated_ = !!animate;
328
329      if (this.isAnimated_) {
330        this.scheduleUpdate();
331      }
332    };
333
334    /**
335     * @return {boolean} Whether the canvas is animated.
336     */
337    CanvasLayer.prototype.isAnimated = function() {
338      return this.isAnimated_;
339    };
340
341    /**
342     * Set the MapPane in which this layer will be displayed, by name. See
343     * {@code google.maps.MapPanes} for the panes available.
344     * @param {string} paneName The name of the desired MapPane.
345     */
346    CanvasLayer.prototype.setPaneName = function(paneName) {
347      this.paneName_ = paneName;
348
349      this.setPane_();
350    };
351
352    /**
353     * @return {string} The name of the current container pane.
354     */
355    CanvasLayer.prototype.getPaneName = function() {
356      return this.paneName_;
357    };
358
359    /**
360     * Adds the canvas to the specified container pane. Since this is guaranteed to
361     * execute only after onAdd is called, this is when paneName's existence is
362     * checked (and an error is thrown if it doesn't exist).
363     * @private
364     */
365    CanvasLayer.prototype.setPane_ = function() {
366      if (!this.isAdded_) {
367        return;
368      }
369
370      // onAdd has been called, so panes can be used
371      var panes = this.getPanes();
372      if (!panes[this.paneName_]) {
373        throw new Error('"' + this.paneName_ + '" is not a valid MapPane name.');
374      }
375
376      panes[this.paneName_].appendChild(this.canvas);
377    };
378
379    /**
380     * Set a function that will be called whenever the parent map and the overlay's
381     * canvas have been resized. If opt_resizeHandler is null or unspecified, any
382     * existing callback is removed.
383     * @param {?function=} opt_resizeHandler The resize callback function.
384     */
385    CanvasLayer.prototype.setResizeHandler = function(opt_resizeHandler) {
386      this.resizeHandler_ = opt_resizeHandler;
387    };
388
389    /**
390     * Sets a value for scaling the canvas resolution relative to the canvas
391     * display size. This can be used to save computation by scaling the backing
392     * buffer down, or to support high DPI devices by scaling it up (by e.g.
393     * window.devicePixelRatio).
394     * @param {number} scale
395     */
396    CanvasLayer.prototype.setResolutionScale = function(scale) {
397      if (typeof scale === 'number') {
398        this.resolutionScale_ = scale;
399        this.resize_();
400      }
401    };
402
403    /**
404     * Set a function that will be called when a repaint of the canvas is required.
405     * If opt_updateHandler is null or unspecified, any existing callback is
406     * removed.
407     * @param {?function=} opt_updateHandler The update callback function.
408     */
409    CanvasLayer.prototype.setUpdateHandler = function(opt_updateHandler) {
410      this.updateHandler_ = opt_updateHandler;
411    };
412
413    /**
414     * @inheritDoc
415     */
416    CanvasLayer.prototype.onAdd = function() {
417      if (this.isAdded_) {
418        return;
419      }
420
421      this.isAdded_ = true;
422      this.setPane_();
423
424      this.resizeListener_ = google.maps.event.addListener(this.getMap(),
425          'resize', this.resizeFunction_);
426      this.centerListener_ = google.maps.event.addListener(this.getMap(),
427          'center_changed', this.repositionFunction_);
428
429      this.resize_();
430      this.repositionCanvas_();
431    };
432
433    /**
434     * @inheritDoc
435     */
436    CanvasLayer.prototype.onRemove = function() {
437      if (!this.isAdded_) {
438        return;
439      }
440
441      this.isAdded_ = false;
442      this.topLeft_ = null;
443
444      // remove canvas and listeners for pan and resize from map
445      this.canvas.parentElement.removeChild(this.canvas);
446      if (this.centerListener_) {
447        google.maps.event.removeListener(this.centerListener_);
448        this.centerListener_ = null;
449      }
450      if (this.resizeListener_) {
451        google.maps.event.removeListener(this.resizeListener_);
452        this.resizeListener_ = null;
453      }
454
455      // cease canvas update callbacks
456      if (this.requestAnimationFrameId_) {
457        this.cancelAnimFrame_.call(window, this.requestAnimationFrameId_);
458        this.requestAnimationFrameId_ = null;
459      }
460    };
461
462    /**
463     * The internal callback for resize events that resizes the canvas to keep the
464     * map properly covered.
465     * @private
466     */
467    CanvasLayer.prototype.resize_ = function() {
468      if (!this.isAdded_) {
469        return;
470      }
471
472      var map = this.getMap();
473      var mapWidth = map.getDiv().getElementsByTagName('div')[0].offsetWidth;
474      var mapHeight = map.getDiv().getElementsByTagName('div')[0].offsetHeight;
475
476      var newWidth = mapWidth * this.resolutionScale_;
477      var newHeight = mapHeight * this.resolutionScale_;
478      var oldWidth = this.canvas.width;
479      var oldHeight = this.canvas.height;
480
481      // resizing may allocate a new back buffer, so do so conservatively
482      if (oldWidth !== newWidth || oldHeight !== newHeight) {
483        this.canvas.width = newWidth;
484        this.canvas.height = newHeight;
485
486        this.needsResize_ = true;
487        this.scheduleUpdate();
488      }
489
490      // reset styling if new sizes don't match; resize of data not needed
491      if (this.canvasCssWidth_ !== mapWidth ||
492          this.canvasCssHeight_ !== mapHeight) {
493        this.canvasCssWidth_ = mapWidth;
494        this.canvasCssHeight_ = mapHeight;
495        this.canvas.style.width = mapWidth + 'px';
496        this.canvas.style.height = mapHeight + 'px';
497      }
498    };
499
500    /**
501     * @inheritDoc
502     */
503    CanvasLayer.prototype.draw = function() {
504      this.repositionCanvas_();
505    };
506
507    /**
508     * Internal callback for map view changes. Since the Maps API moves the overlay
509     * along with the map, this function calculates the opposite translation to
510     * keep the canvas in place.
511     * @private
512     */
513    CanvasLayer.prototype.repositionCanvas_ = function() {
514      // TODO(bckenny): *should* only be executed on RAF, but in current browsers
515      //     this causes noticeable hitches in map and overlay relative
516      //     positioning.
517
518      var map = this.getMap();
519
520      // topLeft can't be calculated from map.getBounds(), because bounds are
521      // clamped to -180 and 180 when completely zoomed out. Instead, calculate
522      // left as an offset from the center, which is an unwrapped LatLng.
523      var top = map.getBounds().getNorthEast().lat();
524      var center = map.getCenter();
525      var scale = Math.pow(2, map.getZoom());
526      var left = center.lng() - (this.canvasCssWidth_ * 180) / (256 * scale);
527      this.topLeft_ = new google.maps.LatLng(top, left);
528
529      // Canvas position relative to draggable map's container depends on
530      // overlayView's projection, not the map's. Have to use the center of the
531      // map for this, not the top left, for the same reason as above.
532      var projection = this.getProjection();
533      var divCenter = projection.fromLatLngToDivPixel(center);
534      var offsetX = -Math.round(this.canvasCssWidth_ / 2 - divCenter.x);
535      var offsetY = -Math.round(this.canvasCssHeight_ / 2 - divCenter.y);
536      this.canvas.style[CanvasLayer.CSS_TRANSFORM_] = 'translate(' +
537          offsetX + 'px,' + offsetY + 'px)';
538
539      this.scheduleUpdate();
540    };
541
542    /**
543     * Internal callback that serves as main animation scheduler via
544     * requestAnimationFrame. Calls resize and update callbacks if set, and
545     * schedules the next frame if overlay is animated.
546     * @private
547     */
548    CanvasLayer.prototype.update_ = function() {
549      this.requestAnimationFrameId_ = null;
550
551      if (!this.isAdded_) {
552        return;
553      }
554
555      if (this.isAnimated_) {
556        this.scheduleUpdate();
557      }
558
559      if (this.needsResize_ && this.resizeHandler_) {
560        this.needsResize_ = false;
561        this.resizeHandler_();
562      }
563
564      if (this.updateHandler_) {
565        this.updateHandler_();
566      }
567    };
568
569    /**
570     * A convenience method to get the current LatLng coordinate of the top left of
571     * the current view of the map.
572     * @return {google.maps.LatLng} The top left coordinate.
573     */
574    CanvasLayer.prototype.getTopLeft = function() {
575      return this.topLeft_;
576    };
577
578    /**
579     * Schedule a requestAnimationFrame callback to updateHandler. If one is
580     * already scheduled, there is no effect.
581     */
582    CanvasLayer.prototype.scheduleUpdate = function() {
583      if (this.isAdded_ && !this.requestAnimationFrameId_) {
584        this.requestAnimationFrameId_ =
585            this.requestAnimFrame_.call(window, this.requestUpdateFunction_);
586      }
587    };
588
589  } else {
590    /* Queue this for 500ms from now to allow us to retry until we get it loaded */
591    if(CanvasLayer.__EXTENSION_STATUS.attempts < CanvasLayer.__EXTENSION_STATUS.max){
592      setTimeout(() => {
593        __canvasLayerPrototypeExtension();
594      }, CanvasLayer.__EXTENSION_STATUS.delay);
595    }
596  }
597}
598
599// Start the loader
600__canvasLayerPrototypeExtension();
601

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.