NoPaste

Karte

von uname

SNIPPET_TEXT:
  1. <!DOCTYPE html>
  2. <html lang="de">
  3. <head>
  4.     <meta charset="utf-8" />
  5.     <meta name="viewport" content="width=device-width, initial-scale=1" />
  6.     <title>Karte</title>
  7.     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin="" />
  8.     <style>
  9.         body, html, #map {
  10.             height: 100%;
  11.             margin: 0;
  12.             padding: 0;
  13.         }
  14.  
  15.         .custom-popup .leaflet-popup-content-wrapper {
  16.             background: #fff;
  17.             color: #333;
  18.             font-size: 14px;
  19.             line-height: 24px;
  20.             border-radius: 5px;
  21.             padding: 10px;
  22.             text-align: center;
  23.             max-width: 250px;
  24.         }
  25.  
  26.         .custom-popup .leaflet-popup-content {
  27.             margin: 0;
  28.             display: flex;
  29.             justify-content: center;
  30.             align-items: center;
  31.         }
  32.  
  33.         .crosshair-icon {
  34.             display: block;
  35.             margin: auto;
  36.             width: 24px;
  37.             height: 24px;
  38.         }
  39.  
  40.         .popup-button {
  41.             display: inline-block;
  42.             padding: 4px 8px;
  43.             border-radius: 4px;
  44.             text-decoration: none;
  45.             color: #333;
  46.             font-weight: bold;
  47.             text-align: center;
  48.             transition: background-color 0.3s;
  49.             background-color: #fff;
  50.             border: 1px solid #ccc;
  51.             font-size: 12px;
  52.         }
  53.  
  54.         .actions {
  55.             display: flex;
  56.             justify-content: center;
  57.         }
  58.  
  59.         .locate-button {
  60.             background: white;
  61.             padding: 5px;
  62.             border-radius: 4px;
  63.             cursor: pointer;
  64.             font-size: 20px;
  65.             width: 30px;
  66.             height: 30px;
  67.             line-height: 30px;
  68.             text-align: center;
  69.         }
  70.  
  71.         .number-icon {
  72.             background-color: #3388ff;
  73.             border-radius: 5px;
  74.             border: 2px solid #fff;
  75.             text-align: center;
  76.             color: #fff;
  77.             font-weight: bold;
  78.             font-size: 12px;
  79.             padding: 4px 8px;
  80.             white-space: nowrap;
  81.             min-width: 80px;
  82.             max-width: 120px;
  83.             box-sizing: border-box;
  84.             overflow: hidden;
  85.             text-overflow: ellipsis;
  86.         }
  87.  
  88.         .popup-content h3 {
  89.             margin: 0 0 10px 0;
  90.             font-size: 16px;
  91.             text-align: center;
  92.         }
  93.  
  94.         .popup-content .actions {
  95.             display: flex;
  96.             justify-content: center;
  97.             gap: 10px;
  98.         }
  99.     </style>
  100. </head>
  101. <body>
  102.     <div id="map"></div>
  103.     <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script>
  104.     <script src="https://unpkg.com/leaflet-polylinedecorator@1.6.0/dist/leaflet.polylineDecorator.js"></script>
  105.     <script>
  106.         const locations = [
  107.             { id: "01 Nationalpark Haus Baltrum", latlon: "53.7261269,7.367696" },
  108.             { id: "02 Igelhütte", latlon: "53.7287549,7.40876823" },
  109.             { id: "03 Westbake Baltrum", latlon: "53.7278049,7.36136" },
  110.         ];
  111.  
  112.         function getMapLink(latlon, zoom = 18) {
  113.             const userAgent = navigator.userAgent || navigator.vendor || window.opera;
  114.             if (/android/i.test(userAgent)) {
  115.                 return `geo:${latlon}?z=${zoom}`;
  116.             } else if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
  117.                 return `comgooglemaps://?center=${latlon}&zoom=${zoom}`;
  118.             } else {
  119.                 return `https://maps.google.com/maps?q=${latlon}&z=${zoom}`;
  120.             }
  121.         }
  122.  
  123.         function isMobile() {
  124.             return /Mobi|Android/i.test(navigator.userAgent);
  125.         }
  126.  
  127.         function truncateText(text, maxLength = 20) {
  128.             if (text.length <= maxLength) {
  129.                 return text;
  130.             }
  131.             return text.slice(0, maxLength - 3) + "...";
  132.         }
  133.  
  134.         const map = L.map("map");
  135.         const osmLayer = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
  136.             maxZoom: 19,
  137.             attribution: "© OpenStreetMap",
  138.         }).addTo(map);
  139.  
  140.         const esriLayer = L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", {
  141.             maxZoom: 20,
  142.             attribution: "Tiles © Esri",
  143.         });
  144.  
  145.         L.control.layers({ OSM: osmLayer, "Esri Satellite": esriLayer }).addTo(map);
  146.  
  147.         const bounds = L.latLngBounds();
  148.         const latLngs = [];
  149.  
  150.         locations.forEach(function (location) {
  151.             const [lat, lon] = location.latlon.split(",").map(parseFloat);
  152.             latLngs.push([lat, lon]);
  153.  
  154.             const popupContent = `
  155.                 <div class="popup-content">
  156.                     <h3>${location.id}</h3>
  157.                     <div class="actions">
  158.                         <a href="${getMapLink(location.latlon)}" target="_blank" class="popup-button">
  159.                             <svg viewBox="0 0 24 24" class="crosshair-icon">
  160.                                 <path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3A8.994 8.994 0 0 0 13 3.06V1h-2v2.06A8.994 8.994 0 0 0 3.06 11H1v2h2.06A8.994 8.994 0 0 0 11 20.94V23h2v-2.06A8.994 8.994 0 0 0 20.94 13H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
  161.                             </svg>
  162.                         </a>
  163.                     </div>
  164.                 </div>
  165.             `;
  166.  
  167.  
  168. L.marker([lat, lon], {
  169.     icon: L.divIcon({
  170.         className: "number-icon",
  171.         html: truncateText(location.id),
  172.         iconSize: [Math.max(80, location.id.length * 8), 30],
  173.         iconAnchor: [Math.max(40, location.id.length * 4) / 2, 15],
  174.     }),
  175. })
  176.             .addTo(map)
  177.             .bindPopup(L.popup({
  178.                 maxWidth: 300,
  179.                 closeButton: true,
  180.                 className: "custom-popup"
  181.             }).setContent(popupContent));
  182.  
  183.             bounds.extend([lat, lon]);
  184.         });
  185.  
  186.         map.fitBounds(bounds, { padding:[30,30] });
  187.  
  188.         const polyline = L.polyline(latLngs, { color:"blue" }).addTo(map);
  189.  
  190.         L.polylineDecorator(polyline, {
  191.             patterns:[{
  192.                 offset:"0",
  193.                 repeat:"100",
  194.                 symbol:L.Symbol.arrowHead({
  195.                     pixelSize:"15",
  196.                     polygon:false,
  197.                     pathOptions:{ stroke:true, color:"#3388ff" },
  198.                 }),
  199.             }],
  200.         }).addTo(map);
  201.  
  202.         const locateControl = L.control({ position:"topright" });
  203.  
  204.         locateControl.onAdd = function (map) {
  205.             const div = L.DomUtil.create("div", "locate-button");
  206.             div.innerHTML = `
  207.                 <svg viewBox="0 0 24 24">
  208.                     <path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3A8.994 8.994 0 0 0 13 3.06V1h-2v2.06A8.994 8.994 0 0 0 3.06 11H1v2h2.06A8.994 8.994 0 0 0 11 20.94V23h2v-2.06A8.994 8.994 0 0 0 20.94 13H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
  209.                 </svg>
  210.             `;
  211.  
  212.             div.addEventListener("click", function () {
  213.                 if (navigator.geolocation) {
  214.                     navigator.geolocation.getCurrentPosition(
  215.                         function (position) {
  216.                             const { latitude:userLat, longitude:userLng } = position.coords;
  217.                             map.setView([userLat, userLng],15);
  218.                             L.circle([userLat,userLng],{ color:"blue", fillColor:"#30f", fillOpacity:"0.5", radius:"10", }).addTo(map);
  219.                          
  220.                             L.marker([userLat, userLng], {
  221.                                 icon: L.divIcon({
  222.                                     className: "crosshair-icon",
  223.                                     html: `
  224.                                         <svg viewBox="0 0 24 24">
  225.                                             <path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3A8.994 8.994 0 0 0 13 3.06V1h-2v2.06A8.994 8.994 0 0 0 3.06 11H1v2h2.06A8.994 8.994 0 0 0 11 20.94V23h2v-2.06A8.994 8.994 0 0 0 20.94 13H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
  226.                                     </svg>
  227.                                     `,
  228.                                     iconSize: [24, 24],
  229.                                     iconAnchor: [12, 12],
  230.                                 }),
  231.                             }).addTo(map);
  232.                         },
  233.                         function (error) {
  234.                             console.error("Geolocation error:", error.message);
  235.                             alert("Standort konnte nicht bestimmt werden:" + error.message);
  236.                         },
  237.                         { enableHighAccuracy:true, timeout:"5000", maximumAge:"0" }
  238.                     );
  239.                 } else {
  240.                     alert("Geolocation wird von Ihrem Browser nicht unterstützt.");
  241.                 }
  242.             });
  243.  
  244.             return div;
  245.         };
  246.  
  247.         locateControl.addTo(map);
  248.     </script>
  249. </body>
  250. </html>

Quellcode

Hier kannst du den Code kopieren und ihn in deinen bevorzugten Editor einfügen. PASTEBIN_DOWNLOAD_SNIPPET_EXPLAIN