1window.zaw.loadMapRoute=()=>(zaw.mapRoute||=JSON.parse(localStorage.getItem(zaw.getWeekendPrefix()+"mapRoute")||"{}"));window.zaw.saveMapRoute=(freezeLocations=false)=>{if(freezeLocations)zaw.mapRoute.frozenLocations=true;localStorage.setItem(zaw.getWeekendPrefix()+"mapRoute",JSON.stringify(zaw.mapRoute));};(function(){const MAX_ZAW_LOCATIONS=10;const OVERVIEW_ZOOM=14;const LOCATION_ZOOM=17;const MARKER_TYPE_EVENT="Event";const MARKER_TYPE_EXHIBITION="Exhibition";const allMarkers=[];const mapVenuesBySlug={};const mapMarkersByLocation={};window.allMarkers=allMarkers;var myLocationMarker=null;const takenLocations={};let currentRoutePolyline=null;let currentFocusedMarker=null;function randomizeGeoposition(location){location.lat=parseFloat(location.lat);location.lng=parseFloat(location.lng);const tostr=(_location)=>_location.lat.toFixed(6)+","+_location.lng.toFixed(6);while(takenLocations[tostr(location)]){location.lat+=0.00005*(Math.random()-0.5);location.lng+=0.00005*(Math.random()-0.5);} 2takenLocations[tostr(location)]=true;return location;} 3function findMarker(location){for(var i=0;i<allMarkers.length;i++){var marker=allMarkers[i];var markerLocation=marker.get("position");if(markerLocation.lat()==location.lat&&markerLocation.lng()==location.lng){return marker;}}} 4function blurMarker(marker){$(marker.content).removeClass("focused");if(marker.initialZIndex)marker.zIndex=marker.initialZIndex;delete marker.initialZIndex;} 5function clearMarker(marker){$(marker.content).removeClass("focused");if(marker.initialZIndex)marker.zIndex=marker.initialZIndex;delete marker.initialZIndex;} 6function focusMarker(marker,flyto=false){for(const marker of allMarkers){blurMarker(marker);} 7$(marker.content).addClass("focused");currentFocusedMarker=marker;focusUiZawLocation(marker);marker.initialZIndex=marker.zIndex;marker.zIndex=allMarkers.length+1;if(flyto){flyToMarker(marker);}} 8function clearMarkersSelection(){for(const marker of allMarkers){clearMarker(marker);}} 9function blurAllMarkers(){for(const marker of allMarkers){blurMarker(marker);}} 10function flyToMarker(marker){const bounds=map.getBounds();if(map.getZoom()==LOCATION_ZOOM&&bounds&&bounds.contains(marker.position)){map.panTo(marker.position);return;} 11map.setZoom(OVERVIEW_ZOOM);google.maps.event.addListenerOnce(map,"idle",function(){map.panTo(marker.position);google.maps.event.addListenerOnce(map,"idle",function(){map.setZoom(LOCATION_ZOOM);google.maps.event.addListenerOnce(map,"idle",function(){panByRouteControlsOffset(marker.position);});});});} 12function panByRouteControlsOffset(geoPosition){if($("#not_md").is(":visible"))return;const $widget=$(".rmp-controls:not(.collapsed)");if($widget.length==0)return;const projection=map.getProjection();if(!projection)return;
12const sw=map.getBounds().getSouthWest();const leftMapCornerPoint=projection.fromLatLngToPoint(sw);const geoPositionPoint=projection.fromLatLngToPoint(geoPosition);const widgetWidth=$widget.width();const scale=1<<map.getZoom();const positionOffsetX=(geoPositionPoint.x-leftMapCornerPoint.x)*scale;if(positionOffsetX>widgetWidth+160)return;map.panBy(-widgetWidth/2,0);} 13function getMarkerByLocationID(locationID){return mapMarkersByLocation[locationID];} 14function addExhibitionMarker(exhibition,venue){const zawLocation=buildExhibitionZawLocation(venue,exhibition);const $content=$('<div><div class="widget"></div><div class="shadow"></div></div>');$content.addClass("map-marker exhibition-marker");if(zawLocation.isFavourite){$content.addClass("favourite");$content.find(".widget").addClass("feat-bg");}else{$content.css({"background-color":window.venueTypes[venue.type.value].color,});} 15const marker=new google.maps.marker.AdvancedMarkerElement({map:map,position:exhibition.location,content:$content.get(0),});marker.typ=MARKER_TYPE_EXHIBITION;marker.zawVenue=venue;marker.zawExhibition=exhibition;marker.zawLocation=zawLocation;mapMarkersByLocation[marker.zawLocation.locationID]=marker;addMarker(marker);return marker;} 16function addEventMarker(event){const $content=$("<div>");$content.addClass("marp-marker event-marker feat-bg");$content.css({opacity:1,});const marker=new google.maps.marker.AdvancedMarkerElement({map:map,position:event.location,content:$content.get(0),});marker.typ=MARKER_TYPE_EVENT;marker.zawEvent=event;marker.zawLocation=buildEventZawLocation(event);mapMarkersByLocation[marker.zawLocation.locationID]=marker;addMarker(marker);return marker;} 17function addMarker(marker){marker.addListener("mouseover",function(){focusUiZawLocation(marker);});marker.addListener("mouseout",function(){$(".zaw-location").removeClass("focused");});marker.addListener("gmp-click",function(){focusMarker(marker);showInfowindow(marker);});allMarkers.push(marker);marker.zIndex=allMarkers.length;} 18let openedInfoWindow=null;function showInfowindow(marker){closeCurrentInfoWindow();const headerContent=marker.typ;const isAddedToRoute=$(`.zaw-location[data-location-id="${marker.zawLocation.locationID}"]`).length>0;const templateHtml=$(`#zaw_map_${marker.typ.toLowerCase()}_infowindow_template`).html();const content=ejs.render(templateHtml,{isRoutingEnabled:$(".routed-map").length>0,isAddedToRoute,zawLocation:marker.zawLocation,event:marker.typ==MARKER_TYPE_EVENT?marker.zawEvent:undefined,venue:marker.typ==MARKER_TYPE_EXHIBITION?marker.zawVenue:undefined,exhibition:marker.typ==MARKER_TYPE_EXHIBITION?marker.zawExhibition:undefined,});const infoWindow=new google.maps.InfoWindow({headerContent,content,});google.maps.event.addListener(infoWindow,"closeclick",function(){clearMarkersSelection();});infoWindow.open(map,marker);google.maps.event.addListener(infoWindow,"domready",function(){$(".gm-style-iw a").blur();if(marker.zawLocation.isFavourite) 19$(".gm-style-iw").addClass("favourite");});openedInfoWindow=infoWindow;panByRouteControlsOffset(marker.position);} 20function closeCurrentInfoWindow(){if(openedInfoWindow){openedInfoWindow.close();}} 21function eventZawLocationID(event){return`event-${event.slug}-${event.location.place_id}`;} 22function buildEventZawLocation(event){return{locationID:eventZawLocationID(event),googleLocation:event.location,venueName:event.venueName||event.title,streetAddress:`at ${event.location.street_name} ${event.location.street_number}`,isFavourite:zaw.getFavouriteEntry("events",event.slug)?true:false,};} 23function exhibitionZawLocationID(venue,exhibition){return`exhibition-${venue.slug}-${exhibition.location.place_id}`;} 24function buildExhibitionZawLocation(venue,exhibition){return{locationID:exhibitionZawLocationID(venue,exhibition),googleLocation:exhibition.location,venueName:venue.title,streetAddress:`at ${exhibition.location.street_name} ${exhibition.location.street_number}`,isFavourite:zaw.getFavouriteEntry("exhibitions",venue.slug)?true:false,};} 25function addTheMarkers(){var bounds=null;var activeMarker=null;var events=window.mapEvents;if(events&&events.length>0){for(const event of events){randomizeGeoposition(event.location);var marker=addEventMarker(event);if(event.is_selected){activeMarker=marker;} 26if(!bounds){bounds=new google.maps.LatLngBounds(event.location,event.location);} 27bounds.extend(event.location);}}
28var venues=window.mapVenues;if(venues&&venues.length>0){for(const venue of venues){mapVenuesBySlug[venue.slug]=venue;for(var j=0;j<venue.exhibitions.length;j++){const exhibition=venue.exhibitions[j];if(!exhibition.location){console.error("No location for exhibition of venue "+ 29venue.title+", exhibition artists: "+ 30exhibition.artists);continue;} 31randomizeGeoposition(exhibition.location);const marker=addExhibitionMarker(exhibition,venue);if(!bounds){bounds=new google.maps.LatLngBounds(exhibition.location,exhibition.location);} 32if(venue.is_selected&&j==venue.selected_show_index-1){activeMarker=marker;} 33bounds.extend(exhibition.location);}}} 34setTimeout(function(){if(bounds&&allMarkers.length>1){map.fitBounds(bounds);} 35if(activeMarker){focusMarker(activeMarker,true);showInfowindow(activeMarker);}},300);} 36function fitMarkerBounds(markers){if(!markers||markers.length==0){return;} 37var bounds=null;for(var i=0;i<markers.length;i++){var markerLocation=markers[i].position;if(!bounds){bounds=new google.maps.LatLngBounds(markerLocation,markerLocation);} 38bounds.extend(markerLocation);} 39map.fitBounds(bounds);} 40function initGeolocation(forseDetection,callback){if(!forseDetection&&sessionStorage.getItem("geolocationAskedAlready")=="yes"){return;} 41var myLocationUpdateInterval=3*60*1000;var myLocationUpdatedAt=sessionStorage.getItem("myLocationUpdatedAt");if(myLocationUpdatedAt&&Date.now()-parseInt(myLocationUpdatedAt)<myLocationUpdateInterval){initMyLocation(getMyLocationFromSession());if(callback){callback(true);}}else{var infoWindow=new google.maps.InfoWindow({map:map});if(navigator.geolocation){navigator.geolocation.getCurrentPosition(function(position){var myLocation={lat:position.coords.latitude,lng:position.coords.longitude,};sessionStorage.setItem("myLocationUpdatedAt",Date.now());sessionStorage.setItem("myLocationLatLng",JSON.stringify(myLocation));initMyLocation(myLocation);sessionStorage.setItem("geolocationAskedAlready","yes");if(callback){callback(true);}},function(){console.error("Error: The Geolocation service failed.");sessionStorage.setItem("geolocationAskedAlready","yes");if(callback){callback(false);}});}else{console.error("Error: Your browser doesn't support geolocation.");if(callback){callback(false);}}}} 42function getMyLocationFromSession(){var myLocation=sessionStorage.getItem("myLocationLatLng");return JSON.parse(myLocation);} 43function clearRoutingCache(){delete zaw.mapRoute.cached;zaw.saveMapRoute();} 44function calcAndRenderRoute(optimizeWaypointOrder=false,fitBounds=false,callback){if((zaw.mapRoute?.zawLocations?.length||0)<2){if(currentRoutePolyline){currentRoutePolyline.setMap(null);currentRoutePolyline=null;} 45return;} 46const renderRoute=(encodedPolyline)=>{if(currentRoutePolyline){currentRoutePolyline.setMap(null);} 47switch(zaw.mapRoute.travelMode){case"WALK":currentRoutePolyline=new google.maps.Polyline({path:google.maps.geometry.encoding.decodePath(encodedPolyline),geodesic:true,strokeOpacity:0,icons:[{icon:{path:"M 0,0 0,0",fillColor:"#0021f3",fillOpacity:1,strokeColor:"#0021f3",strokeOpacity:1,scale:7,},offset:"0",repeat:"12px",},],map:map,});break;case"BICYCLE":currentRoutePolyline=new google.maps.Polyline({path:google.maps.geometry.encoding.decodePath(encodedPolyline),geodesic:true,strokeOpacity:1,strokeWeight:3,strokeColor:"#0021f3",map:map,});break;case"DRIVE":case"BICYCLE":default:currentRoutePolyline=new google.maps.Polyline({path:google.maps.geometry.encoding.decodePath(encodedPolyline),geodesic:true,strokeOpacity:1,strokeWeight:5,strokeColor:"#0021f3",map:map,});break;} 48if(fitBounds){const routeMarkers=zaw.mapRoute.zawLocations.map((zl)=>getMarkerByLocationID(zl.locationID));google.maps.event.addListenerOnce(map,"idle",function(){fitMarkerBounds(routeMarkers);});}};const cached=zaw.mapRoute.cached;let useCached=cached;if(useCached)useCached=cached.travelMode==zaw.mapRoute.travelMode;if(useCached)useCached=!optimizeWaypointOrder||cached.optimized;if(useCached)zaw.mapRoute.cached?.travelMode==zaw.mapRoute.travelMode;if(useCached){const newIds=zaw.mapRoute.zawLocations.map((l)=>l.locationID);const cachedIds=zaw.mapRoute.cached.locationIds.slice();if(cached.optimized){newIds.sort();cachedIds.sort();} 49useCached=JSON.stringify(newIds)==JSON.stringify(cachedIds);} 50if(useCached){console.log("Rendering cached route");renderRoute(zaw.mapRoute.cached.encodedPolyline);if(callback)callback();return;}else{console.log("Fetching new route poliline");} 51const copiedLocations=zaw.mapRoute.zawLocations.slice();const origin=copiedLocations.shift().googleLocation;const destination=copiedLocations.pop().googleLocation;const waypoints=copiedLocations.map((zl)=>({location:{latLng:{latitude:zl.googleLocation.lat,longitude:zl.googleLocation.lng,},},}));const requestBody={origin:{location:{latLng:{latitude:origin.lat,longitude:origin.lng}},},destination:{location:{latLng:{latitude:destination.lat,longitude:destination.lng},},},intermediates:waypoints,travelMode:zaw.mapRoute.travelMode,optimizeWaypointOrder,};fetch(`https://routes.googleapis.com/directions/v2:computeRoutes?key=${googleMapsApiKey}`,{method:"POST",headers:{"Content-Type":"application/json","X-Goog-FieldMask":"routes.distanceMeters,routes.duration,routes.polyline,routes.optimized_intermediate_waypoint_index",},body:JSON.stringify(requestBody),}).then((response)=>response.json()).then((data)=>
51{if(!data.routes||data.routes.length===0){console.error("No route found");if(callback)callback();return;} 52const route=data.routes[0];if(optimizeWaypointOrder&&zaw.mapRoute.zawLocations.length>3&&route.optimizedIntermediateWaypointIndex?.length==zaw.mapRoute.zawLocations.length-2){const unorderedLocations=zaw.mapRoute.zawLocations;zaw.mapRoute.zawLocations=[unorderedLocations.shift()];for(const oldIndex of route.optimizedIntermediateWaypointIndex){zaw.mapRoute.zawLocations.push(unorderedLocations[oldIndex]);} 53zaw.mapRoute.zawLocations.push(unorderedLocations.pop());} 54zaw.mapRoute.cached={travelMode:zaw.mapRoute.travelMode,optimized:optimizeWaypointOrder,locationIds:zaw.mapRoute.zawLocations.map((l)=>l.locationID),encodedPolyline:route.polyline.encodedPolyline,};zaw.saveMapRoute(false);renderRoute(route.polyline.encodedPolyline);}).catch((error)=>console.error("Error fetching route:",error)).finally(()=>{if(callback)callback();});} 55function initMyLocation(myLocation){} 56function initTheRouting(){if($(".routed-map").length==0){return;} 57zaw.loadMapRoute();const autogen=!zaw.mapRoute.frozenLocations;if(autogen){const favs=window.zaw.getWeekendFavourites();const favLocations=[];(favs.exhibitions||[]).map((fav)=>mapVenuesBySlug[fav.ID]).filter((venue)=>venue?.location).forEach((venue)=>{venue.exhibitions.forEach((exhibition)=>{const locationID=exhibitionZawLocationID(venue,exhibition);const marker=getMarkerByLocationID(locationID);if(marker)favLocations.push(marker.zawLocation);});});zaw.mapRoute.zawLocations=favLocations.filter((lc,index,self)=>self.findIndex((o)=>o.streetAddress===lc.streetAddress)===index).slice(-MAX_ZAW_LOCATIONS);} 58zaw.mapRoute.travelMode||="WALK";calcAndRenderRoute(autogen,true,updateZawLocationsUI);$(".zaw-locations").sortable({placeholder:"zl-drop-placeholder",start:function(event,ui){ui.item.addClass("focused");},stop:function(event,ui){ui.item.removeClass("focused");},update:function(event,ui){refreshRoutingViewAfterUiChange(true,true);},});$("body").on("click",".zloc-remove",function(){$(this).closest(".zaw-location").remove();refreshRoutingViewAfterUiChange(true,true);});let lastFocusedMarker=null;$(".zaw-locations").mouseenter(()=>(lastFocusedMarker=currentFocusedMarker));$(".zaw-locations").mouseleave(()=>{if(lastFocusedMarker){focusMarker(lastFocusedMarker,false);lastFocusedMarker=null;}else{blurAllMarkers();}});$("body").on("mouseenter",".zaw-location",function(){const marker=getMarkerByLocationID($(this).data("location-id"));focusMarker(marker,false);});$(".ctr-calltoaction").click(()=>$(".rmp-controls").removeClass("collapsed"));$(".collapse-route-controls").click(()=>$(".rmp-controls").addClass("collapsed"));$("body").on("click",".zloc-venue-details",function(){const locationID=$(this).closest(".zaw-location").data("location-id");if(!locationID)return;const marker=getMarkerByLocationID(locationID);if(!marker)return;focusMarker(marker,true);showInfowindow(marker);});$(`.travel-mode[data-mode="${zaw.mapRoute.travelMode}"]`).addClass("selected");$(".travel-mode").click(function(){$(".travel-mode").removeClass("selected");$(this).addClass("selected");refreshRoutingViewAfterUiChange(false,true);});$(".optimize-route").click(function(){calcAndRenderRoute(true,false,(res)=>{updateZawLocationsUI();zaw.saveMapRoute(true);});updateZawLocationsUI();});if(zaw.mapRoute.hideNonRoute){$(".show-hide-non-route").addClass("hiding");} 59$(".show-hide-non-route").click(function(){$(this).toggleClass("hiding");zaw.mapRoute.hideNonRoute=$(this).is(".hiding");zaw.saveMapRoute();showHideNonRouteMarkers();});$("body").on("click",".map-infowindow .add-to-route-btn",function(){const canAddToRoute=zaw.mapRoute.zawLocations.length<=MAX_ZAW_LOCATIONS;if(!canAddToRoute){$(".zaw-map-cannot-add-to-route").dialog({modal:true,appendTo:".weekends-map",});return;} 60const marker=getMarkerByLocationID($(this).closest(".map-infowindow").data("location-id"));zaw.mapRoute.zawLocations||=[];zaw.mapRoute.zawLocations.push(marker.zawLocation);updateZawLocationsUI();refreshRoutingViewAfterUiChange(true,true);closeCurrentInfoWindow();});$("body").on("click",".map-infowindow .remove-from-route-btn",function(){const marker=getMarkerByLocationID($(this).closest(".map-infowindow").data("location-id"));zaw.mapRoute.zawLocations||=[];const locationIndex=zaw.mapRoute.zawLocations.findIndex((item)=>item.locationID===marker.zawLocation.locationID);if(locationIndex!==-1){zaw.mapRoute.zawLocations.splice(locationIndex,1);} 61updateZawLocationsUI();refreshRoutingViewAfterUiChange(true,true);closeCurrentInfoWindow();});let qrCodeObj;$(".open-full-navigation").click(()=>{$(".zaw-map-navigation-dialog").dialog({modal:true,classes:{"ui-dialog":"full-nav-dialog"},appendTo:".weekends-map",open:function(){$dialog=$(this);const mapUrl=generateRouteGoogleMapUrl();$dialog.find("a.open-navigation-directly").attr("href",mapUrl);$(".ui-widget-overlay").addClass("feat-bg").click(()=>{$(".zaw-map-navigation-dialog").dialog("close");});const qrElm=$dialog.find(".qrcode").get(0);if(qrCodeObj){qrCodeObj.clear();qrCodeObj.makeCode(mapUrl);}else{qrCodeObj=new QRCode(qrElm,{text:mapUrl,width:270,height:270,colorDark:"#000000",colorLight:"#ffffff",correctLevel:QRCode.CorrectLevel.L,});}},});});}
62function showHideNonRouteMarkers(){allMarkers.forEach((marker)=>{const isAddedToRoute=$(`.zaw-location[data-location-id="${marker.zawLocation.locationID}"]`).length>0;const $markerElm=$(marker.content);if(!isAddedToRoute&&zaw.mapRoute.hideNonRoute){$markerElm.css("display","none");}else{$markerElm.css("display","");}});} 63function generateRouteGoogleMapUrl(){const url=new URL("https://www.google.com/maps/dir/?api=1");const waypoints=[],waypointIds=[];zaw.mapRoute.zawLocations.forEach((loc,index)=>{const place=loc.venueName;const placeId=loc.googleLocation.place_id;if(index==0){url.searchParams.set("origin",place);url.searchParams.set("origin_place_id",placeId);return;} 64if(index==zaw.mapRoute.zawLocations.length-1){url.searchParams.set("destination",place);url.searchParams.set("destination_place_id",placeId);return;} 65waypoints.push(place);waypointIds.push(placeId);});if(waypoints.length>0){url.searchParams.set("waypoints",waypoints.join("|"));url.searchParams.set("waypoint_place_ids",waypointIds.join("|"));} 66url.searchParams.set("travelmode",{WALK:"walking",BICYCLE:"bicycling",DRIVE:"driving",}[zaw.mapRoute.travelMode]);return url.toString();} 67function refreshRoutingViewAfterUiChange(freezeLocations=false,refreshRouteCache=false){if(refreshRouteCache)clearRoutingCache();zaw.mapRoute.travelMode=$(".travel-mode.selected").data("mode")||"WALK";const udpatedZawLocations=[];$(".zaw-location").each(function(){const marker=getMarkerByLocationID($(this).data("location-id"));udpatedZawLocations.push(marker.zawLocation);});zaw.mapRoute.zawLocations=udpatedZawLocations;calcAndRenderRoute(false,false);zaw.saveMapRoute(freezeLocations);} 68function updateZawLocationsUI(){$("ul.zaw-locations").html("");for(const zawLocation of zaw.mapRoute.zawLocations){const html=ejs.render($("#zaw_map_location_template").html(),zawLocation);$("ul.zaw-locations").append($(html));} 69showHideNonRouteMarkers();} 70function focusUiZawLocation(marker){$(".zaw-location").removeClass("focused");$(`.zaw-location[data-location-id="${marker.zawLocation.locationID}"]`).addClass("focused");} 71window.initMap=()=>{if(!window.google){console.log("Skipping map initialization, no Google library was loaded.");return;} 72if($("#googlemaps").length==0){return;} 73const map=new google.maps.Map($("#googlemaps").get(0),{mapId:"3f3d5d6ee66c0b31",zoom:OVERVIEW_ZOOM,streetViewControl:false,scaleControl:true,mapTypeId:google.maps.MapTypeId.ROADMAP,mapTypeControl:false,fullscreenControl:false,center:new google.maps.LatLng(47.3667,8.55),});window.map=map;initGeolocation(true);addTheMarkers();initTheRouting();};jQuery(document).ready(function($){if(!zaw.isSmallScreen())$(".rmp-controls").removeClass("collapsed");$("[pan-to-location]").on("click",function(){var locationAttrs=$(this).attr("pan-to-location").split(",");var location={lat:parseFloat(locationAttrs[0]),lng:parseFloat(locationAttrs[1]),};function panToLocation(){setTimeout(function(){var marker=findMarker(location);if(marker&&myLocationMarker){fitMarkerBounds([myLocationMarker,marker]);map.setZoom(map.getZoom()-1);}else{map.panTo(location);map.setZoom(15);} 74if(marker){focusMarker(marker);showInfowindow(marker);var offsetY=0;if($(".header_title_mobile")){offsetY+=$(".header_title_mobile").outerHeight()+ 75$(".back-to-overview").outerHeight()*1.2;}else if($("#footer_section").is(":visible")){offsetY-=$("#footer_section").height();} 76offsetY=offsetY?offsetY:0;map.panBy(0,-offsetY);}},100);} 77if(!myLocationMarker){initGeolocation(true,panToLocation);}else{panToLocation();}});$("body").on("click","[map-view-initiator]",function(){$("body").addClass("map-view");$("#page-background").removeClass("page-cover");$(".map-view").removeClass("hidden");});$("body").on("click","[map-view-closer]",function(){$("body").removeClass("map-view");$("#page-background").addClass("page-cover");$(".map-view").addClass("hidden");});});})();
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.