"use strict"; // Variables for global usage const zLevelHide = 16; const zoomLevelToRotate = 19; const mapRotateDegrees = 90; let disableClicks = false; let lotAndFloorplanData = {}; const baseUrl = 'https://jekyllseasideretreat.com/'; // Replace with your actual domain const theme = 'seasideretreat'; let map; let salesCenterLat = 31.040952; let salesCenterLng = -81.414055; const initialZoom = 11; const targetZoom = 17.8; const animationDelay = 1000; const cookieName = "mapZoomPlayed"; let zoomLevel = initialZoom; let sitePlanOverlay; // Declare globally function initMap() { const centerLat = 31.03988; const centerLng = -81.41382; const mapCenter = new google.maps.LatLng(centerLat, centerLng); const siteSVG = document.querySelector('#siteplanSVG'); const siteMapBounds = new google.maps.LatLngBounds( new google.maps.LatLng(31.0384, -81.41474), new google.maps.LatLng(31.04132, -81.41264) ); const mapOptions = { zoom: initialZoom, center: mapCenter, scrollwheel: false, mapTypeControl: true, fullscreenControl: false, streetViewControl: false, mapId: 'ae63ecc734886ff6' }; map = new google.maps.Map(document.getElementById('map_canvas_full'), mapOptions); class sitePlanSVGOverlay extends google.maps.OverlayView { constructor(bounds, svg, map) { super(); this.bounds = bounds; this.svg = svg; this.map = map; this.setMap(map); } onAdd() { const panes = this.getPanes(); panes.overlayMouseTarget.appendChild(this.svg); this.svg.style.display = 'block'; this.svg.style.position = 'absolute'; this.svg.style.zIndex = 10; this.attachEvents(); } attachEvents() { const lotElements = this.svg.querySelectorAll('[id*="Lot"]'); lotElements.forEach(el => { el.addEventListener('click', (e) => { handleLotClick(e, el); }); el.addEventListener('mouseover', (e) => { handleLotMouseOver(e, el); }); el.addEventListener('mouseout', (e) => { handleLotMouseOut(e, el); }); // Optional: Update tooltip position on mouse move el.addEventListener('mousemove', (e) => { updateTooltipPosition(e); }); }); } draw() { const projection = this.getProjection(); const sw = projection.fromLatLngToDivPixel(this.bounds.getSouthWest()); const ne = projection.fromLatLngToDivPixel(this.bounds.getNorthEast()); Object.assign(this.svg.style, { left: `${sw.x}px`, top: `${ne.y}px`, width: `${ne.x - sw.x}px`, height: `${sw.y - ne.y}px` }); } show() { this.svg.style.display = 'block'; } hide() { this.svg.style.display = 'none'; } } sitePlanOverlay = new sitePlanSVGOverlay(siteMapBounds, siteSVG, map); handleMapEvents(map, sitePlanOverlay); addTreesOverlay(); addMapKeyOverlay(); if (!getCookie(cookieName)) { setTimeout(() => { animateZoom(zoomLevel, targetZoom); }, animationDelay); setCookie(cookieName, "true", 5); // Set the cookie for 5 days } else { map.setZoom(targetZoom); } } function animateZoom(currentZoom, finalZoom) { let zoom = currentZoom; // Create an interval to increase the zoom level gradually const interval = setInterval(() => { if (zoom >= finalZoom) { clearInterval(interval); } else { zoom += .1; // Increment the zoom value (Adjust for smoother/slower zoom) map.setZoom(Math.round(zoom)); } }, 100); // Adjust interval time for the desired animation speed } function stepZoom() { if (zoomLevel >= targetZoom) { map.setZoom(targetZoom); } else { zoomLevel += 0.05; // Increment the zoom value for smoother zoom map.setZoom(Math.round(zoomLevel)); requestAnimationFrame(stepZoom); } } function loadGoogleMapsAPI() { const apiKey = 'AIzaSyAwiTTETlNIim29ien_PiMWP30pnXKNAoc'; // Replace with your actual Google Maps API key const script = document.createElement('script'); script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&callback=initMap&loading=async`; script.async = true; script.defer = true; document.head.appendChild(script); } if (typeof google === 'undefined' || typeof google.maps === 'undefined') { loadGoogleMapsAPI(); } else { initMap(); } function handleMapEvents(map, overlay) { google.maps.event.addListener(map, 'zoom_changed', () => { const zoomLevel = map.getZoom(); console.log('zoomLevel',zoomLevel); /*if (zoomLevel >= zLevelHide) { overlay.show(); } else { overlay.hide(); }*/ }); } async function getLotsAndFloorplans(phase = 0) { try { const url = new URL(`${baseUrl}/themes/${theme}/modules/siteplan/siteplan.cfc?method=getLotsAndFloorplans`); url.searchParams.append('phase', phase); const response = await fetch(url.toString(), { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const lot_data = await response.json(); return lot_data; } catch (error) { console.error('Failed to fetch lots and floorplans:', error); return null; } } getLotsAndFloorplans().then(data => { lotAndFloorplanData = JSON.parse(data); setLotStatus(); }).catch(error => { console.error('Error fetching data:', error); }); function setLotStatus() { console.log('lotAndFloorplanData',lotAndFloorplanData); lotAndFloorplanData.lots.forEach(lot => { $('#Lot' + lot.lotNumber).addClass(lot.lotSalesStatus); $('#Lot' + lot.lotNumber).attr('data-status', lot.lotSalesStatus); }); // Attach events after lot status is set /*if (sitePlanOverlay) { sitePlanOverlay.attachEvents(); }*/ } function handleLotClick(e, element) { e.stopPropagation(); if (!disableClicks) { createAndShowLotModal(element.id); } } function createAndShowLotModal(lotNumber) { const lotInfo = getLotByNumber(lotAndFloorplanData, lotNumber.replace('Lot', '')); if (lotInfo) { console.log('lotInfo',lotInfo); const lotSize = Number(lotInfo.lotSize).toLocaleString(); const salesStatus = ''; $('.modal').remove(); let modalContent = `
Home Site

