<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Map with Smooth Path</title> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCcoovljMQbS-cflVninzLeUm_gxzqVKq8"></script> <script src="points.js"></script> <style> #map { height: 100vh; width: 100%; } </style> </head> <body> <div id="map"></div> <script> function initMap() { const center = { lat: 54.5208617, lng: 18.5293044 }; // Centered around Gdynia Główna const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: center, }); const cameras = [ { name: "beta", lat: 54.596, lng: 18.343, link: 'https://www.google.com' }, { name: "beta", lat: 54.610556, lng: 18.181778, link: 'https://www.google.com' }, { name: "beta", lat: 54.604556, lng: 18.247722, link: 'https://www.google.com' }, { name: "beta", lat: 54.603806, lng: 18.261389, link: 'https://www.google.com' }, ]; const stations = [ { name: "Lębork", lat: 54.5336953, lng: 17.7505833 }, { name: "Lębork Mosty", lat: 54.5501508, lng: 17.7928783 }, { name: "Godętowo", lat: 54.5820128, lng: 17.8648961 }, { name: "Bożepole Wielkie", lat: 54.5692544, lng: 17.96556 }, { name: "Strzebielino Morskie", lat: 54.5627919, lng: 18.0297814 }, { name: "Luzino", lat: 54.5672303, lng: 18.1036106 }, { name: "Gościcino Wejherowskie", lat: 54.6054475, lng: 18.161305 }, { name: "Wejherowo", lat: 54.6058203, lng: 18.2292289 }, { name: "Wejherowo Nanice", lat: 54.6035731, lng: 18.2496314 }, { name: "Wejherowo Śmiechowo", lat: 54.6019864, lng: 18.2743514 }, { name: "Reda Pieleszewo", lat: 54.6027481, lng: 18.3180667 }, { name: "Reda", lat: 54.5950133, lng: 18.3532075 }, { name: "Rumia", lat: 54.5690953, lng: 18.3866003 }, { name: "Rumia Janowo", lat: 54.55944, lng: 18.4046489 }, { name: "Gdynia Cisowa", lat: 54.5497331, lng: 18.4473861 }, { name: "Gdynia Chylonia", lat: 54.54616, lng: 18.4624442 }, { name: "Gdynia Leszczynki", lat: 54.5413494, lng: 18.4782806 }, { name: "Gdynia Grabówek", lat: 54.5342378, lng: 18.4959956 }, { name: "Gdynia Stocznia", lat: 54.5254606, lng: 18.5192603 }, { name: "Gdynia Główna", lat: 54.5208617, lng: 18.5293044 }, { name: "Gdynia Wzgórze Św. Maksymiliana", lat: 54.5074792, lng: 18.5353856 }, { name: "Gdynia Redłowo", lat: 54.4914125, lng: 18.5383092 }, { name: "Gdynia Orłowo", lat: 54.4779422, lng: 18.5475819 }, { name: "Sopot Kamienny Potok", lat: 54.4575428, lng: 18.553505 }, { name: "Sopot", lat: 54.4418144, lng: 18.5617683 }, { name: "Sopot Wyścigi", lat: 54.4316644, lng: 18.565025 }, { name: "Gdańsk Żabianka-A WFiS", lat: 54.4206053, lng: 18.5684253 }, { name: "Gdańsk Oliwa", lat: 54.4094981, lng: 18.5719353 }, { name: "Gdańsk Przymorze-Uniwersytet", lat: 54.4007606, lng: 18.5764489 }, { name: "Gdańsk Zaspa", lat: 54.3899158, lng: 18.5911644 }, { name: "Gdańsk Wrzeszcz", lat: 54.3820017, lng: 18.6050972 }, { name: "Gdańsk Politechnika", lat: 54.3740778, lng: 18.6275386 }, { name: "Gdańsk Stocznia", lat: 54.364365, lng: 18.6420111 }, { name: "Gdańsk Główny", lat: 54.3553942, lng: 18.6439281 }, { name: "Gdańsk Śródmieście", lat: 54.3464492, lng: 18.6443958 } ]; stations.forEach(station => { new google.maps.Marker({ position: { lat: station.lat, lng: station.lng }, map: map, icon: { url: "train_station.png", scaledSize: new google.maps.Size(30, 30) }, title: station.name }); }); cameras.forEach(camera => { const marker = new google.maps.Marker({ position: { lat: camera.lat, lng: camera.lng }, map: map, icon: { url: "camera.png", scaledSize: new google.maps.Size(50, 50) }, title: camera.name }); marker.addListener("click", () => { window.location.href = camera.link; }); }); // ROUTE const route = points.map(point => ({ lat: point.lat, lng: point.lng })); const path = new google.maps.Polyline({ path: route, geodesic: true, strokeColor: "#FF0000", strokeOpacity: 0.5, strokeWeight: 5, }); path.setMap(map); // Moving marker (blue dot) const movingMarker = new google.maps.Marker({ position: route[0], map: map, icon: { path: google.maps.SymbolPath.CIRCLE, scale: 6, fillColor: "blue", fillOpacity: 1, strokeWeight: 0, }, }); function moveMarker(marker, route, speed) { let index = 0; let progress = 0; const updateInterval = 50; // ms const step = speed / (1000 / updateInterval); // Speed per frame function animate() { if (index < route.length - 1) { const start = route[index]; const end = route[index + 1]; const lat = start.lat + (end.lat - start.lat) * progress; const lng = start.lng + (end.lng - start.lng) * progress; marker.setPosition({ lat, lng }); progress += step; if (progress >= 1) { progress = 0; index++; } setTimeout(animate, updateInterval); } } animate(); } moveMarker(movingMarker, route, 100); // Adjust speed as needed } // Function to compute total route length function getTotalDistance(route) { let totalDistance = 0; for (let i = 0; i < route.length - 1; i++) { totalDistance += google.maps.geometry.spherical.computeDistanceBetween( new google.maps.LatLng(route[i].lat, route[i].lng), new google.maps.LatLng(route[i + 1].lat, route[i + 1].lng) ); } return totalDistance; } // Function to get midpoint of the route function getMidpoint(route) { const totalDistance = getTotalDistance(route); let distanceCovered = 0; let midDistance = totalDistance / 2; for (let i = 0; i < route.length - 1; i++) { let segmentDistance = google.maps.geometry.spherical.computeDistanceBetween( new google.maps.LatLng(route[i].lat, route[i].lng), new google.maps.LatLng(route[i + 1].lat, route[i + 1].lng) ); if (distanceCovered + segmentDistance >= midDistance) { let ratio = (midDistance - distanceCovered) / segmentDistance; let midLat = route[i].lat + (route[i + 1].lat - route[i].lat) * ratio; let midLng = route[i].lng + (route[i + 1].lng - route[i].lng) * ratio; return { lat: midLat, lng: midLng }; } distanceCovered += segmentDistance; } return route[Math.floor(route.length / 2)]; // Fallback // Place second blue dot at the midpoint of the route const midpoint = getMidpoint(route); const midpointMarker = new google.maps.Marker({ position: midpoint, map: map, icon: { path: google.maps.SymbolPath.CIRCLE, scale: 60, fillColor: "blue", fillOpacity: 1, strokeWeight: 0, }, }); } window.onload = initMap; </script> </body> </html>