PageSourceSearch

https://www.bgcgh.ca/wp-content/plugins/wp-google-maps/js/v8/open-layers/ol-map.js?ver=10.0.09+pro-10.0.07

js bgcgh.ca collected 2026-10-06 18:40:53 UTC 27,448 bytes, 1,018 lines download raw bytes

1/**
2 * @namespace WPGMZA
3 * @module OLMap
4 * @requires WPGMZA.Map
5 * @pro-requires WPGMZA.ProMap
6 */
7jQuery(function($) {
8	
9	var Parent;
10	
11	WPGMZA.OLMap = function(element, options)
12	{
13		var self = this;
14		
15		Parent.call(this, element);
16		
17		this.setOptions(options);
18		
19		var viewOptions = this.settings.toOLViewOptions();
20		
21		this.mapType = viewOptions.mapType ? viewOptions.mapType : 'roadmap';
22		this.tileLayers = this.getTileLayers();
23
24		$(this.element).html("");
25
26		viewOptions = this.extendNativeConfig(viewOptions);
27
28		let mapOptions = {
29			target: $(element)[0],
30			layers: this.tileLayers,
31			view: this.getTileView(viewOptions)
32		};
33
34		if(!this.isLegacy()){
35			/* Has V10 OpenLayers */
36			const attributionOptions = { collapsible: true };
37			if(typeof WPGMZA.tileServer !== 'undefined' && WPGMZA.tileServer instanceof Object){
38				if(WPGMZA.tileServer.attribution && WPGMZA.tileServer.type === 'xyz'){
39					attributionOptions.attributions = WPGMZA.tileServer.attribution;
40				}
41			}
42			const attribution = new ol.control.Attribution(attributionOptions);
43			mapOptions.controls = ol.control.defaults.defaults({attribution: false}).extend([attribution]);
44		}
45		
46		
47		this.olMap = new ol.Map(mapOptions);
48
49		if(this.customTileMode){
50			/* The system is in custom tile view mode */
51			if(!(ol.extent.containsCoordinate(this.customTileModeExtent, this.olMap.getView().getCenter()))){
52				const view = this.olMap.getView();
53
54				view.setCenter(ol.extent.getCenter(this.customTileModeExtent));
55				this.wrapLongitude();
56				this.onBoundsChanged();
57			}
58		}
59		
60		// NB: Handles legacy checkboxes as well as new, standard controls
61		function isSettingDisabled(value)
62		{
63			if(value === "yes")
64				return true;
65			
66			return (value ? true : false);
67		}
68		
69		// TODO: Re-implement using correct setting names
70		// Interactions
71		this.olMap.getInteractions().forEach(function(interaction) {
72			
73			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
74			if(interaction instanceof ol.interaction.DragPan)
75				interaction.setActive(
76					!isSettingDisabled(self.settings.wpgmza_settings_map_draggable)
77				);
78			else if(interaction instanceof ol.interaction.DoubleClickZoom)
79				interaction.setActive(
80					!isSettingDisabled(self.settings.wpgmza_settings_map_clickzoom)
81				);
82			else if(interaction instanceof ol.interaction.MouseWheelZoom)
83				interaction.setActive(
84					!isSettingDisabled(self.settings.wpgmza_settings_map_scroll)
85				);
86			
87		}, this);
88		
89		// Cooperative gesture handling
90		if(!(this.settings.wpgmza_force_greedy_gestures == "greedy" || this.settings.wpgmza_force_greedy_gestures == "yes" || this.settings.wpgmza_force_greedy_gestures == true))
91		{
92			this.gestureOverlay = $("<div class='wpgmza-gesture-overlay'></div>")
93			this.gestureOverlayTimeoutID = null;
94			
95			if(WPGMZA.isTouchDevice())
96			{
97				// On touch devices, require two fingers to drag and pan
98				// NB: Temporarily removed due to inconsistent behaviour
99
100				// Reintroduced: 9.0.0 -> We have made some changes to improve consistency 
101				this.olMap.getInteractions().forEach(function(interaction) {
102					
103					if(interaction instanceof ol.interaction.DragPan)
104						self.olMap.removeInteraction(interaction);
105					
106				});
107				
108				this.olMap.addInteraction(new ol.interaction.DragPan({
109					
110					condition: function(olBrowserEvent) {
111						let allowed = false;
112						let originalEvent = olBrowserEvent.originalEvent; 
113						if(originalEvent instanceof PointerEvent){
114							/* Handle this as a pointer */
115							if(this.targetPointers && this.targetPointers.length){
116								allowed = this.targetPointers.length == 2;
117							}
118						} else if (originalEvent instanceof TouchEvent){
119							if(originalEvent.touches && originalEvent.touches.length){
120								allowed = originalEvent.touches.length == 2;
121							}
122						}
123						
124						if(!allowed)
125							self.showGestureOverlay();
126						
127						return allowed;
128					}
129					
130				}));
131				
132				this.gestureOverlay.text(WPGMZA.localized_strings.use_two_fingers);
133			}
134			else
135			{
136				// On desktops, require Ctrl + zoom to zoom, show an overlay if that condition is not met
137				this.olMap.on("wheel", function(event) {
138					
139					if(!ol.events.condition.platformModifierKeyOnly(event))
140					{
141						self.showGestureOverlay();
142
143						// Allow the page to scroll normally by commenting this out 
144						//event.originalEvent.preventDefault();
145						
146						return false;
147					}
148					
149				});
150				
151				let getstureString = WPGMZA.localized_strings.use_ctrl_scroll_to_zoom;
152				if(WPGMZA.isDeviceiOS()){
153					getstureString = WPGMZA.localized_strings.use_ctrl_scroll_to_zoom_ios;
154				}
155				
156				this.gestureOverlay.text(getstureString);
157			}
158		}
159		
160		// Controls
161		this.olMap.getControls().forEach(function(control) {
162			
163			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
164			if(control instanceof ol.control.Zoom && WPGMZA.settings.wpgmza_settings_map_zoom == true)
165				self.olMap.removeControl(control);
166			
167		}, this);
168		
169
170		/* Layer control */
171		const multiLayerConfig = this.settings.hasMutlilayerTileServer();
172		if(multiLayerConfig){
173			/* This map has more than one layer in it's tile server configuration */
174			if(!isSettingDisabled(WPGMZA.settings.wpgmza_settings_map_type)){
175				this.addMapTypeControl(multiLayerConfig, !isSettingDisabled(WPGMZA.settings.wpgmza_settings_map_full_screen_control));
176			}
177		}
178
179		if(!isSettingDisabled(WPGMZA.settings.wpgmza_settings_map_full_screen_control)){
180			this.olMap.addControl(new ol.control.FullScreen());
181		}
182
183		if(this.settings.enable_scale_control){
184			this.enableScaleControl(true);
185		}
186		
187		if(WPGMZA.OLMarker.renderMode == WPGMZA.OLMarker.RENDER_MODE_VECTOR_LAYER)
188		{
189			// Marker layer
190			this.markerLayer = new ol.layer.Vector({
191				source: new ol.source.Vector({
192					features: []
193				})
194			});
195			this.olMap.addLayer(this.markerLayer);
196			
197			this.olMap.on("click", function(event) {
198				var features = self.olMap.getFeaturesAtPixel(event.pixel);
199				
200				if(!features || !features.length)
201					return;
202				
203				var marker = features[0].wpgmzaMarker;
204					
205				if(!marker){
206					return;
207				}
208				
209				marker.trigger("click");
210				marker.trigger("select");
211			});
212		}
213		
214		// Listen for drag start
215		this.olMap.on("movestart", function(event) {
216			self.isBeingDragged = true;
217		});
218		
219		// Listen for end of pan so we can wrap longitude if needs be
220		this.olMap.on("moveend", function(event) {
221			self.wrapLongitude();
222			
223			self.isBeingDragged = false;
224			self.dispatchEvent("dragend");
225			self.onIdle();
226		});
227		
228		// Listen for zoom
229		this.olMap.getView().on("change:resolution", function(event) {
230			self.dispatchEvent("zoom_changed");
231			self.dispatchEvent("zoomchanged");
232			setTimeout(function() {
233				self.onIdle();
234			}, 10);
235		});
236		
237		// Listen for bounds changing
238		this.olMap.getView().on("change", function() {
239			// Wrap longitude
240			self.onBoundsChanged();
241		});
242		self.onBoundsChanged();
243		
244		// Hover interaction
245		this._mouseoverNativeFeatures = [];
246		
247		this.olMap.on("pointermove", function(event) {
248			
249			if(event.dragging)
250				return;
251			
252			try{
253				var featuresUnderPixel = event.target.getFeaturesAtPixel(event.pixel);
254			}catch(e) {
255				// NB: Hacktacular.. An error is thrown when you mouse over a heatmap. See https://github.com/openlayers/openlayers/issues/10100. This was allegedly solved and merged in but seems to still be present in OpenLayers 6.4.3.
256				return;
257			}
258			
259			if(!featuresUnderPixel)
260				featuresUnderPixel = [];
261			
262			var nativeFeaturesUnderPixel = [], i, props;
263			
264			for(i = 0; i < featuresUnderPixel.length; i++)
265			{
266				props = featuresUnderPixel[i].getProperties();
267				
268				if(!props.wpgmzaFeature)
269					continue;
270				
271				nativeFeature = props.wpgmzaFeature;
272				nativeFeaturesUnderPixel.push(nativeFeature);
273				
274				if(self._mouseoverNativeFeatures.indexOf(nativeFeature) == -1)
275				{
276					// Now hovering over this feature, when we weren't previously
277					nativeFeature.trigger("mouseover");
278					self._mouseoverNativeFeatures.push(nativeFeature);
279				}
280			}
281				
282			for(i = self._mouseoverNativeFeatures.length - 1; i >= 0; i--)
283			{
284				nativeFeature = self._mouseoverNativeFeatures[i];
285				
286				if(nativeFeaturesUnderPixel.indexOf(nativeFeature) == -1)
287				{
288					// No longer hovering over this feature, where we had been previously
289					nativeFeature.trigger("mouseout");
290					self._mouseoverNativeFeatures.splice(i, 1);
291				}
292			}
293			
294		});
295		
296		// Right click listener
297		$(this.element).on("click contextmenu", function(event) {
298			
299			var isRight;
300			event = event || window.event;
301
302			var latLng = self.pixelsToLatLng(event.offsetX, event.offsetY);
303			
304			if("which" in event)
305				isRight = event.which == 3;
306			else if("button" in event)
307				isRight = event.button == 2;
308			
309			if(event.which == 1 || event.button == 1){
310				if(self.isBeingDragged)
311					return;
312				
313				// Left click
314				if($(event.target).closest(".ol-marker").length)
315					return; // A marker was clicked, not the map. Do nothing
316
317				/*
318				 * User is clicking on the map, but looks like it was not a marker...
319				 * 
320				 * Finding a light at the end of the tunnel 
321				*/
322				try{
323					if(self.element){
324						const nestedCanvases = self.element.querySelectorAll('canvas');
325						if(nestedCanvases.length > 1){
326							const diff = (nestedCanvases[0].width  /  nestedCanvases[1].width);
327							event.offsetX *= diff;
328							event.offsetY *= diff;
329						}
330					}
331
332					var featuresUnderPixel = self.olMap.getFeaturesAtPixel([event.offsetX, event.offsetY]);
333				}catch(e) {
334					return;
335				}
336				
337				if(!featuresUnderPixel)
338					featuresUnderPixel = [];
339				
340				var nativeFeaturesUnderPixel = [], i, props;
341				for(i = 0; i < featuresUnderPixel.length; i++){
342					props = featuresUnderPixel[i].getProperties();
343					
344					if(!props.wpgmzaFeature)
345						continue;
346					
347					nativeFeature = props.wpgmzaFeature;
348					nativeFeaturesUnderPixel.push(nativeFeature);
349					let clickCoordinates = new WPGMZA.LatLng(latLng);
350					nativeFeature.trigger({type:"click", coordinates : clickCoordinates});
351				}
352
353				if(featuresUnderPixel.length > 0){
354					/*
355					 * This is for a pixel interpolated feature, like polygons
356					 *
357					 * Let's return early, to avoid double event firing
358					*/
359					return;
360				}
361
362				if(event.target instanceof HTMLCanvasElement){
363					/* Only trigger if this is the canvas element directly */
364					self.trigger({
365						type: "click",
366						latLng: latLng
367					});
368				}
369				
370				return;
371			}
372			
373			if(!isRight){
374				return;
375			}
376			
377			return self.onRightClick(event);
378		});
379
380		// Touch event support
381		$(this.element).on("touchstart", function (event) {
382            try{
383            	let offsetX;
384            	let offsetY;
385              	if(self.element){
386					const nestedCanvases = self.element.querySelectorAll('canvas');
387
388					const touch = event.originalEvent.changedTouches[0];
389					const targetElement = event.originalEvent.target;
390					const rect = targetElement.getBoundingClientRect();
391
392					offsetX = touch.clientX - rect.left;
393					offsetY = touch.clientY - rect.top;
394					
395					if(nestedCanvases.length > 1){
396						const diff = (nestedCanvases[0].width  /  nestedCanvases[1].width);
397						offsetX *= diff;
398						offsetY *= diff;
399					}
400              	}
401
402              	var featuresUnderPixel = self.olMap.getFeaturesAtPixel([offsetX, offsetY]);
403            }catch(e) {
404              return;
405            }
406            
407            if(!featuresUnderPixel){
408              	featuresUnderPixel = [];
409			}
410            
411            var nativeFeaturesUnderPixel = [], i, props;
412            for(i = 0; i < featuresUnderPixel.length; i++){
413              	props = featuresUnderPixel[i].getProperties();
414              
415              	if(!props.wpgmzaFeature){
416                	continue;
417				}
418              
419              	nativeFeature = props.wpgmzaFeature;
420              	nativeFeaturesUnderPixel.push(nativeFeature);
421              
422              	nativeFeature.trigger("click");
423            }
424		});
425
426
427		// Dispatch event
428		if(!WPGMZA.isProVersion())
429		{
430			this.trigger("init");
431			
432			this.dispatchEvent("created");
433			WPGMZA.events.dispatchEvent({type: "mapcreated", map: this});
434			
435			// Legacy event
436			$(this.element).trigger("wpgooglemaps_loaded");
437		}
438	}
439
440	if(WPGMZA.isProVersion())
441		Parent = WPGMZA.ProMap;
442	else
443		Parent = WPGMZA.Map;
444	
445	WPGMZA.OLMap.prototype = Object.create(Parent.prototype);
446	WPGMZA.OLMap.prototype.constructor = WPGMZA.OLMap;
447	
448	WPGMZA.OLMap.prototype.getTileLayers = function() {
449		let url = WPGMZA.settings.tile_server_url ? WPGMZA.settings.tile_server_url : "https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png";
450		const config = this.settings.configureTileServer(url, {
451			authentication : WPGMZA.settings.open_layers_api_key ? WPGMZA.settings.open_layers_api_key : false, 
452			map : this
453		});
454		
455		if(config && config.url){
456			if(config.type && config.type === 'vector' && typeof olms !== 'undefined'){
457				const layerGroup = new ol.layer.Group();
458				olms.apply(layerGroup, config.url);
459
460				return [layerGroup];
461			} else if(config.type && config.type === 'custom' && config.custom){
462				/* Custom mode */
463				const extent = [0, 0, config.custom.width, config.custom.height];
464		
465				const projection = new ol.proj.Projection({
466					code: 'custom-tile-map',
467					units: 'pixels',
468					extent: extent
469				});
470
471				return [new ol.layer.Image({
472					source: new ol.source.ImageStatic({
473						attributions: config.custom.attribution ? config.custom.attribution : '©',
474						url: config.url,
475						projection: projection,
476						imageExtent: extent,
477						imageSize: config.custom.dimensions ? config.custom.dimensions : null
478					})
479				})];
480			}
481
482			const layers = [];
483
484			if(config.dependencies){
485				for(let dependency of config.dependencies){
486					config.options.url = dependency.url;
487					layers.push(
488						new ol.layer.Tile({
489							source: new ol.source.OSM(config.options)
490						})
491					);
492				}
493			}
494
495			config.options.url = config.url;
496			layers.push(
497				new ol.layer.Tile({
498					source: new ol.source.OSM(config.options)
499				})
500			);
501
502			return layers;
503		}
504		
505		/* Fallback */
506		return [new ol.layer.Tile({
507			source: new ol.source.OSM({url : url})
508		})];
509	}
510
511	WPGMZA.OLMap.prototype.getTileView = function(viewOptions){
512		if(this.settings && this.settings.custom_tile_enabled){
513			if(this.settings.custom_tile_image_width && this.settings.custom_tile_image_height){
514				const width = parseInt(this.settings.custom_tile_image_width);
515				const height = parseInt(this.settings.custom_tile_image_height);
516				
517				if(this.settings.custom_tile_image){
518					const extent = [0, 0, width, height];
519		
520					const projection = new ol.proj.Projection({
521						code: 'custom-tile-map',
522						units: 'pixels',
523						extent: extent
524					});
525
526					viewOptions.projection = projection;
527
528					this.customTileModeExtent = extent;
529					this.customTileMode = true;
530				}
531			}
532		}
533		return new ol.View(viewOptions);
534	}
535	
536	WPGMZA.OLMap.prototype.wrapLongitude = function()
537	{
538		var transformed = ol.proj.transform(this.olMap.getView().getCenter(), "EPSG:3857", "EPSG:4326");
539		var center = {
540			lat: transformed[1],
541			lng: transformed[0]
542		};
543		
544		if(center.lng >= -180 && center.lng <= 180)
545			return;
546		
547		center.lng = center.lng - 360 * Math.floor(center.lng / 360);
548		
549		if(center.lng > 180)
550			center.lng -= 360;
551		
552		this.setCenter(center);
553	}
554	
555	WPGMZA.OLMap.prototype.getCenter = function()
556	{
557		var lonLat = ol.proj.toLonLat(
558			this.olMap.getView().getCenter()
559		);
560		return {
561			lat: lonLat[1],
562			lng: lonLat[0]
563		};
564	}
565	
566	WPGMZA.OLMap.prototype.setCenter = function(latLng)
567	{
568		var view = this.olMap.getView();
569		
570		WPGMZA.Map.prototype.setCenter.call(this, latLng);
571		
572		view.setCenter(ol.proj.fromLonLat([
573			latLng.lng,
574			latLng.lat
575		]));
576		
577		this.wrapLongitude();
578
579		this.onBoundsChanged();
580	}
581	
582	WPGMZA.OLMap.prototype.getBounds = function()
583	{
584		var bounds = this.olMap.getView().calculateExtent(this.olMap.getSize());
585		var nativeBounds = new WPGMZA.LatLngBounds();
586		
587		var topLeft = ol.proj.toLonLat([bounds[0], bounds[1]]);
588		var bottomRight = ol.proj.toLonLat([bounds[2], bounds[3]]);
589		
590		nativeBounds.north = topLeft[1];
591		nativeBounds.south = bottomRight[1];
592		
593		nativeBounds.west = topLeft[0];
594		nativeBounds.east = bottomRight[0];
595		
596		return nativeBounds;
597	}
598	
599	/**
600	 * Fit to given boundaries
601	 * @return void
602	 */
603	WPGMZA.OLMap.prototype.fitBounds = function(southWest, northEast)
604	{
605		if(southWest instanceof WPGMZA.LatLng)
606			southWest = {lat: southWest.lat, lng: southWest.lng};
607		if(northEast instanceof WPGMZA.LatLng)
608			northEast = {lat: northEast.lat, lng: northEast.lng};
609		else if(southWest instanceof WPGMZA.LatLngBounds)
610		{
611			var bounds = southWest;
612			
613			southWest = {
614				lat: bounds.south,
615				lng: bounds.west
616			};
617			
618			northEast = {
619				lat: bounds.north,
620				lng: bounds.east
621			};
622		}
623		
624		var view = this.olMap.getView();
625		
626		var extent = ol.extent.boundingExtent([
627			ol.proj.fromLonLat([
628				parseFloat(southWest.lng),
629				parseFloat(southWest.lat)
630			]),
631			ol.proj.fromLonLat([
632				parseFloat(northEast.lng),
633				parseFloat(northEast.lat)
634			])
635		]);
636		view.fit(extent, { size : this.olMap.getSize(), padding : [60, 60, 60, 60] });
637	}
638	
639	WPGMZA.OLMap.prototype.panTo = function(latLng, zoom)
640	{
641		var view = this.olMap.getView();
642		var options = {
643			center: ol.proj.fromLonLat([
644				parseFloat(latLng.lng),
645				parseFloat(latLng.lat),
646			]),
647			duration: 500
648		};
649		
650		if(arguments.length > 1)
651			options.zoom = parseInt(zoom);
652		
653		view.animate(options);
654	}
655	
656	WPGMZA.OLMap.prototype.getZoom = function()
657	{
658		return Math.round( this.olMap.getView().getZoom() );
659	}
660	
661	WPGMZA.OLMap.prototype.setZoom = function(value)
662	{
663		this.olMap.getView().setZoom(value);
664	}
665	
666	WPGMZA.OLMap.prototype.getMinZoom = function()
667	{
668		return this.olMap.getView().getMinZoom();
669	}
670	
671	WPGMZA.OLMap.prototype.setMinZoom = function(value)
672	{
673		this.olMap.getView().setMinZoom(value);
674	}
675	
676	WPGMZA.OLMap.prototype.getMaxZoom = function()
677	{
678		return this.olMap.getView().getMaxZoom();
679	}
680	
681	WPGMZA.OLMap.prototype.setMaxZoom = function(value)
682	{
683		this.olMap.getView().setMaxZoom(value);
684	}
685
686	WPGMZA.OLMap.prototype.setMapType = function(type){
687		if(this.mapType !== type){
688			this.mapType = type;
689
690			if(this.tileLayers){
691				for(let layer of this.tileLayers){
692					this.olMap.removeLayer(layer);
693				}
694			}
695
696			this.tileLayers = this.getTileLayers();
697			const reversedLayers = this.tileLayers.slice().reverse();
698			for(let layer of reversedLayers){
699				this.olMap.getLayers().insertAt(0, layer);
700			}
701
702			$(this.element).find('.ol-layer-button[data-map-type]').removeClass('selected');
703			$(this.element).find('.ol-layer-button[data-map-type="' + type + '"]').addClass('selected');
704		}	
705	}
706
707	WPGMZA.OLMap.prototype.getMapType = function(){
708		return this.mapType ? this.mapType : 'roadmap';
709	}
710	
711	WPGMZA.OLMap.prototype.setOptions = function(options)
712	{
713		Parent.prototype.setOptions.call(this, options);
714		
715		if(!this.olMap)
716			return;
717		
718		this.olMap.getView().setProperties( this.settings.toOLViewOptions() );
719	}
720	
721	/**
722	 * TODO: Consider moving all these functions to their respective classes, same on google map (DO IT!!! It's very misleading having them here)
723	 */
724	WPGMZA.OLMap.prototype.addMarker = function(marker)
725	{
726		if(WPGMZA.OLMarker.renderMode == WPGMZA.OLMarker.RENDER_MODE_HTML_ELEMENT){
727			this.olMap.addOverlay(marker.overlay);
728		} else {
729			if(!marker.featureInSource){
730				this.markerLayer.getSource().addFeature(marker.feature);
731				marker.featureInSource = true;
732			}
733		}
734		
735		Parent.prototype.addMarker.call(this, marker);
736	}
737	
738	WPGMZA.OLMap.prototype.removeMarker = function(marker)
739	{
740		if(WPGMZA.OLMarker.renderMode == WPGMZA.OLMarker.RENDER_MODE_HTML_ELEMENT)
741			this.olMap.removeOverlay(marker.overlay);
742		else
743		{
744			this.markerLayer.getSource().removeFeature(marker.feature);
745			marker.featureInSource = false;
746		}
747		
748		Parent.prototype.removeMarker.call(this, marker);
749	}
750	
751	WPGMZA.OLMap.prototype.addPolygon = function(polygon)
752	{
753		this.olMap.addLayer(polygon.layer);
754		
755		Parent.prototype.addPolygon.call(this, polygon);
756	}
757	
758	WPGMZA.OLMap.prototype.removePolygon = function(polygon)
759	{
760		this.olMap.removeLayer(polygon.layer);
761		
762		Parent.prototype.removePolygon.call(this, polygon);
763	}
764	
765	WPGMZA.OLMap.prototype.addPolyline = function(polyline)
766	{
767		this.olMap.addLayer(polyline.layer);
768		
769		Parent.prototype.addPolyline.call(this, polyline);
770	}
771	
772	WPGMZA.OLMap.prototype.removePolyline = function(polyline)
773	{
774		this.olMap.removeLayer(polyline.layer);
775		
776		Parent.prototype.removePolyline.call(this, polyline);
777	}
778	
779	WPGMZA.OLMap.prototype.addCircle = function(circle)
780	{
781		this.olMap.addLayer(circle.layer);
782		
783		Parent.prototype.addCircle.call(this, circle);
784	}
785	
786	WPGMZA.OLMap.prototype.removeCircle = function(circle)
787	{
788		this.olMap.removeLayer(circle.layer);
789		
790		Parent.prototype.removeCircle.call(this, circle);
791	}
792	
793	WPGMZA.OLMap.prototype.addRectangle = function(rectangle)
794	{
795		this.olMap.addLayer(rectangle.layer);
796		
797		Parent.prototype.addRectangle.call(this, rectangle);
798	}
799	
800	WPGMZA.OLMap.prototype.removeRectangle = function(rectangle)
801	{
802		this.olMap.removeLayer(rectangle.layer);
803		
804		Parent.prototype.removeRectangle.call(this, rectangle);
805	}
806	
807	WPGMZA.OLMap.prototype.pixelsToLatLng = function(x, y)
808	{
809		if(y == undefined)
810		{
811			if("x" in x && "y" in x)
812			{
813				y = x.y;
814				x = x.x;
815			}
816			else
817				console.warn("Y coordinate undefined in pixelsToLatLng (did you mean to pass 2 arguments?)");
818		}
819		
820		var coord = this.olMap.getCoordinateFromPixel([x, y]);
821		
822		if(!coord)
823			return {
824				x: null,
825				y: null
826			};
827		
828		var lonLat = ol.proj.toLonLat(coord);
829		return {
830			lat: lonLat[1],
831			lng: lonLat[0]
832		};
833	}
834	
835	WPGMZA.OLMap.prototype.latLngToPixels = function(latLng)
836	{
837		var coord = ol.proj.fromLonLat([latLng.lng, latLng.lat]);
838		var pixel = this.olMap.getPixelFromCoordinate(coord);
839		
840		if(!pixel)
841			return {
842				x: null,
843				y: null
844			};
845		
846		return {
847			x: pixel[0],
848			y: pixel[1]
849		};
850	}
851	
852	WPGMZA.OLMap.prototype.enableBicycleLayer = function(value)
853	{
854		if(value)
855		{
856			if(!this.bicycleLayer)
857				this.bicycleLayer = new ol.layer.Tile({
858					source: new ol.source.OSM({
859						url: "http://{a-c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"
860					})
861				});
862				
863			this.olMap.addLayer(this.bicycleLayer);
864		}
865		else
866		{
867			if(!this.bicycleLayer)
868				return;
869			
870			this.olMap.removeLayer(this.bicycleLayer);
871		}
872	}
873	
874	WPGMZA.OLMap.prototype.showGestureOverlay = function()
875	{
876		var self = this;
877		
878		clearTimeout(this.gestureOverlayTimeoutID);
879		
880		$(this.gestureOverlay).stop().animate({opacity: "100"});
881		$(this.element).append(this.gestureOverlay);
882		
883		$(this.gestureOverlay).css({
884			"line-height":	$(this.element).height() + "px",
885			"opacity":		"1.0"
886		});
887		$(this.gestureOverlay).show();
888		
889		this.gestureOverlayTimeoutID = setTimeout(function() {
890			self.gestureOverlay.fadeOut(2000);
891		}, 2000);
892	}
893	
894	WPGMZA.OLMap.prototype.onElementResized = function(event)
895	{
896		this.olMap.updateSize();
897	}
898
899	WPGMZA.OLMap.prototype.resetBounds = function() {
900		var latlng = new WPGMZA.LatLng(this.settings.map_start_lat, this.settings.map_start_lng);
901		this.panTo(latlng, this.settings.map_start_zoom);
902	}
903	
904	WPGMZA.OLMap.prototype.onRightClick = function(event)
905	{
906		if($(event.target).closest(".ol-marker, .wpgmza_modern_infowindow, .wpgmza-modern-store-locator").length)
907			return true;
908		
909		var parentOffset = $(this.element).offset();
910		var relX = event.pageX - parentOffset.left;
911		var relY = event.pageY - parentOffset.top;
912		var latLng = this.pixelsToLatLng(relX, relY);
913		
914		this.trigger({type: "rightclick", latLng: latLng});
915		
916		// Legacy event compatibility
917		$(this.element).trigger({type: "rightclick", latLng: latLng});
918		
919		// Prevent menu
920		event.preventDefault();
921		return false;
922	}
923
924	WPGMZA.OLMap.prototype.enableAllInteractions = function()
925	{	
926
927		this.olMap.getInteractions().forEach(function(interaction) {
928			
929			if(interaction instanceof ol.interaction.DragPan || interaction instanceof ol.interaction.DoubleClickZoom || interaction instanceof ol.interaction.MouseWheelZoom)
930			{
931				interaction.setActive(true);
932			}
933			
934		}, this);
935
936	}
937
938	WPGMZA.OLMap.prototype.addMapTypeControl = function(config, hasFullscreen){
939		if(this.olMap && config && config.layers && config.layers.length >= 2){
940			const container = document.createElement('div');
941			container.classList.add('ol-control');
942			container.classList.add('ol-unselectable');
943			container.classList.add('ol-control-layers');
944
945			if(hasFullscreen){
946				container.classList.add('ol-has-fullscreen');
947			}
948
949			// .ol-full-screen {
950			// 	right: .5em;
951			// 	top: .5em;
952			// }
953
954			for(let index in config.layers){
955				const layer = config.layers[index];
956				let label = WPGMZA.localized_strings[`map_type_${layer}`] ? WPGMZA.localized_strings[`map_type_${layer}`] : WPGMZA.capitalizeWords(layer);
957
958				const button = document.createElement('button');
959				button.innerText = label;
960				button.classList.add('ol-layer-button');
961				button.classList.add('ol-layer-button');
962				button.setAttribute('type', 'button');
963				button.setAttribute('data-map-type', layer);
964
965				if(config.active && config.active === layer){
966					button.classList.add('selected');
967				}
968
969				container.append(button);
970
971				button.addEventListener('click', (event) => {
972					event.preventDefault();
973
974					this.setMapType(layer);
975				});
976			}
977
978			const layerController = new ol.control.Control({
979				element : container,
980			});
981
982			this.olMap.addControl(layerController);
983		}
984	}
985
986	/**
987	 * Enables / disables the scale control bar
988	 * @param enable boolean, enable or not
989	 * @return void
990	 */
991	WPGMZA.OLMap.prototype.enableScaleControl = function(enable)
992	{
993		if(!this.olMap)
994			return;
995
996		if(this.scaleControl){
997			this.olMap.removeControl(this.scaleControl);
998			this.scaleControl = null;
999		}
1000
1001		if(enable){
1002			const units = (this.settings.store_locator_distance == WPGMZA.Distance.MILES)
1003				? 'imperial'
1004				: 'metric';
1005
1006			this.scaleControl = new ol.control.ScaleLine({ units: units });
1007			this.olMap.addControl(this.scaleControl);
1008		}
1009	}
1010
1011	WPGMZA.OLMap.prototype.isLegacy = function(){
1012		if(WPGMZA.settings && WPGMZA.settings.engine === 'open-layers'){
1013			return true; // Using Legacy V6 OpenLayers
1014		}
1015		return false;
1016	}
1017	
1018});

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.