1/** 2 * @namespace WPGMZA 3 * @module LeafletMap 4 * @requires WPGMZA.Map 5 * @pro-requires WPGMZA.ProMap 6 */ 7jQuery(function($) { 8 9 var Parent; 10 11 WPGMZA.LeafletMap = function(element, options) 12 { 13 var self = this; 14 15 Parent.call(this, element); 16 17 this.setOptions(options); 18 19 $(this.element).html(""); 20 21 let mapOptions = this.settings.toLeafletViewOptions(); 22 mapOptions = mapOptions ? mapOptions : {}; 23 24 this.mapType = mapOptions.mapType ? mapOptions.mapType : 'roadmap'; 25 this.tileLayers = this.getTileLayers(); 26 27 mapOptions.layers = this.tileLayers; 28 29 if(this.customTileMode){ 30 mapOptions.crs = L.extend({}, L.CRS.Simple, { 31 scale: (zoom) => { 32 const initialScale = Math.min( 33 1000 / this.customTileDimensions.width, 34 1000 / this.customTileDimensions.height 35 ); 36 return initialScale * Math.pow(2, zoom); 37 } 38 }); 39 40 if(this.customTileBounds){ 41 const mapBounds = L.latLngBounds(this.customTileBounds); 42 if(!mapBounds.contains(mapOptions.center)){ 43 /* Starting location is out of bounds */ 44 mapOptions.center = mapBounds.getCenter(); 45 this.onBoundsChanged(); 46 } 47 } 48 } 49 50 mapOptions = this.extendNativeConfig(mapOptions); 51 52 this.leafletMap = L.map($(element)[0], mapOptions); 53 54 function isSettingDisabled(value) { 55 if(value === "yes"){ 56 return true; 57 } 58 return (value ? true : false); 59 } 60 61 /* Gesture Handling */ 62 if(!(this.settings.wpgmza_force_greedy_gestures == "greedy" || this.settings.wpgmza_force_greedy_gestures == "yes" || this.settings.wpgmza_force_greedy_gestures == true)){ 63 this.gestureOverlay = $("<div class='wpgmza-gesture-overlay'></div>") 64 this.gestureOverlayTimeoutID = null; 65 66 if(WPGMZA.isTouchDevice()) { 67 /* Touch : Two finger pan for drag events */ 68 if(this.leafletMap.dragging){ 69 this.leafletMap.dragging.disable(); 70 71 this.gestureState = { 72 touches : {}, 73 touchCount : 0, 74 midpoint : null, 75 center : null 76 }; 77 78 const leafletContainer = this.leafletMap.getContainer(); 79 80 L.DomEvent.on(leafletContainer, 'touchstart', (event) => { 81 Array.from(event.touches).forEach((touch) => { 82 this.gestureState.touches[touch.identifier] = { 83 x : touch.clientX, 84 y : touch.clientY 85 }; 86 }); 87 88 this.gestureState.touchCount = Object.keys(this.gestureState.touches).length; 89 if(this.gestureState.touchCount === 2){ 90 /* Two finger pan, track the gesture event for panning */ 91 L.DomEvent.preventDefault(event); 92 93 let touches = { 94 a : event.touches[0], 95 b : event.touches[1] 96 }; 97 98 this.gestureState.midpoint = L.point( 99 (touches.a.clientX + touches.b.clientX) / 2, 100 (touches.a.clientY + touches.b.clientY) / 2 101 ); 102 103 this.gestureState.center = this.leafletMap.getCenter(); 104 } else if(this.gestureState.touchCount === 1){ 105 /* If one touch, show the notice, if more we don't do anything */ 106 this.showGestureOverlay(); 107 } 108 }); 109 110 L.DomEvent.on(leafletContainer, 'touchmove', (event) => { 111 if(this.gestureState.touchCount === 2 && event.touches.length === 2){ 112 L.DomEvent.preventDefault(event); 113 114 let touches = { 115 a : event.touches[0], 116 b : event.touches[1] 117 }; 118 119 const midpoint = L.point( 120 (touches.a.clientX + touches.b.clientX) / 2, 121 (touches.a.clientY + touches.b.clientY) / 2 122 ); 123 124 const delta = { 125 x : midpoint.x - this.gestureState.midpoint.x, 126 y : midpoint.y - this.gestureState.midpoint.y 127 }; 128 129 const mapCenterPoint = this.leafletMap.latLngToContainerPoint(this.gestureState.center); 130 131 this.leafletMap.panTo( 132 this.leafletMap.containerPointToLatLng( 133 L.point( 134 mapCenterPoint.x - delta.x, 135 mapCenterPoint.y - delta.y 136 ) 137 ), 138 { 139 animate : false 140 } 141 ); 142 } 143 }); 144 145 L.DomEvent.on(leafletContainer, 'touchend', (event) => { 146 Array.from(event.changedTouches).forEach((touch) => { 147 delete this.gestureState.touches[touch.identifier]; 148 }); 149 150 if(Object.keys(this.gestureState.touches).length < 2){ 151 this.gestureState.midpoint = null; 152 this.gestureState.center = null; 153 } 154 }); 155 156 L.DomEvent.on(leafletContainer, 'touchcancel', (event) => { 157 this.gestureState.touches = {}; 158 this.gestureState.midpoint = null; 159 this.gestureState.center = null; 160 }); 161 162 this.gestureOverlay.text(WPGMZA.localized_strings.use_two_fingers); 163 } 164 } else { 165 /* Desktop : Require CTLR or CMD + Scroll to zoom, show overlay if not */ 166 if(this.leafletMap.scrollWheelZoom){ 167 this.leafletMap.scrollWheelZoom.disable(); 168 169 const leafletContainer = this.leafletMap.getContainer(); 170 L.DomEvent.on(leafletContainer, 'wheel', (event) => { 171 L.DomEvent.preventDefault(event); 172 173 if(event.ctrlKey || event.metaKey){ 174 const delta = L.DomEvent.getWheelDelta(event); 175 this.leafletMap.setZoom(this.leafletMap.getZoom() + (delta > 0 ? 1 : -1)); 176 } else { 177 this.showGestureOverlay(); 178 } 179 }); 180 181 let getstureString = WPGMZA.localized_strings.use_ctrl_scroll_to_zoom; 182 if(WPGMZA.isDeviceiOS()){ 183 getstureString = WPGMZA.localized_strings.use_ctrl_scroll_to_zoom_ios; 184 } 185 186 this.gestureOverlay.text(getstureString); 187 } 188 } 189 } 190 191 /* Layer control */ 192 const multiLayerConfig = this.settings.hasMutlilayerTileServer(); 193 if(multiLayerConfig && !this.customTileMode){
194 /* This map has more than one layer in it's tile server configuration */ 195 196 if(!isSettingDisabled(WPGMZA.settings.wpgmza_settings_map_type)){ 197 this.addMapTypeControl(multiLayerConfig); 198 } 199 } 200 201 /* Fullscreen Controller */ 202 if(!isSettingDisabled(WPGMZA.settings.wpgmza_settings_map_full_screen_control)){ 203 this.addFullscreenControl(); 204 } 205 206 /* Scale Control */ 207 if(this.settings.enable_scale_control){ 208 this.enableScaleControl(true); 209 } 210 211 /* Click listener */ 212 this.leafletMap.on('click', (event) => { 213 this.dispatchEvent({ 214 type: "click", 215 map: this, 216 latLng : { 217 lat : event.latlng.lat, 218 lng : event.latlng.lng 219 } 220 }); 221 }) 222 223 /* Drag Start */ 224 this.leafletMap.on("movestart", (event) => { 225 this.isBeingDragged = true; 226 }); 227 228 /* Drag End */ 229 this.leafletMap.on("moveend", (event) => { 230 // this.wrapLongitude(); 231 232 if(this.isBeingDragged){ 233 this.dispatchEvent("dragend"); 234 this.isBeingDragged = false; 235 } 236 this.onIdle(); 237 }); 238 239 /* Zoom Event */ 240 this.leafletMap.on('zoomend', (event) => { 241 this.dispatchEvent("zoom_changed"); 242 this.dispatchEvent("zoomchanged"); 243 setTimeout(() => { 244 this.onIdle(); 245 }, 10); 246 }); 247 248 /* Bounds change */ 249 this.leafletMap.on("move", () => { 250 this.onBoundsChanged(); 251 }); 252 253 this.onBoundsChanged(); 254 255 /* Right click listener */ 256 this.leafletMap.on('click contextmenu', (event) => { 257 let isRight; 258 259 if("which" in event.originalEvent) 260 isRight = event.originalEvent.which == 3; 261 else if("button" in event.originalEvent) 262 isRight = event.originalEvent.button == 2; 263 264 if(event.originalEvent.which == 1 || event.originalEvent.button == 1){ 265 if(this.isBeingDragged){ 266 return; 267 } 268 } 269 270 if(!isRight){ 271 return; 272 } 273 274 return this.onRightClick(event); 275 }); 276 277 // Dispatch event 278 if(!WPGMZA.isProVersion()) { 279 this.trigger("init"); 280 281 this.dispatchEvent("created"); 282 WPGMZA.events.dispatchEvent({type: "mapcreated", map: this}); 283 284 // Legacy event 285 $(this.element).trigger("wpgooglemaps_loaded"); 286 } 287 288 if(this.innerStack && this.innerStack.length > 0){ 289 /* Disable inner stack components from allowing clicks through to the map surface */ 290 this.innerStack.each((index, element) => { 291 L.DomEvent.disableClickPropagation(element); 292 L.DomEvent.disableScrollPropagation(element); 293 L.DomEvent.on(element, 'mousedown', L.DomEvent.stopPropagation); 294 }); 295 } 296 297 /* Force a Leaflet origin recalc after the page has actually painted. 298 * `L.map(...)` above snapshots the container's dimensions at construction 299 * time and computes its internal pixel origin from them; if the page 300 * hasn't finished its initial layout (web fonts still settling, parent 301 * flex/grid widths still resolving, a `display:none` ancestor that just 302 * became visible, etc.) the snapshot is wrong and every marker placed 303 * thereafter is offset against that bad origin. 304 * 305 * Double-nested requestAnimationFrame is the standard "after first 306 * paint" signal: the outer rAF fires before the next paint, the inner 307 * rAF guarantees the browser has actually painted at least once before 308 * we measure. Leaflet's invalidateSize() compares old vs new dimensions 309 * internally and bails when nothing changed, so this is safe to fire 310 * unconditionally â the happy-path cost is one size measurement. */ 311 if(typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function'){ 312 window.requestAnimationFrame(() => { 313 window.requestAnimationFrame(() => { 314 if(this.leafletMap && typeof this.leafletMap.invalidateSize === 'function'){ 315 this.leafletMap.invalidateSize(); 316 } 317 }); 318 }); 319 } 320 } 321 322 if(WPGMZA.isProVersion()) 323 Parent = WPGMZA.ProMap; 324 else 325 Parent = WPGMZA.Map; 326 327 WPGMZA.LeafletMap.prototype = Object.create(Parent.prototype); 328 WPGMZA.LeafletMap.prototype.constructor = WPGMZA.LeafletMap; 329 330 WPGMZA.LeafletMap.prototype.getTileLayers = function(){ 331 let url = WPGMZA.settings.tile_server_url ? WPGMZA.settings.tile_server_url : "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; 332 let tileKey = WPGMZA.settings.leaflet_api_key ? WPGMZA.settings.leaflet_api_key : false;
333 334 switch(WPGMZA.settings.engine){ 335 case 'leaflet-azure': 336 /* Remap to Azure settings */ 337 url = WPGMZA.settings.tile_server_url_leaflet_azure ? WPGMZA.settings.tile_server_url_leaflet_azure : url; 338 tileKey = WPGMZA.settings.wpgmza_leaflet_azure_key ? WPGMZA.settings.wpgmza_leaflet_azure_key : tileKey; 339 break; 340 case 'leaflet-stadia': 341 /* Remap to Stadia settings */ 342 url = WPGMZA.settings.tile_server_url_leaflet_stadia ? WPGMZA.settings.tile_server_url_leaflet_stadia : url; 343 tileKey = WPGMZA.settings.wpgmza_leaflet_stadia_key ? WPGMZA.settings.wpgmza_leaflet_stadia_key : tileKey; 344 break; 345 case 'leaflet-maptiler': 346 /* Remap to Maptiler settings */ 347 url = WPGMZA.settings.tile_server_url_leaflet_maptiler ? WPGMZA.settings.tile_server_url_leaflet_maptiler : url; 348 tileKey = WPGMZA.settings.wpgmza_leaflet_maptiler_key ? WPGMZA.settings.wpgmza_leaflet_maptiler_key : tileKey; 349 break; 350 case 'leaflet-locationiq': 351 /* Remap to LocationIQ settings */ 352 url = WPGMZA.settings.tile_server_url_leaflet_locationiq ? WPGMZA.settings.tile_server_url_leaflet_locationiq : url; 353 tileKey = WPGMZA.settings.wpgmza_leaflet_locationiq_key ? WPGMZA.settings.wpgmza_leaflet_locationiq_key : tileKey; 354 break; 355 case 'leaflet-zerocost': 356 /* Remap to zerocost settings */ 357 url = WPGMZA.settings.tile_server_url_leaflet_zerocost ? WPGMZA.settings.tile_server_url_leaflet_zerocost : url; 358 break; 359 } 360 361 const config = this.settings.configureTileServer(url, { 362 authentication : tileKey, 363 preferServerGlobals : true, 364 map : this 365 }); 366 367 if(config && config.url){ 368 if(config.type && config.type === 'vector' && typeof L.maplibreGL !== 'undefined'){ 369 /* Vector base layer, so we use MapLibreGL */ 370 let mapLibreOptions = {style : config.url}; 371 if(config.options){ 372 for(let key in config.options){ 373 if(key === 'url'){ 374 continue; 375 } 376 377 mapLibreOptions[key] = config.options[key]; 378 }; 379 } 380 381 return [L.maplibreGL(mapLibreOptions)]; 382 } else if (config.type && config.type === 'custom'){ 383 this.customTileDimensions = {width : config.custom.width, height : config.custom.height}; 384 this.customTileBounds = [[0,0], [this.customTileDimensions.height, this.customTileDimensions.width]]; 385 this.customTileMode = true; 386 return [L.imageOverlay(config.url, this.customTileBounds, { 387 attribution: config.custom.attribution ? config.custom.attribution : '©' 388 })]; 389 } 390 391 const layers = []; 392 393 if(config.dependencies){ 394 for(let dependency of config.dependencies){ 395 layers.push(new L.tileLayer(dependency.url, config.options ? config.options : {})); 396 } 397 } 398 399 layers.push(new L.tileLayer(config.url, config.options ? config.options : {})); 400 return layers; 401 } 402 403 /* Fallback */ 404 return [new L.tileLayer(url, {})]; 405 } 406 407 WPGMZA.LeafletMap.prototype.wrapLongitude = function(){ 408 let center = this.leafletMap.getCenter(); 409 if(center.lng >= -180 && center.lng <= 180){ 410 return; 411 } 412 413 center.lng = center.lng - 360 * Math.floor(center.lng / 360); 414 415 if(center.lng > 180){ 416 center.lng -= 360; 417 } 418 419 this.setCenter(center); 420 } 421 422 WPGMZA.LeafletMap.prototype.getCenter = function(){ 423 const center = this.leafletMap.getCenter(); 424 return { 425 lat: center.lat, 426 lng: center.lng 427 }; 428 } 429 430 WPGMZA.LeafletMap.prototype.setCenter = function(latLng) { 431 WPGMZA.Map.prototype.setCenter.call(this, latLng); 432 433 this.leafletMap.panTo(L.latLng({lat : latLng.lat, lng : latLng.lng}), {animate : false}); 434 // this.wrapLongitude(); 435 436 this.onBoundsChanged(); 437 } 438 439 WPGMZA.LeafletMap.prototype.getBounds = function() { 440 let bounds = this.leafletMap.getBounds(); 441 let nativeBounds = new WPGMZA.LatLngBounds(); 442 443 nativeBounds.north = bounds.getNorth(); 444 nativeBounds.south = bounds.getSouth(); 445 446 nativeBounds.west = bounds.getWest(); 447 nativeBounds.east = bounds.getEast(); 448 449 return nativeBounds; 450 } 451 452 /** 453 * Fit to given boundaries 454 * @return void 455 */ 456 WPGMZA.LeafletMap.prototype.fitBounds = function(southWest, northEast) { 457 if(southWest instanceof WPGMZA.LatLng){ 458 southWest = {lat: southWest.lat, lng: southWest.lng}; 459 } 460 461 if(northEast instanceof WPGMZA.LatLng){ 462 northEast = {lat: northEast.lat, lng: northEast.lng}; 463 } else if(southWest instanceof WPGMZA.LatLngBounds) { 464 var bounds = southWest; 465 466 southWest = { 467 lat: bounds.south, 468 lng: bounds.west 469 }; 470 471 northEast = { 472 lat: bounds.north, 473 lng: bounds.east 474 }; 475 } 476 477 const leafletBounds = L.latLngBounds( 478 L.latLng({lat : northEast.lat, lng : northEast.lng}),
479 L.latLng({lat : southWest.lat, lng : southWest.lng}) 480 ); 481 482 this.leafletMap.fitBounds(leafletBounds, { padding : [60, 60]}); 483 } 484 485 WPGMZA.LeafletMap.prototype.panTo = function(latLng, zoom) { 486 if(arguments.length > 1){ 487 this.leafletMap.flyTo(L.latLng({lat: latLng.lat, lng: latLng.lng}), parseInt(zoom)); 488 } else { 489 this.leafletMap.flyTo(L.latLng({lat: latLng.lat, lng: latLng.lng})); 490 } 491 } 492 493 WPGMZA.LeafletMap.prototype.getZoom = function() { 494 return Math.round( this.leafletMap.getZoom() ); 495 } 496 497 WPGMZA.LeafletMap.prototype.setZoom = function(value) { 498 this.leafletMap.setZoom(value); 499 } 500 501 WPGMZA.LeafletMap.prototype.getMinZoom = function() { 502 return this.leafletMap.getMinZoom(); 503 } 504 505 WPGMZA.LeafletMap.prototype.setMinZoom = function(value) { 506 this.leafletMap.setMinZoom(value); 507 } 508 509 WPGMZA.LeafletMap.prototype.getMaxZoom = function() { 510 return this.leafletMap.getMaxZoom(); 511 } 512 513 WPGMZA.LeafletMap.prototype.setMaxZoom = function(value) { 514 this.leafletMap.setMaxZoom(value); 515 } 516 517 WPGMZA.LeafletMap.prototype.setMapType = function(type){ 518 if(this.mapType !== type){ 519 this.mapType = type; 520 521 if(this.tileLayers){ 522 for(let layer of this.tileLayers){ 523 if(this.leafletMap.hasLayer(layer)){ 524 this.leafletMap.removeLayer(layer); 525 } 526 } 527 } 528 529 this.tileLayers = this.getTileLayers(); 530 531 for(let layer of this.tileLayers){ 532 this.leafletMap.addLayer(layer); 533 } 534 535 $(this.element).find('.leaflet-layer-button[data-map-type]').removeClass('selected'); 536 $(this.element).find('.leaflet-layer-button[data-map-type="' + type + '"]').addClass('selected'); 537 } 538 } 539 540 WPGMZA.LeafletMap.prototype.getMapType = function(){ 541 return this.mapType ? this.mapType : 'roadmap'; 542 } 543 544 WPGMZA.LeafletMap.prototype.setOptions = function(options) { 545 Parent.prototype.setOptions.call(this, options); 546 547 if(!this.leafletMap){ 548 /* Hasn't been initialized yet */ 549 return; 550 } 551 552 /* Leaflet doesn't allow a bulk setter like other engines, we need to manage this internally */ 553 let mapOptions = this.settings.toLeafletViewOptions(); 554 for (const key in mapOptions) { 555 if (!mapOptions.hasOwnProperty(key)) { 556 continue; 557 } 558 559 const value = options[key]; 560 561 switch (key) { 562 case 'zoomControl': 563 if (value === false && this.leafletMap.zoomControl) { 564 this.leafletMap.removeControl(this.leafletMap.zoomControl); 565 } else if (value === true && !this.leafletMap.zoomControl) { 566 this.leafletMap.addControl(L.control.zoom()); 567 } 568 break; 569 case 'dragging': 570 case 'doubleClickZoom': 571 case 'scrollWheelZoom': 572 case 'boxZoom': 573 case 'keyboard': 574 case 'tap': 575 case 'touchZoom': 576 if (this.leafletMap[key]) { 577 if (value === true) { 578 this.leafletMap[key].enable(); 579 } else { 580 this.leafletMap[key].disable(); 581 } 582 } 583 break; 584 case 'minZoom': 585 this.setMinZoom(value); 586 break; 587 case 'maxZoom': 588 this.setMaxZoom(value); 589 break; 590 default: 591 break; 592 } 593 } 594 } 595 596 /** 597 * TODO: Consider moving all these functions to their respective classes, same on google map (DO IT!!! It's very misleading having them here) 598 */ 599 WPGMZA.LeafletMap.prototype.addMarker = function(marker) { 600 marker.leafletMarker.addTo(this.leafletMap); 601 Parent.prototype.addMarker.call(this, marker); 602 } 603 604 WPGMZA.LeafletMap.prototype.removeMarker = function(marker) { 605 marker.leafletMarker.removeFrom(this.leafletMap); 606 Parent.prototype.removeMarker.call(this, marker); 607 } 608 609 WPGMZA.LeafletMap.prototype.addPolygon = function(polygon) { 610 polygon.leafletFeature.addTo(this.leafletMap); 611 Parent.prototype.addPolygon.call(this, polygon); 612 } 613 614 WPGMZA.LeafletMap.prototype.removePolygon = function(polygon) { 615 polygon.leafletFeature.remove(); 616 Parent.prototype.removePolygon.call(this, polygon); 617 } 618 619 WPGMZA.LeafletMap.prototype.addPolyline = function(polyline) { 620 polyline.leafletFeature.addTo(this.leafletMap); 621 Parent.prototype.addPolyline.call(this, polyline); 622 } 623 624 WPGMZA.LeafletMap.prototype.removePolyline = function(polyline) { 625 polyline.leafletFeature.remove(); 626 Parent.prototype.removePolyline.call(this, polyline); 627 } 628 629 WPGMZA.LeafletMap.prototype.addCircle = function(circle) { 630 circle.leafletFeature.addTo(this.leafletMap); 631 Parent.prototype.addCircle.call(this, circle); 632 } 633 634 WPGMZA.LeafletMap.prototype.removeCircle = function(circle) { 635 circle.leafletFeature.remove(); 636 Parent.prototype.removeCircle.call(this, circle); 637 } 638 639 WPGMZA.LeafletMap.prototype.addRectangle = function(rectangle) { 640 rectangle.leafletFeature.addTo(this.leafletMap); 641 Parent.prototype.addRectangle.call(this, rectangle); 642 } 643 644 WPGMZA.LeafletMap.prototype.removeRectangle = function(rectangle) { 645 rectangle.leafletFeature.remove(); 646 Parent.prototype.removeRectangle.call(this, rectangle); 647 } 648 649 WPGMZA.LeafletMap.prototype.pixelsToLatLng = function(x, y) { 650 if(y == undefined) { 651 if("x" in x && "y" in x) { 652 y = x.y; 653 x = x.x; 654 } else { 655 console.warn("Y coordinate undefined in pixelsToLatLng (did you mean to pass 2 arguments?)"); 656 } 657 } 658 659 let coord = this.leafletMap.containerPointToLatLng(L.point(x, y)); 660 if(!coord){ 661 return { 662 x: null, 663 y: null 664 }; 665 } 666 667 return { 668 lat: coord.lat, 669 lng: coord.lng 670 }; 671 } 672 673 WPGMZA.LeafletMap.prototype.latLngToPixels = function(latLng) { 674 let pixel = this.leafletMap.latLngToContainerPoint(latLng); 675 if(!pixel){ 676 return { 677 x: null, 678 y: null 679 }; 680 } 681 682 return { 683 x: pixel.x, 684 y: pixel.y 685 }; 686 } 687 688 WPGMZA.LeafletMap.prototype.showGestureOverlay = function() { 689 clearTimeout(this.gestureOverlayTimeoutID); 690 691 $(this.gestureOverlay).stop().animate({opacity: "100"}); 692 $(this.element).append(this.gestureOverlay); 693 694 $(this.gestureOverlay).css({ 695 "line-height": $(this.element).height() + "px", 696 "opacity": "1.0" 697 }); 698 699 $(this.gestureOverlay).show(); 700 701 this.gestureOverlayTimeoutID = setTimeout(() => { 702 this.gestureOverlay.fadeOut(500); 703 }, 1000); 704 } 705 706 WPGMZA.LeafletMap.prototype.onRightClick = function(event) { 707 this.trigger({type: "rightclick", latLng: event.latlng}); 708 709 // Legacy event compatibility 710 $(this.element).trigger({type: "rightclick", latLng: event.latlng}); 711 712 // Prevent menu 713 event.originalEvent.preventDefault(); 714 return false;
715 } 716 717 WPGMZA.LeafletMap.prototype.addFullscreenControl = function(){ 718 if(this.leafletMap){ 719 const fullscreenController = L.control({position : 'topright'}); 720 fullscreenController.onAdd = (map) => { 721 const container = L.DomUtil.create('div'); 722 container.classList.add('leaflet-bar'); 723 container.classList.add('leaflet-control'); 724 container.classList.add('leaflet-control-fullscreen'); 725 726 const button = L.DomUtil.create('a'); 727 button.classList.add('leaflet-control-button'); 728 button.classList.add('leaflet-fullscreen-button'); 729 button.href = '#'; 730 731 button.setAttribute('aria-label', "Fullscreen"); 732 733 const corners = ['tl' , 'tr' , 'bl', 'br']; 734 for(let corner of corners){ 735 const element = L.DomUtil.create('span'); 736 element.classList.add('leaflet-fullscreen-corner'); 737 element.classList.add('leaflet-fullscreen-corner-' + corner); 738 button.append(element); 739 } 740 741 container.append(button); 742 743 L.DomEvent.on(button, 'click', (event) => { 744 event.preventDefault(); 745 if(document.fullscreenElement){ 746 document.exitFullscreen(); 747 } else { 748 const mapContainer = this.element; 749 if (mapContainer.requestFullscreen) { 750 mapContainer.requestFullscreen(); 751 } else if (mapContainer.mozRequestFullScreen) { 752 mapContainer.mozRequestFullScreen(); 753 } else if (mapContainer.webkitRequestFullscreen) { 754 mapContainer.webkitRequestFullscreen(); 755 } else if (mapContainer.msRequestFullscreen) { 756 mapContainer.msRequestFullscreen(); 757 } 758 } 759 }); 760 761 return container; 762 } 763 764 fullscreenController.addTo(this.leafletMap); 765 } 766 } 767 768 WPGMZA.LeafletMap.prototype.addMapTypeControl = function(config){ 769 if(this.leafletMap && config && config.layers && config.layers.length >= 2){ 770 const layerController = L.control({position : 'topright'}); 771 layerController.onAdd = (map) => { 772 const container = L.DomUtil.create('div'); 773 container.classList.add('leaflet-bar'); 774 container.classList.add('leaflet-control'); 775 container.classList.add('leaflet-control-layers'); 776 777 for(let index in config.layers){ 778 const layer = config.layers[index]; 779 780 let label = WPGMZA.localized_strings[`map_type_${layer}`] ? WPGMZA.localized_strings[`map_type_${layer}`] : WPGMZA.capitalizeWords(layer); 781 782 const button = L.DomUtil.create('a'); 783 button.innerText = label; 784 button.classList.add('leaflet-control-button'); 785 button.classList.add('leaflet-layer-button'); 786 button.href = '#'; 787 788 button.setAttribute('data-map-type', layer); 789 790 if(config.active && config.active === layer){ 791 button.classList.add('selected'); 792 } 793 794 container.append(button); 795 796 L.DomEvent.on(button, 'click', (event) => { 797 event.preventDefault(); 798 this.setMapType(layer); 799 }); 800 } 801 802 803 return container; 804 } 805 806 layerController.addTo(this.leafletMap); 807 } 808 } 809 810 /** 811 * Enables / disables the scale control bar 812 * @param enable boolean, enable or not 813 * @return void 814 */ 815 WPGMZA.LeafletMap.prototype.enableScaleControl = function(enable) 816 { 817 if(!this.leafletMap) 818 return; 819 820 if(this.scaleControl){ 821 this.scaleControl.remove(); 822 this.scaleControl = null; 823 } 824 825 if(enable){ 826 const imperial = (this.settings.store_locator_distance == WPGMZA.Distance.MILES); 827 828 this.scaleControl = L.control.scale({ 829 imperial: imperial, 830 metric: !imperial, 831 position: 'bottomleft' 832 }).addTo(this.leafletMap); 833 } 834 } 835 836 WPGMZA.LeafletMap.prototype.getLayerGroupPane = function(pane, layer, basePane){ 837 basePane = typeof basePane === 'undefined' || !basePane ? 'overlayPane' : basePane; 838 if(this.leafletMap){ 839 let nativePane = this.leafletMap.getPane(`${pane}${layer}`); 840 if(!nativePane){ 841 nativePane = this.leafletMap.createPane(`${pane}${layer}`, this.leafletMap.getPane(basePane)); 842 nativePane.style.zIndex = layer; 843 } 844 845 return `${pane}${layer}`; 846 } 847 return false; 848 } 849 850 WPGMZA.LeafletMap.prototype.resetBounds = function() { 851 var latlng = new WPGMZA.LatLng(this.settings.map_start_lat, this.settings.map_start_lng); 852 this.panTo(latlng, this.settings.map_start_zoom); 853 } 854});
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.