315 lines
10 KiB
PHP
315 lines
10 KiB
PHP
<style>
|
||
#map {
|
||
height: 100%;
|
||
margin: 0;
|
||
}
|
||
.my-leaflet-map-container img {
|
||
max-height: none;
|
||
}
|
||
.dtl-text{
|
||
font-size: 0.75rem;
|
||
}
|
||
/* .leaflet-overlay-pane svg {
|
||
transform: none !important;
|
||
} */
|
||
.leaflet-routing-container {
|
||
display: none !important;
|
||
}
|
||
</style>
|
||
|
||
|
||
<div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="mdlDetailTripLabel">{{$nopol1}} Trip Detail</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
</div>
|
||
<div class="modal-body row" id="viewPdf">
|
||
<!-- <div class="col-2">
|
||
<img id="infoVehicles-thumb-md" src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png" class="img-fluid thumb-img-landscape" alt="">
|
||
</div> -->
|
||
<div class="col-4">
|
||
<p class="text-bold mb-0">Start</p>
|
||
<p class="mb-0 time">{{ $start['time'] }}</p>
|
||
<p class="mb-0">Vehicle Mileage: {{number_format($start['mileage'], 2)}} km</p>
|
||
<p>{{$start['fulladdress']}}</p>
|
||
</div>
|
||
<div class="col-4">
|
||
<p class="text-bold mb-0">Finish</p>
|
||
<p class="mb-0 time">{{ $finish['time'] }}</p>
|
||
<p class="mb-0">Vehicle Mileage: {{number_format($finish['mileage'], 2)}} km</p>
|
||
<p>{{$finish['fulladdress']}}</p>
|
||
</div>
|
||
<div class="col-2">
|
||
<p class="text-bold mb-0">Distance</p>
|
||
<p class="mb-0">{{number_format($distance, 2)}} km</p>
|
||
</div>
|
||
<div class="col-2">
|
||
<p class="text-bold mb-0">Duration</p>
|
||
<p class="mb-0">{{$duration}}</p>
|
||
</div>
|
||
<div class="col-12">
|
||
<div id="leafMap" style="height: 400px;"></div>
|
||
</div>
|
||
<div class="col-12">
|
||
<!-- <li class="list-group-item p-1 px-2">
|
||
<p class="text-bold mb-0">Time: 25 Aug 2025 07:31:08</p>
|
||
<p class="text-muted mb-0 dtl-text">-8.55387 - 125.542409</p>
|
||
<p class="text-muted mb-0 dtl-text">Avenida Luro Mata, Praia dos Coqueiros, Bebunuk, Dom Aleixo, Dili, Timor-Leste;2066973</p>
|
||
<p class="mb-0 dtl-text">Current speed: 7km/h</p>
|
||
</li> -->
|
||
@foreach ($list as $item)
|
||
<!-- <li class="list-group-item p-1 px-2">
|
||
<p class="text-bold mb-0">Time: {{date('d-m-Y H:i:s', $item->crt_s)}}</p>
|
||
<p class="text-muted mb-0 dtl-text">Vehicle Mileage: {{number_format($item->vhc_milleage, 2)}} km</p>
|
||
<p class="text-muted mb-0 dtl-text">{{number_format($item->latitude, 6)}} - {{number_format($item->longitude, 6)}}</p>
|
||
<p class="text-muted mb-0 dtl-text">{{urldecode($item->fulladdress)}}</p>
|
||
<p class="text-muted mb-0 dtl-text">Current speed: {{number_format($item->speed, 2)}} km/h</p>
|
||
</li> -->
|
||
<li class="list-group-item p-1 px-2">
|
||
<div class="row">
|
||
<div class="col-4">
|
||
<p class="text-bold mb-0">Time: <span class="time">{{ $item->crt_s }}</span></p>
|
||
<p class="text-muted mb-0 dtl-text">Vehicle Mileage: {{number_format($item->vhc_milleage, 2)}} km</p>
|
||
<p class="text-muted mb-0 dtl-text">Current speed: {{$item->speed}} km/h</p>
|
||
</div>
|
||
<div class="col-8">
|
||
<p class="text-muted mb-0 dtl-text">{{number_format($item->latitude, 6)}} - {{number_format($item->longitude, 6)}}</p>
|
||
<p class="text-muted mb-0 dtl-text">{{urldecode($item->fulladdress)}}</p>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<!-- <button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> -->
|
||
<!-- @can('vehicle.delete')
|
||
<button type="button" id="btnDelVhc_updt" class="btn btn-sm btn-warning">Delete ?</button>
|
||
@endcan
|
||
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
|
||
@can('vehicle.edit')
|
||
<button id="btnSubmitEdtVhc" type="button" class="btn btn-sm btn-danger">Update data</button>
|
||
@endcan
|
||
<div id="edt-btnSubmitEdtVhc" class="d-none">
|
||
<div class="spinner-border" role="status">
|
||
<span class="visually-hidden">Loading...</span>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
$(document).ready(function(){
|
||
$('.time').each(function () {
|
||
const unix = $(this).text().trim();
|
||
$(this).text(moment.unix(unix).format('DD MMM YYYY HH:mm:ss'));
|
||
});
|
||
|
||
let coords
|
||
setTimeout(() => {
|
||
map.invalidateSize(); // force Leaflet to recalc
|
||
// map.fitBounds(polyline.getBounds());
|
||
map.fitBounds(coords.map(c => L.latLng(c[0], c[1])));
|
||
}, 200);
|
||
|
||
const linesData = (@json($list));
|
||
|
||
// 1) Initialize map
|
||
const map = L.map("leafMap").setView([-8.90507, 125.9945732], 10)
|
||
|
||
// 2) Add tile layer
|
||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||
maxZoom: 20,
|
||
crossOrigin: true
|
||
}).addTo(map);
|
||
|
||
// // // 3) Coordinates (Lat, Lng) for polyline
|
||
const points = linesData
|
||
.filter(p => p.latitude && p.longitude)
|
||
.map((point) => [point.latitude, point.longitude])
|
||
|
||
// // 4) Add polyline
|
||
// const polyline = L.polyline(points,{
|
||
// color: 'blue',
|
||
// weight: 3,
|
||
// opacity: 0.7,
|
||
// smoothFactor: 1
|
||
// }).addTo(map);
|
||
|
||
// const lines = L.Routing.control({
|
||
// waypoints: points,
|
||
// // router: L.Routing.osrmv1(),
|
||
// router: L.Routing.osrmv1({
|
||
// serviceUrl: "https://brilianapps.britimorleste.tl:5001/route/v1",
|
||
// }),
|
||
// show: false,
|
||
// itinerary: null, // 👈 completely removes the panel
|
||
// addWaypoints: false, // ❌ prevent adding points by clicking
|
||
// draggableWaypoints: false, // ❌ prevent dragging markers
|
||
// routeWhileDragging: false, // optional: don’t reroute while dragging
|
||
// createMarker: () => null,
|
||
// routingOptions: {
|
||
// radiuses: [100, 100] // tolerance in meters per waypoint
|
||
// },
|
||
// lineOptions:{
|
||
// styles: [{ color: "#C0392B", weight: 4, opacity: 0.7 }],
|
||
// },
|
||
// }).addTo(map)
|
||
|
||
function fetchOsrm(points) {
|
||
// balik koordinat: [lat, lon] -> [lon, lat]
|
||
const coords = points
|
||
|
||
// hints: N-1 semicolon
|
||
const hints = ";".repeat(points.length - 1);
|
||
|
||
const body = {
|
||
coordinates: coords,
|
||
overview: "false",
|
||
alternatives: "true",
|
||
steps: "true",
|
||
hints: hints
|
||
};
|
||
|
||
let config = {
|
||
method: 'post',
|
||
maxBodyLength: Infinity,
|
||
url: 'https://brilianapps.britimorleste.tl/osrm-backend/post-route/v1/driving/',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
data: body
|
||
};
|
||
|
||
return axios.request(config)
|
||
.then((response) => {
|
||
// console.log(JSON.stringify(response.data));
|
||
return response.data; // supaya bisa dipakai di luar
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", err.message);
|
||
return null;
|
||
});
|
||
|
||
}
|
||
|
||
function decodeOSRMGeometry(encoded) {
|
||
const coordinates = [];
|
||
let index = 0,
|
||
lat = 0,
|
||
lng = 0;
|
||
|
||
while (index < encoded.length) {
|
||
let result = 1,
|
||
shift = 0,
|
||
b;
|
||
do {
|
||
b = encoded.charCodeAt(index++) - 63 - 1;
|
||
result += b << shift;
|
||
shift += 5;
|
||
} while (b >= 0x1f);
|
||
lat += (result & 1 ? ~(result >> 1) : result >> 1);
|
||
|
||
result = 1;
|
||
shift = 0;
|
||
do {
|
||
b = encoded.charCodeAt(index++) - 63 - 1;
|
||
result += b << shift;
|
||
shift += 5;
|
||
} while (b >= 0x1f);
|
||
lng += (result & 1 ? ~(result >> 1) : result >> 1);
|
||
|
||
coordinates.push([lat / 1e5, lng / 1e5]);
|
||
}
|
||
|
||
return coordinates;
|
||
}
|
||
|
||
|
||
fetchOsrm(points).then(osrm => {
|
||
if (!osrm) return console.log("OSRM gagal");
|
||
|
||
coords = osrm.routes[0].legs.flatMap(leg =>
|
||
leg.steps.flatMap(step =>
|
||
decodeOSRMGeometry(step.geometry)
|
||
)
|
||
);
|
||
|
||
L.polyline(coords, {
|
||
color: "#2980B9",
|
||
weight: 3,
|
||
opacity: 0.8
|
||
}).addTo(map);
|
||
// map.fitBounds(coords.map(c => L.latLng(c[0], c[1])));
|
||
});
|
||
|
||
|
||
// start and finish point
|
||
const startIcon = L.icon({
|
||
iconUrl: "{{ asset('images/start.png') }}",
|
||
iconSize: [30, 30],
|
||
iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
|
||
})
|
||
L.marker(points[0], {icon: startIcon}).addTo(map)
|
||
|
||
const finishIcon = L.icon({
|
||
iconUrl: "{{ asset('images/finish.png') }}",
|
||
iconSize: [30, 30],
|
||
iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
|
||
})
|
||
L.marker(points[points.length - 1], {icon: finishIcon}).addTo(map)
|
||
|
||
// // 5) Auto-fit map to polyline bounds
|
||
// map.fitBounds(polyline.getBounds())
|
||
|
||
// download pdf
|
||
$(document).on('click', '#btnDownloadReport', function () {
|
||
const viewPdf = document.getElementById("viewPdf");
|
||
|
||
// find overlay svg (the one holding polylines)
|
||
const overlaySvg = document.querySelector('.leaflet-overlay-pane svg');
|
||
let originalTransform = '';
|
||
if (overlaySvg) {
|
||
originalTransform = overlaySvg.style.transform;
|
||
overlaySvg.style.transform = 'none';
|
||
}
|
||
|
||
html2canvas(viewPdf, {
|
||
scale: 2,
|
||
useCORS: true,
|
||
logging: true
|
||
}).then(canvas => {
|
||
const imgData = canvas.toDataURL('image/png');
|
||
const { jsPDF } = window.jspdf;
|
||
|
||
const pdf = new jsPDF('p', 'mm', 'a4');
|
||
const pageWidth = pdf.internal.pageSize.getWidth();
|
||
const pageHeight = pdf.internal.pageSize.getHeight();
|
||
|
||
const imgWidth = pageWidth - 20; // margin
|
||
const imgHeight = canvas.height * imgWidth / canvas.width;
|
||
|
||
let position = 10;
|
||
|
||
// 👉 Handle multipage content
|
||
let heightLeft = imgHeight;
|
||
while (heightLeft > 0) {
|
||
pdf.addImage(imgData, 'PNG', 10, position, imgWidth, imgHeight);
|
||
heightLeft -= pageHeight;
|
||
if (heightLeft > 0) {
|
||
pdf.addPage();
|
||
position = 0;
|
||
}
|
||
}
|
||
|
||
pdf.save(`{{$nopol1}} Trip Report {{$start['time']}}.pdf`);
|
||
|
||
});
|
||
});
|
||
|
||
});
|
||
</script>
|