(function ($, hotspots, undefined) { "use strict"; var Leaflet = L.noConflict(); var ua = window.navigator.userAgent, isiOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i), isWebkit = !!ua.match(/WebKit/i), isWebkitiOS = isiOS && isWebkit, isMobileSafari = isiOS && isWebkit && !ua.match(/CriOS/i), getBrowserVersion = function () { var temp, M = ua.match( /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i, ) || []; M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"]; if ((temp = ua.match(/version\/(\d+)/i)) != null) { M.splice(1, 1, temp[1]); } return parseInt(M[1]); }; // Store all the leaflets on the page in an array for access later var leaflets = []; // Store all image maps on the page in an object for access later var imageMaps = {}; // Store all the more info area hotspots in an object for access later hotspots.infoSpots = {}; var mapSetup = function () { $(".da-error").hide(); $(".hotspot-info").addClass("da-hidden"); var images = $("img.hotspots-image, picture.hotspots-image img"); // Select images as well as images inside picture elements images.each(function () { var img = $(this); var tester = new Image(); tester.onload = function () { markLoaded(img); moreInfoSetup(img); leafletSetup(img); }; tester.src = img.attr("src"); }); if (isMobileSafari) { window.onpageshow = function (event) { if (event.persisted) { window.location.reload(); } }; } }; var markLoaded = function (img) { img.data("status", "loaded"); var container = img.parents(".hotspots-container").addClass("loaded"); img.attr("aria-hidden", true); }; var stopAudioVideo = function (el) { var iframe = el.querySelector("iframe[src*=youtube]"); var video = el.querySelector("video"); var audio = el.querySelector("audio"); if (iframe) { var iframeSrc = iframe.src; iframe.src = iframeSrc; } if (video) { video.pause(); } if (audio) { audio.pause(); } }; var moreInfoSetup = function (img) { var container = img.parents(".hotspots-container"); if (container.data("layout") == "tooltip") { return; } if (container.data("layout") == "lightbox") { lightboxSetup(container, img); return; } infoboxSetup(container, img); }; var infoboxSetup = function (container, img) { var initial = container.find(".hotspot-initial"); var content = container.find(".hotspots-placeholder"); initial.addClass("visible"); container.on("active.responsilight inactive.responsilight", function (e) { var data = $(e.target).data("areaData"); var info; if (e.type === "active") { info = $(data.href); } else { info = initial; } var visibleContent = content.children(".visible"); stopAudioVideo(visibleContent.get(0)); visibleContent.removeClass("visible"); info.removeClass("da-hidden").addClass("visible").appendTo(content); // Check for an embedded video player var video = info.find(".wp-video"); if (video.length) { if (!info.data("video-resized")) { info.data("video-resized", true); window.dispatchEvent(new Event("resize")); } } }); }; var lightboxSetup = function (container, img) { container.on("active.responsilight", function (e) { var data = $(e.target).data("areaData"), info = $(data.href), container = info.parent(), target = $(e.target), currentLightbox = $(".featherlight"); if (e.type === "active" && currentLightbox.length === 0) { $.featherlight('
', { closeLabel: drawattentionData.closeLabel, closeSpeed: 250, closeOnEsc: false, afterContent: function () { var content = $(".featherlight-inner"), lb = $(".featherlight-content"), mapNo = img.data("id"); info.appendTo(content).show(); lb.addClass("lightbox-" + mapNo); // Fix accessibility issue - links not focusable by keyboard var untabbables = info.find("a[tabindex=-1]"); untabbables.attr("tabindex", 0); setTimeout(function () { var img = content.find("img"), contentHeight = content.get(0).scrollHeight, imgHeight = img.height(), lbHeight = lb.outerHeight(); if (contentHeight > lbHeight) { var diff = contentHeight - lbHeight + 50, newHeight = imgHeight - diff, minHeight = $(window).innerHeight() / 2; newHeight = newHeight < minHeight ? minHeight : newHeight; var naturalHeight = img.prop("naturalHeight"); if (newHeight < naturalHeight) { img.css({ width: "auto" }); img.animate( { height: newHeight, }, 200, ); } } }, 100); lightboxAnchorLinks(content, target); window.dispatchEvent(new Event("resize")); // Trigger window resize event for [video] shortcode JS }, afterOpen: function () { $("body").on("keyup", documentEsc); }, afterClose: function () { target.removeClass("hotspot-active"); $("body").off("keyup", documentEsc); }, beforeClose: function () { stopAudioVideo(document.querySelector(".featherlight-content")); setTimeout(function () { info.hide().appendTo(container); }, 500); // delay hiding content and moving it back outside the lightbox }, }); } }); }; var documentEsc = function (e) { if (e.keyCode === 27) { $.featherlight.current().close(); } }; var lightboxAnchorLinks = function (content, hotspot) { var links = content.find('.hotspot-content a[href^="#"]'); links.on("click", function (e) { e.preventDefault(); var targetEl = $(e.target.hash); var current = $.featherlight.current(); if (!current) return; current.afterClose = function () { hotspot.removeClass("hotspot-active"); $("html").removeClass("with-featherlight"); $("html, body").animate( { scrollTop: targetEl.offset().top, }, 500, ); }; current.close(); }); }; var showTooltip = function (shape, areaData) { var container = $(shape._map._container); var content = $(areaData.href).html(); var tip = Leaflet.responsivePopup({ autoPan: false, closeButton: areaData.trigger == "click", hasTip: container.width() > 840, maxHeight: container.height() * 0.9, offset: new Leaflet.Point(0, 0), }); tip.setContent(content); shape.bindPopup(tip); if (areaData.trigger === "click") { shape.on("click", function (e) { if (shape._path.classList.contains("hotspot-active")) { shape.closePopup(); } else { shape.openPopup(); } }); } else { shape.on("mouseover", function () { shape.openPopup(); }); shape.on("mouseout", function () { shape.closePopup(); }); } container.on("click", function (e) { e.stopPropagation(); }); $(document).on("click", function (e) { shape.closePopup(); shape._path.classList.remove("hotspot-active"); }); }; var leafletSetup = function (img) { var id = img.data("id"); var container = $( '', ); var imgWidth = img.width(); var imgHeight = img.height(); container.css({ width: imgWidth + "px", height: imgHeight + "px", }); img.after(container); // Check to be sure the container is on the page // To prevent errors when loaded in Elementor popup var containerTest = $("#hotspots-map-container-" + id); if (!containerTest.length) { return; } var map = Leaflet.map("hotspots-map-container-" + id, { attributionControl: false, boxZoom: false, crs: Leaflet.CRS.Simple, doubleClickZoom: false, dragging: false, keyboard: false, minZoom: -20, scrollWheelZoom: false, // tap: !isWebkitiOS, tap: true, touchZoom: false, zoomControl: false, zoomSnap: 0, }); var domImg = img.get(0); var natHeight = domImg.naturalHeight; var natWidth = domImg.naturalWidth; img.data("natW", natWidth); img.data("natH", natHeight); var bounds = [ [0, 0], [natHeight, natWidth], ]; var imageLayer = Leaflet.imageOverlay(img.attr("src"), bounds).addTo(map); map.fitBounds(bounds); leaflets.push({ map: map, img: img, }); drawSpots(img, map); }; var showContextMenu = function (shape, areaData, e) { var hash = areaData.href; var container = $(shape._map._container); if (!hash) { return; } $(".da-address-wrapper").remove(); var windowAddress = window.location.href.split("#")[0]; var shapeAddress = windowAddress + hash; var div = $('') .css({ left: e.originalEvent.pageX + "px", top: e.originalEvent.pageY + "px", }) .append("" + shapeAddress + "
") .append('×') .appendTo(document.body); div.find(".da-address-close").on("click", function () { div.remove(); }); }; var drawSpots = function (img, map) { var id = img.data("id"); /* If the image has a usemap attribute, detach the map and store it in the imageMaps object */ if (img[0].hasAttribute("usemap")) { var mapName = img.attr("usemap").replace("#", ""); var imageMap = $('map[name="' + mapName + '"]'); imageMaps[id] = imageMap.detach(); img.removeAttr("usemap"); } else { /* Else we've already removed the image map, so we just need to get it */ var imageMap = imageMaps[id]; } var areas = imageMap.find("area"); var container = img.parents(".hotspots-container"); areas.each(function () { var area = $(this); var shape = area.attr("shape"); var coords = area.attr("coords").split(","); var areaData = { style: area.data("color-scheme") ? area.data("color-scheme") : "default", title: area.attr("title"), href: area.attr("href"), spot: area.data("id"), target: area.attr("target"), action: area.data("action"), layout: container.data("layout"), trigger: container.data("trigger"), }; switch (shape) { case "circle": renderCircle(coords, map, img, areaData); break; case "rect": renderPoly(coords, map, img, areaData); break; case "polygon": renderPoly(coords, map, img, areaData); break; case "poly": // Leaving this here for backward compatibility renderPoly(coords, map, img, areaData); break; } }); // A11y fixes after all the spots are drawn a11yFixes(img, map); // Link to area after all the spots are drawn hotspots.linkToArea(); }; var renderCircle = function (coords, map, img, areaData) { var x = coords[0]; var y = img.data("natH") - coords[1]; var rad = coords[2]; var circle = Leaflet.circle([y, x], { radius: rad, className: "hotspot-" + areaData.style, title: areaData.title, }); circle.on("add", function (e) { var $circle = $(e.target.getElement()); $circle.data("areaData", areaData); $circle.attr("tabindex", "0"); $circle.attr("aria-label", areaData.title); $circle.attr("name", areaData.title); }); circle.addTo(map); // If this is a more info hotspot, add it to the infoSpots object if (areaData.href.charAt(0) === "#") { var spotName = areaData.href.replace("#", ""); hotspots.infoSpots[spotName] = circle; } shapeEvents(circle, areaData); }; var renderPoly = function (coords, map, img, areaData) { var xCoords = []; var yCoords = []; for (var i = 0; i < coords.length; i++) { if (i % 2 == 0) { xCoords.push(coords[i]); } else { yCoords.push(coords[i]); } } var polyCoords = yCoords.map(function (coord, index) { return [img.data("natH") - coord, xCoords[index]]; }); var poly = Leaflet.polygon(polyCoords, { className: "hotspot-" + areaData.style, title: areaData.title, }); // Attach the area data to the path as soon as it's added to the map, a11y attributes poly.on("add", function (e) { var $poly = $(e.target.getElement()); $poly.data("areaData", areaData); $poly.attr("tabindex", "0"); $poly.attr("aria-label", areaData.title); $poly.attr("name", areaData.title); }); poly.addTo(map); // If this is a more info hotspot, add it to the infoSpots object if (areaData.href.charAt(0) === "#") { var spotName = areaData.href.replace("#", ""); hotspots.infoSpots[spotName] = poly; } shapeEvents(poly, areaData); }; var shapeOver = function (shape, areaData, e) { var $shape = $(e.target.getElement()); $shape.trigger("over.responsilight"); if ( areaData.trigger === "hover" && (e.type !== "touchstart") & (e.type !== "keypress") ) { $shape.addClass("hotspot-active"); $shape.trigger("active.responsilight"); } }; var shapeOut = function (shape, areaData, e) { var $shape = $(e.target.getElement()); $shape.trigger("out.responsilight"); if (areaData.trigger === "hover" && e.type !== "keypress") { $shape.removeClass("hotspot-active"); $shape.trigger("inactive.responsilight"); // If mouse user, blur hover spots when mouse moves out if (e.type === "mouseout") { $shape.trigger("blur"); } } }; var shapeClick = function (shape, areaData, e) { var $shape = $(e.target.getElement()); $shape.trigger("areaClick.responsilight"); if ( areaData.trigger === "hover" && e.type !== "touchstart" && e.type !== "keypress" && !isMobileSafari ) { return; } $shape.toggleClass("hotspot-active"); if ($shape.hasClass("hotspot-active")) { $shape.trigger("active.responsilight"); } else { $shape.trigger("inactive.responsilight"); } var oldActive = $shape.siblings(".hotspot-active"); if (oldActive.length) { oldActive.removeClass("hotspot-active"); } }; var shapeEvents = function (shape, areaData) { // Handle URL spots if (areaData.action == "url") { if (areaData.title) { shape.bindTooltip(areaData.title); } shape.on("click", function (e) { if (areaData.target == "_new" && !isMobileSafari) { // new window window.open(areaData.href, "_blank"); } else { // same window var first = areaData.href.charAt(0); var targetElem; try { targetElem = first === "#" ? $(areaData.href) : null; } catch (error) { targetElem = null; } if (targetElem && targetElem.length) { // hash link to existing target $("html, body").animate( { scrollTop: targetElem.offset().top - 50, }, 750, function () { // callback after scrolling history.pushState({}, "", areaData.href); }, ); } else { window.location = areaData.href; } } }); return; } // Show right-click context menu for logged-in admins only if (drawattentionData.isLoggedIn && drawattentionData.isAdmin) { shape.on("contextmenu", function (e) { showContextMenu(shape, areaData, e); }); } // Handle tooltip spots if (areaData.layout === "tooltip") { showTooltip(shape, areaData); } // Add styled tooltip to all non-hover areas if ( areaData.action === "url" || (areaData.trigger === "click" && areaData.layout !== "tooltip") ) { if (areaData.title) { shape.bindTooltip(areaData.title); } } // Handle all other spots var moved = false; shape.on( "touchstart touchmove touchend click mouseover mouseout keypress focus blur", function (e) { switch (e.type) { case "touchstart": moved = false; break; case "touchmove": moved = true; break; case "touchend": if (moved) { return; } shapeOver(shape, areaData, e); shapeClick(shape, areaData, e); break; case "click": shapeClick(shape, areaData, e); break; case "keypress": var key = e.originalEvent.which; if (key == 13 || key == 32) { e.originalEvent.preventDefault(); shapeClick(shape, areaData, e); } break; case "mouseover": if (!isMobileSafari || (isMobileSafari && getBrowserVersion < 13)) { shapeOver(shape, areaData, e); } if (isMobileSafari && !(getBrowserVersion() >= 12)) { shapeClick(shape, areaData, e); } break; case "focus": shapeOver(shape, areaData, e); break; case "blur": shapeOut(shape, areaData, e); break; case "mouseout": shapeOut(shape, areaData, e); break; } }, ); }; var a11yFixes = function (img, map) { let svg = img .siblings(".leaflet-container") .find(".leaflet-overlay-pane svg"); let id = img.data("id"); // Add title and description to SVG svg.prepend( '