| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- <?php
- // get data from AWIGO API
- $ch = curl_init('https://www.awigo.de/index.php?id=122');
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
- 'legacy_eID' => 'awigoLocations',
- 'awigo_locations[method]' => 'getLocations',
- 'awigo_locations[lat]' => 52.28,
- 'awigo_locations[lon]' => 8.05,
- 'awigo_locations[v]' => 2,
- 'awigo_locations[format]' => 'json'
- ]));
- $response = curl_exec($ch);
- curl_close($ch);
- $orte = json_decode($response, true);
- $orteJsArray = json_encode($orte, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
- // ### HTML-Response
- $html = '
- <!DOCTYPE html>
- <html lang="de">
- <head>
- <link rel="stylesheet" href="https://area51.cybob.com/praktikum/daniel/agent/leaflet/leaflet.css">
- <link rel="stylesheet" href="https://area51.cybob.com/praktikum/daniel/agent/css/map.css">
- <script src="https://area51.cybob.com/praktikum/daniel/agent/leaflet/leaflet.js"></script>
- </head>
- <body>
- <div id="map-wrapper">
- <div id="zipcode-search-wrapper">
- <div class="input-with-clear">
- <input
- type="input"
- id="zipcode-input"
- placeholder="PLZ"
- inputmode="numeric"
- list="zipcode-datalist"
- maxlength="5"
- autocomplete="true"
- />
- <button id="zipcode-search-close" type="button" aria-label="Eingabe löschen">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
- <line x1="1" y1="1" x2="15" y2="15" stroke="currentColor" stroke-width="2"/>
- <line x1="15" y1="1" x2="1" y2="15" stroke="currentColor" stroke-width="2"/>
- </svg>
- </button>
- </div>
- <button id="zipcode-search-button" type="button">🔍</button>
- </div>
- <datalist id="zipcode-datalist"></datalist>
-
- <div id="map-info">
- <button id="map-info-close" aria-label="Schließen" title="Schließen">
- <img src="https://area51.cybob.com/praktikum/daniel/agent/images/x.svg" alt="Schließen"/>
- </button>
- <a id="map-link" href="#" target="_blank" title="In Google Maps öffnen" style="display:inline-flex;align-items:center;gap:4px;">
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" class="input-close">
- <path d="M4.146 8.354a.5.5 0 0 1 0-.708L9.793 2H6.5a.5.5 0 0 1 0-1h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V2.707L4.854 8.854a.5.5 0 0 1-.708 0z"/>
- <path d="M13.5 14a.5.5 0 0 1-.5.5H3a2 2 0 0 1-2-2V3.5a.5.5 0 0 1 1 0V12.5a1 1 0 0 0 1 1h10a.5.5 0 0 1 .5.5z"/>
- </svg>
- <span>Google Maps</span>
- </a>
-
- <h4 id="map-info-title">Bitte einen Ort auswählen!</h4>
- <span id="map-info-street"></span><br>
- <span id="map-info-plz"></span><br>
- <span><a id="map-info-telephone"></a></span><br>
- <br>
-
- <div id="map-info-opening-hours-weekdays"></div>
- <div id="map-info-description"></div>
- </div>
- <div id="map"></div>
- </div>
- <script>
- // ### Default is in Osnabrueck ###
- const defaultView = {
- lat: 52.2799,
- lng: 8.0472,
- zoom: 9,
- zoomClose: 16
- };
-
- // ### Default Offset for compact view ###
- const LAT_OFFSET = 0.0011;
- const MIN_DEVIATION = 0.00003;
- const COMPACT_THRESHOLD = 500; // px
-
- // ### State Memory ###
- const mapState = {
- isZoomed: false,
- isDragging: false,
- isCompact: false
- };
-
- // ### Leaflet Map Object ###
- let map = null;
-
- // ### Markers with queried json info (ort) ###
- let markers = [];
-
- function hideMarkers(markers) {
- markers.forEach(marker => {
- const markerElement = marker.getElement();
- const shadow = marker._shadow;
- if (markerElement) {
- markerElement.style.display = "none";
- }
- if (shadow) {
- shadow.style.display = "none"
- }
- })
- }
-
- function hideMarkerShadows(markers) {
- markers.forEach(marker => {
- const shadow = marker._shadow;
- if (shadow) shadow.style.display = "none";
- })
- }
-
- function showMarkers(markers) {
- markers.forEach(marker => {
- const markerElement = marker.getElement();
- if (markerElement) {
- markerElement.style.display = "";
- }
- })
- }
-
- // Close InfoBox with small animation
- function closeInfoBox() {
- const infoBox = document.getElementById("map-info");
- if (!infoBox.classList.contains("active")) {
- return;
- }
- infoBox.classList.remove("active");
- infoBox.classList.add("closing");
- setTimeout(() => {
- infoBox.classList.remove("closing");
- }, 125);
- }
-
- // check for user position => add marker and center map
- function checkUserPosition() {
- if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(function(position) {
- setTimeout(() => {
- userLat = position.coords.latitude;
- userLng = position.coords.longitude;
- map.setView([userLat, userLng], 10);
- map.invalidateSize();
- }, 500)
- }, function(error) {
- console.warn("Geolocation not found");
- });
- } else {
- console.warn("Geolocation not supported by this browser.");
- }
- }
- function loadLeafletScript(callback) {
- var script = document.createElement("script");
- script.src = "https://area51.cybob.com/praktikum/daniel/agent/leaflet/leaflet.js";
- script.onload = callback;
- document.head.appendChild(script);
- console.log("Leaflet script loaded");
- }
- // Fly to LatLng Location with optional offset for compact View
- // Map Marker will then be centered, as the info box with appear from the bottom
- function flyToWithOptionalOffset(latLng, zoom) {
- let newLat = latLng.lat;
- if (mapState.isCompact) {
- newLat -= LAT_OFFSET; // adjust latitude for compact view
- }
- map.flyTo({lat: newLat, lng: latLng.lng}, zoom, {
- animate: true,
- duration: 0.5
- });
- }
-
- function getVisibleMapCenter() {
- const center = map.getCenter().clone();
- if (mapState.isCompact) {
- center.lat -= LAT_OFFSET;
- }
- return center;
- }
-
- function getLogicalMapCenter() {
- let center = map.getCenter().clone();
- if (mapState.isCompact) {
- center.lat += LAT_OFFSET;
- }
- return center;
- }
-
- function updateInfoBox(ort) {
- // replace info box strings
- document.getElementById("map-info-title").innerHTML = ort.title;
- document.getElementById("map-info-description").innerHTML = ort.description || "";
- document.getElementById("map-info-opening-hours-weekdays").innerHTML = ort.openingTimes;
- document.getElementById("map-info-street").innerHTML = ort.address || "";
- document.getElementById("map-info-plz").innerHTML = (ort.zip + " " + ort.city) || "";
- const tel = ort.telephone.replaceAll(" ", "")
- .replaceAll(")", "")
- .replaceAll("(", "")
- .replaceAll("-", "");
- document.getElementById("map-info-telephone").innerHTML = ("Tel.: " + ort.telephone);
- document.getElementById("map-info-telephone").href = "tel:" + tel;
-
- // build & assign google maps url
- const lat = ort.lat;
- const lng = ort.lng;
- document.getElementById("map-link").href = `https://www.google.com/maps?q=${lat},${lng}`;
- }
-
- function showInfoBox() {
- document.getElementById("map-info").classList.add("active");
- }
-
- function isMapDeviationReached(marker) {
- const logicalCenter = getLogicalMapCenter();
- const deltaLat = Math.abs(logicalCenter.lat - marker.getLatLng().lat);
- const deltaLng = Math.abs(logicalCenter.lng - marker.getLatLng().lng);
- return deltaLat >= MIN_DEVIATION || deltaLng >= MIN_DEVIATION;
- }
-
- function initializeMap() {
-
- // initialize the map
- map = L.map("map", {
- zoomAnimation: true,
- markerZoomAnimation: true,
- fadeAnimation: true,
- attributionControl: true,
- }).setView([52.2799, 8.0472], defaultView.zoom);
- L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
- attribution: "© <a href=\\"https://www.openstreetmap.org/copyright\\">OpenStreetMap</a>"
- }).addTo(map);
-
- // Checks with each resize if the map-wrapper is smaller than threshold
- function updateMapLayoutResponsiveness() {
- const mapWrapper = document.getElementById("map-wrapper");
- const mapDiv = document.getElementById("map");
-
- const isCompact = mapWrapper.offsetWidth < COMPACT_THRESHOLD;
- if (isCompact) {
- mapWrapper.classList.add("compact");
- mapDiv.classList.add("compact");
- map.invalidateSize();
- mapState.isCompact = true;
- } else {
- mapWrapper.classList.remove("compact");
- mapDiv.classList.remove("compact");
- mapState.isCompact = false;
- }
- }
- updateMapLayoutResponsiveness();
- window.addEventListener("resize", updateMapLayoutResponsiveness);
- document.getElementById("map").addEventListener("mousedown", () => {
- mapState.isDragging = false;
- })
- document.getElementById("map").addEventListener("mousemove", () => {
- mapState.isDragging = true;
- })
- document.getElementById("map").addEventListener("click", (e) => {
- if (
- e.target.classList.contains("map-info") ||
- e.target.classList.contains("leaflet-marker-icon") ||
- e.target.classList.contains("leaflet-marker-icon") ||
- mapState.isDragging
- ) {
- return;
- }
- closeInfoBox();
- })
- document.getElementById("map-info-close").addEventListener("click", () => {
- closeInfoBox();
- });
- // standard-icon (blue)
- L.Icon.Default.mergeOptions({
- iconRetinaUrl: "awigo-icon-gruenplatz-map.png",
- iconUrl: "awigo-icon-gruenplatz-map.png",
- shadowUrl: "marker-icon-shadow-default.png",
- className: "awigo-marker-icon"
- });
-
- // add marker from json-array
- orte.forEach(function(ort) {
- // remove shadows for AWIGO
- var icon = new L.Icon.Default();
- const marker = L.marker([ort.lat, ort.lng], {icon: icon}).addTo(map);
- marker.ort = ort;
- markers.push(marker);
-
- // Event-Listener for click on marker
- marker.on("click", function() {
- updateInfoBox(ort);
- if (isMapDeviationReached(marker)) {
- showInfoBox();
- flyToWithOptionalOffset(marker.getLatLng(), defaultView.zoomClose);
- mapState.isZoomed = true;
- } else if (mapState.isZoomed){
- flyToWithOptionalOffset({lat: defaultView.lat, lng: defaultView.lng}, defaultView.zoom)
- closeInfoBox();
- mapState.isZoomed = false;
- }
- });
- });
- // re-render map (prevents missing tile issues)
- map.invalidateSize();
- // checkUserPosition();
- hideMarkerShadows(markers);
- }
- // ### Program start ###
- // filter for green places from AWIGO API
- let orte = [];
- orte =' . $orteJsArray . '["Locations"];
- if (orte) {
- orte = orte.filter((ort) => {
- return ort.category.toLowerCase().includes("grün");
- })
- } else {
- console.error("No locations found in the response from AWIGO API.");
- }
-
-
- let zipcodes = [...new Set(orte.map(o => o.zip))].sort();
-
- // Input Select
- const input = document.getElementById("zipcode-input");
- const datalist = document.getElementById("zipcode-datalist");
-
- // add available zipcodes to datalist
- zipcodes.forEach(zip => {
- const option = document.createElement("option");
- option.value = zip;
- datalist.appendChild(option);
- });
-
- function searchByZip(zip) {
- if (!zip || zip.length !== 5 || !/^\d{5}$/.test(zip)) {
- showMarkers(markers);
- return;
- }
-
- const filteredMarkers = markers.filter(marker => marker.ort.zip === zip);
- if (filteredMarkers.length > 0) {
- const firstMarker = filteredMarkers[0];
-
- if (isMapDeviationReached(firstMarker)) {
- flyToWithOptionalOffset(firstMarker.getLatLng(), defaultView.zoomClose);
- mapState.isZoomed = true;
- updateInfoBox(firstMarker.ort);
- showInfoBox();
- }
-
- filteredMarkers.forEach((marker) => {
- hideMarkers(markers);
- showMarkers(filteredMarkers);
- })
- }
- }
-
- input.addEventListener("input", () => {
- input.value = input.value.replace(/\D/g, "").slice(0,5);
- if (input.value.length === 5) {
- searchByZip(input.value);
- } else {
- showMarkers(markers);
- }
- });
-
- document.getElementById("zipcode-search-button").addEventListener("click", () => {
- const zip = input.value.trim();
- searchByZip(zip);
- });
-
- document.getElementById("zipcode-search-close").addEventListener("click", () => {
- input.value = "";
- showMarkers(markers);
- })
-
- // ### callback
- loadLeafletScript(initializeMap);
- </script>
- ';
- // JSON-Response aufbauen
- $dictResponse = [
- "success" => true,
- "status_code" => 200,
- "status_description" => "ok",
- "response" => $html
- ];
- $output = json_encode($dictResponse, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
- header('Content-Type: application/json');
- http_response_code($dictResponse["status_code"]);
- echo $output;
- exit;
|