${lotInfo.lotNumber}

${ formatStatus( lotInfo.lotSalesStatus )}
`; if (lotInfo.lotPriceOverride > 0) { modalContent += `
Lot/Home From

${ formatPrice( lotInfo.lotPriceOverride )}

` } modalContent += `

Floor Plans

Available for Home Site ${lotInfo.lotNumber}
${generateFloorPlanCards(lotInfo)}
`; const modalHtml = ` `; $('body').append(modalHtml); $('#lotModal').modal('show'); } } function generateFloorPlanCards(lotInfo) { let floorPlanRow = ``; lotInfo.lotFloorPlans.forEach(plan => { if (plan != null) { const heatedSqFt = Number(plan.floorHeatedSqFt).toLocaleString(); const totalSqFt = plan.floorTotalSqFt ? Number(plan.floorTotalSqFt).toLocaleString() : 0; let cardHtml = `
${plan.floorPlanName}
${plan.floorPlanName}
${heatedSqFt} Heated SqFt ${totalSqFt != '' ? `| ${totalSqFt} Total SqFt` : ``}
  • ${plan.floorPlanBeds} Beds
  • ${plan.floorPlanBaths} Baths
  • ${plan.floorPlanHalfBaths} Half Bath
  • ${plan.floorPlanStories} Stories
