This commit is contained in:
Roman Pyrih
2026-01-27 15:59:07 +01:00
parent 92248df9d1
commit cecfe792a7

View File

@@ -0,0 +1,341 @@
<?php
$google_map_api = 'AIzaSyD-1SOVhJXr6HREtfmMILvlmV-hml3nxUg';
?>
<div class="main-page" id="places-contact-maps">
<section class="box-1" id="box-map-showrooms" style="position: relative; display: flex; height: 700px;">
<div id="showrooms-sidebar">
<div id="results-list">
<!-- <p>Wpisz miasto</p> -->
</div>
</div>
<div id="map" style="flex-grow: 1; height: 100%;"></div>
<div id="showroom-popup" class="showroom-card--popup">
<div class="showroom-card--popup-wrapper">
<div class="popup--head">
<p class="text">PUNKT SPRZEDAŻY</p>
<p>VIDOK Okna i Drzwi</p>
<span class="close-popup">&times;</span>
</div>
<div class="popup--body">
<div class="popup--body-info">
<div class="info-name"><p></p></div>
<div class="info-time"><p></p></div>
<div class="info-products">
<p>Dostępne produkty</p>
<img src="" alt="">
</div>
<div class="info-contact"><p></p></div>
</div>
</div>
</div>
</div>
</section>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=<?php echo $google_map_api; ?>&libraries=places&callback=initMap" defer></script>
<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>
<script class="footer" type="text/javascript">
let showrooms = [];
const MAX_DISTANCE_KM = 100; // Promień wyszukiwania w kilometrach
let map, markerCluster;
let markers = [];
const mapPointIcon = "https://maps.google.com/mapfiles/ms/icons/yellow-dot.png";
/**
* Fetch showroom data from API
*/
fetch('/api/kontakt-mapa')
.then(response => response.json())
.then(data => {
showrooms = data.data;
})
.catch(error => {
console.error('Error fetching showroom data:', error);
});
/**
* Inicjalizacja mapy Google
*/
function initMap() {
const mapOptions = {
zoom: 6.62,
center: { lat: 52.068, lng: 19.479 },
mapTypeControl: false,
styles: getMapStyles() // Pobieranie stylów z osobnej funkcji
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
// Utworzenie markerów dla wszystkich salonów
renderMarkers();
// Inicjalizacja klastrów (grupowanie markerów)
if (typeof markerClusterer !== 'undefined') {
markerCluster = new markerClusterer.MarkerClusterer({ map, markers });
}
// Inicjalizacja wyszukiwarki
initSearchLogic();
}
/**
* Renderowanie markerów na mapie
*/
function renderMarkers() {
console.log(showrooms);
markers = showrooms.map((item) => {
console.log('item: ', item);
const marker = new google.maps.Marker({
position: { lat: parseFloat(item.position.lat), lng: parseFloat(item.position.lng) },
title: item.city,
icon: mapPointIcon
});
marker.addListener("click", () => openShowroomPopup(item));
return marker;
});
}
/**
* Obsługa wyszukiwania i filtrowania
*/
function initSearchLogic() {
const input = document.getElementById("place");
if (!input) return;
const autocomplete = new google.maps.places.Autocomplete(input);
$('#search-showrooms-form').on('submit', function(e) {
e.preventDefault();
const place = autocomplete.getPlace();
if (place && place.geometry) {
handleLocationSelection(place.geometry.location);
} else {
const address = $(input).val();
if (address.length > 0) {
geocodeAddress(address);
}
}
});
}
/**
* Geokodowanie tekstu na współrzędne
*/
function geocodeAddress(address) {
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: address }, (results, status) => {
if (status === "OK") {
handleLocationSelection(results[0].geometry.location);
} else {
console.error("Geocode failed: " + status);
}
});
}
/**
* Przetwarzanie wybranej lokalizacji
*/
function handleLocationSelection(location) {
map.setCenter(location);
map.setZoom(11);
updateSidebarList(location);
scrollToMap();
}
/**
* Aktualizacja listy salonów w panelu bocznym z uwzględnieniem promienia
*/
function updateSidebarList(location) {
const searchLat = location.lat();
const searchLng = location.lng();
const $resultsContainer = $('#results-list');
// 1. Czyszczenie kontenera
$resultsContainer.empty();
$('#results-list').parent().addClass('has-results');
// 2. Filtrowanie i obliczanie dystansu
let filtered = showrooms
.map(item => ({
...item,
distance: calculateDistance(searchLat, searchLng, item.position.lat, item.position.lng)
}))
.filter(item => item.distance <= MAX_DISTANCE_KM)
.sort((a, b) => a.distance - b.distance);
// 3. Sprawdzenie wyników
if (filtered.length === 0) {
$resultsContainer.append(`<div style="padding:20px; text-align:center;">Nie znaleziono salonów w promieniu ${MAX_DISTANCE_KM} km.</div>`);
return;
}
// 4. Dodawanie elementów za pomocą .append()
filtered.forEach(item => {
const $itemElement = sidebarItem(item);
$resultsContainer.append($itemElement);
});
}
/**
* Generuje bezpieczny i poprawny kod HTML dla pojedynczego elementu listy
*/
function sidebarItem(item) {
const lat = item.position.lat;
const lng = item.position.lng;
const distance = item.distance.toFixed(1);
const itemType = 'SALON SPRZEDAŻY';
console.log('item: ', item);
const $el = `
<div class="sidebar-item" data-lat="${lat}" data-lng="${lng}">
<div class="sidebar-item--wrapper">
<div class="item-type"><span>${itemType}<\/span><\/div>
<div class="item-working-hours">
<p>
${item.data_popup.time}
<\/p>
<\/div>
<div class="item-location">
<p>
${item.data.text}
<\/p>
<\/div>
<div class="item-contact">
<ul>
${renderContacts(item)}
<\/ul>
<\/div>
<\/div>
<\/div>
`;
return $el;
}
function renderContacts(item) {
if (item.contact) {
let html = '';
if (Array.isArray(item.contact.phone)) {
item.contact.phone.forEach(phone => {
html += `
<li>
<img src="/upload/filemanager/icon/iphone.svg" alt="">
<a href="tel:${phone.replace(/\s+/g, '')}">${phone}<\/a>
<\/li>
`;
});
}
if (Array.isArray(item.contact.email)) {
item.contact.email.forEach(email => {
html += `
<li>
<img src="/upload/filemanager/icon/envelope.svg" alt="">
<a href="mailto:${email}">${email}<\/a>
<\/li>
`;
});
}
return html;
}
return '';
}
/**
* Globalna obsługa kliknięcia w elementy listy (Event Delegation)
*/
$(document).on('click', '.sidebar-item', function() {
// Pobieramy współrzędne z atrybutów data-
const lat = $(this).data('lat');
const lng = $(this).data('lng');
$(this).addClass('active').siblings().removeClass('active');
if (lat && lng) {
focusOnMarker(lat, lng);
}
});
/**
* Wyświetlanie szczegółów salonu w popupie
*/
function openShowroomPopup(item) {
const $popup = $('#showroom-popup');
$popup.find('.info-name p').html(item.data_popup.text);
$popup.find('.info-time p').html(item.data_popup.time);
$popup.find('.info-contact p').html(item.data_popup.contact);
$popup.find('.info-products img').attr('src', item.data_popup.products);
// $popup.fadeIn();
$popup.addClass('active');
}
/**
* Funkcje pomocnicze (Nawigacja i Obliczenia)
*/
function focusOnMarker(lat, lng) {
map.setCenter({lat: parseFloat(lat), lng: parseFloat(lng)});
map.setZoom(14);
}
function scrollToMap() {
$('html, body').animate({
scrollTop: $("#box-map-showrooms").offset().top - 120
}, 500);
}
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2);
return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));
}
/**
* Style mapy (Greyscale)
*/
function getMapStyles() {
return [{"featureType":"all","elementType":"all","stylers":[{"saturation":"-100"}]},{"featureType":"administrative","elementType":"all","stylers":[{"saturation":"-100"}]},{"featureType":"landscape","elementType":"all","stylers":[{"saturation":"-100"}]},{"featureType":"landscape.man_made","elementType":"all","stylers":[{"visibility":"on"},{"saturation":"-100"},{"gamma":"1"}]},{"featureType":"poi","elementType":"all","stylers":[{"saturation":"-100"},{"visibility":"simplified"}]},{"featureType":"poi","elementType":"geometry.fill","stylers":[{"saturation":"-100"}]},{"featureType":"poi","elementType":"labels","stylers":[{"visibility":"simplified"}]},{"featureType":"poi","elementType":"labels.text.fill","stylers":[{"saturation":"-100"},{"weight":"6.61"},{"lightness":"0"},{"gamma":"1.5"}]},{"featureType":"poi","elementType":"labels.icon","stylers":[{"saturation":"-100"},{"gamma":"1.5"},{"weight":"0.01"}]},{"featureType":"road","elementType":"labels.icon","stylers":[{"saturation":"-100"}]},{"featureType":"road.highway","elementType":"all","stylers":[{"saturation":"-100"}]},{"featureType":"transit","elementType":"all","stylers":[{"saturation":"-100"}]},{"featureType":"transit","elementType":"labels.text","stylers":[{"saturation":"-100"}]},{"featureType":"transit","elementType":"labels.icon","stylers":[{"saturation":"-100"}]},{"featureType":"water","elementType":"all","stylers":[{"saturation":"-100"}]}];
}
/**
* Uruchomienie po załadowaniu DOM
*/
$(document).ready(function() {
if (typeof google !== 'undefined') {
initMap();
}
$(document).on('click', '.close-popup', function() {
// $('#showroom-popup').fadeOut();
$('#showroom-popup').removeClass('active');
});
});
$(document).ready(function() {
$('body').on('click', '.box-6 .box-info .box-info-right', function(e){
e.preventDefault()
$(this).toggleClass('active')
$('.box-6 .c-row-2').slideToggle()
})
})
</script>