<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Device Tracking - <span th:text="${deviceGuid}"></span></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
#map { height: 500px; border: 2px solid #007bff; border-radius: 5px; }
.info-panel { background-color: #f8f9fa; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container mt-4">
<h1>Tracking Device: <span th:text="${deviceGuid}"></span></h1>
<div class="info-panel">
<p><strong>Time Range:</strong>
<span th:text="${#temporals.format(start, 'yyyy-MM-dd HH:mm')}"></span> -
<span th:text="${#temporals.format(end, 'yyyy-MM-dd HH:mm')}"></span>
</p>
<p><strong>Locations found:</strong> <span th:text="${locations.size()}"></span></p>
<a th:href="@{/}" class="btn btn-secondary">Back to device selection</a>
</div>
<div th:if="${error}" class="alert alert-danger" role="alert">
<span th:text="${error}"></span>
</div>
<div id="map"></div>
<div th:if="${not locations.empty}">
<h3 class="mt-4">Location History</h3>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>Timestamp</th>
<th>Latitude</th>
<th>Longitude</th>
</tr>
</thead>
<tbody>
<tr th:each="location : ${locations}">
<td th:text="${#temporals.format(location.timestamp, 'yyyy-MM-dd HH:mm:ss')}"></td>
<td th:text="${location.latitude}"></td>
<td th:text="${location.longitude}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/
// Получаем данные напрямую из Thymeleaf
var locationsData = /*[[${locations}]]*/ [];
// Initialize map
var map = L.map('map').setView([51.505, -0.09], 13);
// Add OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
console.log('Locations data:', locationsData);
if (locationsData && locationsData.length > 0) {
// Create array of coordinates
var latlngs = locationsData.map(function(loc) {
return [loc.latitude, loc.longitude];
});
// Create polyline with bright color
var polyline = L.polyline(latlngs, {
color: 'red',
weight: 6,
opacity: 0.8,
lineJoin: 'round'
}).addTo(map);
// Add start marker (green icon)
var startIcon = L.icon({
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var startMarker = L.marker(latlngs[0], {icon: startIcon}).addTo(map)
.bindPopup('<strong>START</strong><br>Lat: ' + locationsData[0].latitude.toFixed(6) +
'<br>Lng: ' + locationsData[0].longitude.toFixed(6));
// Add end marker (red icon)
var endIcon = L.icon({
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var endMarker = L.marker(latlngs[latlngs.length-1], {icon: endIcon}).addTo(map)
.bindPopup('<strong>END</strong><br>Lat: ' + locationsData[locationsData.length-1].latitude.toFixed(6) +
'<br>Lng: ' + locationsData[locationsData.length-1].longitude.toFixed(6));
// Add intermediate markers for longer routes
if (locationsData.length > 10) {
for (var i = 1; i < locationsData.length - 1; i += Math.floor(locationsData.length / 5)) {
L.marker([locationsData[i].latitude, locationsData[i].longitude]).addTo(map)
.bindPopup('Point ' + (i+1) + '<br>Lat: ' + locationsData[i].latitude.toFixed(6) +
'<br>Lng: ' + locationsData[i].longitude.toFixed(6));
}
}
// Fit map to show the entire route with padding
map.fitBounds(polyline.getBounds(), { padding: [50, 50] });
// Add zoom control
L.control.zoom({ position: 'topright' }).addTo(map);
} else {
// Show message if no data
var messageDiv = document.createElement('div');
messageDiv.className = 'alert alert-warning';
messageDiv.innerHTML = 'No location data available for mapping.';
messageDiv.style.margin = '20px';
messageDiv.style.padding = '10px';
messageDiv.style.textAlign = 'center';
document.getElementById('map').appendChild(messageDiv);
}
/*]]>*/
</script>
</body>
</html>