`; if (lotInfo.showLotHomePrice) { cardHtml += `
From ${ currency(plan.lotAndHomePrice, {precision: 0}).format() }
`; } cardHtml += `
`; floorPlanRow += cardHtml; } }); return floorPlanRow; } // Add event listener once for floor plan buttons $(document).on('click', '.btn-floor-plan', function (e) { const floorPlanId = $(this).data('floor-plan-id'); createAndShowFloorPlanModal(floorPlanId); }); function createAndShowFloorPlanModal(floorPlanId) { const getFloorPlanDetails = getFloorPlanById(lotAndFloorplanData, floorPlanId); if (getFloorPlanDetails) { $('.floorplan-modal').remove(); const heatedSqFt = Number(getFloorPlanDetails.floorHeatedSqFt).toLocaleString(); let floorPlanDetailsNoPriceHTML = `
`; const floorPlanDetailsHTML = `
`; $('body').append(floorPlanDetailsNoPriceHTML); $('#floorPlanModal').modal('show'); $('#floorPlanModal').on('click', '.close', function () { $('#floorPlanModal').modal('hide'); }); } } function getLotByNumber(data, lotNumber) { const lots = data.lots; for (let lot of lots) { if (lot.lotNumber === lotNumber) { return lot; } } return null; } function getFloorPlanById(data, floorPlanId) { for (let lot of data.lots) { for (let floorPlan of lot.lotFloorPlans) { if (floorPlan.floorPlanID === floorPlanId) { return floorPlan; } } } return null; } function addTreesOverlay() { var srcImage = `/themes/${theme}/modules/siteplan/images/tree-group.svg`; const treeBounds = new google.maps.LatLngBounds( new google.maps.LatLng(31.037261, -81.418090), // Southwest corner new google.maps.LatLng(31.043824, -81.413144) // Northeast corner ); let treesOverlay = new google.maps.GroundOverlay(srcImage,treeBounds); treesOverlay.setMap(map); google.maps.event.addListenerOnce(map, 'idle', function(){ treesOverlay.setOptions({ zIndex: 1000 }); }); }//// end addTreesOverlay function addMapKeyOverlay() { let srcImage = `/themes/${theme}/modules/siteplan/images/map-key.svg`; const mapKeyBounds = new google.maps.LatLngBounds( new google.maps.LatLng(31.038359, -81.413328), // Southwest corner new google.maps.LatLng(31.039054, -81.412435) // Northeast corner ); let mapKeyOverlay = new google.maps.GroundOverlay(srcImage,mapKeyBounds); mapKeyOverlay.setMap(map); google.maps.event.addListenerOnce(map, 'idle', function(){ mapKeyOverlay.setOptions({ zIndex: 1000 }); }); }//// end addTreesOverlay function displayMapInfo(info) { const div = document.getElementById('map-info'); console.log(div); if (div != null){ div.innerHTML += info + '
'; } } ///// helpers function formatPrice(num) { if (num >= 1000000) { // Number is at least 1 million let millions = num / 1000000; let rounded = millions.toFixed(1); return `$${rounded} M`; } else if (num >= 100000) { // Number is between 100,000 and 999,999 let thousands = Math.floor(num / 1000); let rounded = Math.floor(thousands / 10) * 10; return `$${rounded} K`; } else { // For numbers less than 100,000, output the exact number with a dollar sign return `$${num}`; } } function formatStatus(status) { return status.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); } ///// cookies function setCookie(name, value, days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); const expires = "expires=" + date.toUTCString(); document.cookie = name + "=" + value + ";" + expires + ";path=/"; } function getCookie(name) { const cname = name + "="; const decodedCookie = decodeURIComponent(document.cookie); const ca = decodedCookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) === ' ') { c = c.substring(1); } if (c.indexOf(cname) === 0) { return c.substring(cname.length, c.length); } } return ""; } //////// tooltip for sales status //////// // Create tooltip div const tooltipDiv = document.createElement('div'); tooltipDiv.id = 'tooltip'; Object.assign(tooltipDiv.style, { position: 'absolute', pointerEvents: 'none', background: 'rgba(0, 0, 0, 0.7)', color: 'white', padding: '3px 6px', borderRadius: '4px', display: 'none', zIndex: '10000', fontSize: '10px' }); document.body.appendChild(tooltipDiv); function handleLotMouseOverORIG(e, element) { e.stopPropagation(); const status = element.getAttribute('data-status') || 'Call Us'; const formattedStatus = formatStatus(status); showTooltip(e, formattedStatus); } function handleLotMouseOver(e, element) { e.stopPropagation(); let status = element.getAttribute('data-status'); if (!status) { // If data-status is not yet set, default to a placeholder or fetch the status dynamically if possible status = 'Status Loading...'; } else { status = formatStatus(status); } const formattedStatus = formatStatus(status); showTooltip(e, formattedStatus); } function handleLotMouseOut(e, element) { e.stopPropagation(); hideTooltip(); } function showTooltip(e, status) { tooltipDiv.innerHTML = status; const mouseX = e.pageX; const mouseY = e.pageY; tooltipDiv.style.left = (mouseX + 10) + 'px'; tooltipDiv.style.top = (mouseY + 10) + 'px'; tooltipDiv.style.display = 'block'; } function hideTooltip() { tooltipDiv.style.display = 'none'; } // Optional: Update tooltip position on mouse move function updateTooltipPosition(e) { const mouseX = e.pageX; const mouseY = e.pageY; tooltipDiv.style.left = (mouseX + 10) + 'px'; tooltipDiv.style.top = (mouseY + 10) + 'px'; }