"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 = `
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}
${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 = `
`;
if (getFloorPlanDetails.lotAndHomePrice > 0) {
floorPlanDetailsNoPriceHTML += `
From ${ currency(getFloorPlanDetails.lotAndHomePrice, {precision: 0}).format() }
`;
} else {
//floorPlanDetailsNoPriceHTML += `
Call For Price
`;
}
floorPlanDetailsNoPriceHTML += `
${getFloorPlanDetails.floorPlanName}
${getFloorPlanDetails.floorPlanBeds ? `- ${getFloorPlanDetails.floorPlanBeds} Beds
` : ''}
${getFloorPlanDetails.floorPlanBaths ? `- ${getFloorPlanDetails.floorPlanBaths} Baths
` : ''}
${getFloorPlanDetails.floorPlanHalfBaths ? `- ${getFloorPlanDetails.floorPlanHalfBaths} Half Baths
` : ''}
${getFloorPlanDetails.floorPlanStories ? `- ${getFloorPlanDetails.floorPlanStories} Stories
` : ''}
${heatedSqFt ? `- ${heatedSqFt} Heated SqFt
` : ''}
${getFloorPlanDetails.floorPlanDetails}
`;
const floorPlanDetailsHTML = `
${getFloorPlanDetails.floorBasePrice > 0 ? `
Starting at $${getFloorPlanDetails.floorBasePrice}
` : `
Call For Price
`}
${getFloorPlanDetails.floorPlanName}
${getFloorPlanDetails.floorPlanBeds ? `- ${getFloorPlanDetails.floorPlanBeds} Beds
` : ''}
${getFloorPlanDetails.floorPlanBaths ? `- ${getFloorPlanDetails.floorPlanBaths} Baths
` : ''}
${getFloorPlanDetails.floorPlanHalfBaths ? `- ${getFloorPlanDetails.floorPlanHalfBaths} Half Baths
` : ''}
${getFloorPlanDetails.floorPlanStories ? `- ${getFloorPlanDetails.floorPlanStories} Stories
` : ''}
${heatedSqFt ? `- ${heatedSqFt} Heated SqFt
` : ''}
${getFloorPlanDetails.floorPlanDetails}
`;
$('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';
}