goiintra/public_html/lib/install_preview_popup.php

438 lines
9.7 KiB
PHP

<?php
include getenv("DOCUMENT_ROOT")."/include/session_include.php";
require_once getenv("DOCUMENT_ROOT")."/assets/dbCon.php";
$startDate = $_GET['startDate'];
$endDate = $_GET['endDate'];
$sql = "
SELECT
di.di_uid,
di.di_install_date,
di.di_driver_uid,
di.di_address,
di.di_city,
di.di_lat,
di.di_lng,
d.dr_initial
FROM tbl_daily_install di
LEFT JOIN tbl_driver d
ON d.dr_uid = di.di_driver_uid
WHERE di.di_install_date BETWEEN '{$startDate}' AND '{$endDate}'
ORDER BY di.di_install_date, di_driver_uid, di_order_seq ASC
";
$result = mysqli_query($conn, $sql);
if(!$result){
die(mysqli_error($conn));
}
$installData = [];
$sq = qry($sql);
while($row = fetch_array($sq)) {
$installData[] = $row;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Install Preview</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
html,
body{
width:100%;
height:100%;
margin:0;
padding:0;
overflow:hidden;
background:#f5f6f8;
font-family:Arial, sans-serif;
}
#installMap{
width:100%;
height:100vh;
}
.install-map-legend{
position:absolute;
top:15px;
left:15px;
z-index:999;
background:#fff;
border-radius:12px;
padding:14px;
min-width:220px;
box-shadow:0 2px 12px rgba(0,0,0,.15);
}
.legend-title{
font-size:14px;
font-weight:700;
margin-bottom:10px;
}
.legend-item{
display:flex;
align-items:center;
gap:8px;
margin-bottom:8px;
font-size:13px;
}
.legend-color{
width:16px;
height:16px;
border-radius:50%;
}
.date-pin{
width:38px;
height:38px;
border-radius:50%;
color:#fff;
font-size:13px;
font-weight:700;
display:flex;
align-items:center;
justify-content:center;
border:2px solid #fff;
box-shadow:0 2px 8px rgba(0,0,0,.3);
transition:all .15s ease;
cursor:pointer;
}
.date-pin:hover{
transform:scale(1.08);
}
.map-header{
position:absolute;
top:15px;
right:15px;
z-index:999;
background:#fff;
border-radius:12px;
padding:12px 16px;
box-shadow:0 2px 12px rgba(0,0,0,.15);
font-size:14px;
font-weight:600;
}
.flag-marker{
position:relative;
min-width:90px;
max-width:180px;
text-align:center;
transition:all .15s ease;
cursor:pointer;
opacity:.82;
backdrop-filter: blur(2px);
}
.flag-marker:hover{
transform:translateY(-2px);
opacity:1;
z-index:9999;
}
.flag-date{
font-size:13px;
font-weight:700;
padding-bottom:4px;
margin-bottom:4px;
border-bottom: 1px solid rgba(255,255,255,.25);
}
.flag-cities{
display:flex;
flex-direction:column;
gap:2px;
}
.flag-city{
white-space:nowrap;
font-size:11px;
line-height:1.15;
}
.flag-tail{
position:absolute;
left:50%;
bottom:-8px;
transform:translateX(-50%);
width:0;
height:0;
border-left:7px solid transparent;
border-right:7px solid transparent;
border-top:10px solid var(--flag-bg);
}
</style>
</head>
<body>
<div class="map-header">
Install Preview
<span class="text-muted">
<?=$startDate?> ~ <?=$endDate?>
</span>
</div>
<div id="installMapLegend" class="install-map-legend"></div>
<div id="installMap"></div>
<script>
let map;
const installData = <?=json_encode($installData, JSON_UNESCAPED_UNICODE)?>;
const driverPalette = [
"#4275c1",
"#91744fff",
"#198754",
"#dc3545",
"#e97517ff",
"#7443cfff",
"#20c997",
"#0dcaf0"
];
// DRIVER COLOR
function getDriverColor(driverUid) {
return driverPalette[driverUid % driverPalette.length];
}
// CUSTOM PIN
function createPreviewMarker({ date, cities, color }) {
const bg = color;
const wrap = document.createElement('div');
wrap.className = 'flag-marker';
wrap.style.background = bg;
wrap.style.border = `2px solid ${bg}`;
wrap.style.color = "#ffffff";
wrap.style.borderRadius = "10px";
wrap.style.padding = "6px 10px";
wrap.style.fontWeight = "700";
wrap.style.fontSize = "12px";
wrap.style.boxShadow = "0 2px 8px rgba(0,0,0,.25)";
wrap.style.setProperty('--flag-bg', bg);
wrap.innerHTML = `
<div class="flag-date">
${date}
</div>
<div class="flag-cities">
${cities.map(city => `
<div class="flag-city">${city}</div>
`).join('')}
</div>
<div class="flag-tail"></div>
`;
return wrap;
}
// LEGEND
function renderLegend(){
const el = document.getElementById("installMapLegend");
if(!el) return;
let html = `<div class="legend-title">Driver Legend</div>`;
const seen = new Set();
installData.forEach(row => {
const uid = parseInt(row.di_driver_uid, 10);
if(!uid || seen.has(uid)) return;
seen.add(uid);
const color = getDriverColor(uid);
html += `
<div class="legend-item">
<span class="legend-color" style="background:${color}"></span>
<span>${row.dr_initial || 'Unknown'}</span>
</div>
`;
});
el.innerHTML = html;
}
function getCityLabel(cityCounts){
const sorted = Object.entries(cityCounts).sort((a, b) => b[1] - a[1]);
if(sorted.length === 0) return '';
return sorted.map(x => x[0]).join(', ');
}
// INIT MAP
async function initMap(){
const { Map, InfoWindow } = await google.maps.importLibrary("maps");
const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
map = new Map(
document.getElementById("installMap"),
{
center: {
lat: 43.7,
lng: -79.4
},
zoom: 11,
mapId: "4504f8b37365c3d0",
disableDefaultUI: true
}
);
renderLegend();
const bounds = new google.maps.LatLngBounds();
// POLYGON
const grouped = {};
installData.forEach(row => {
const key = `${row.di_driver_uid}_${row.di_install_date}`;
if(!grouped[key]){
grouped[key] = {
driverUid: row.di_driver_uid,
installDate: row.di_install_date,
rows: [],
cityCounts: {}
};
}
grouped[key].rows.push(row);
const city = (row.di_city || '').trim();
if(city){
grouped[key].cityCounts[city] =
(grouped[key].cityCounts[city] || 0) + 1;
}
});
const driverInitialMap = {};
installData.forEach(row => {
if(!driverInitialMap[row.di_driver_uid]){
driverInitialMap[row.di_driver_uid] = row.dr_initial || 'Unknown';
}
});
Object.values(grouped).forEach(group => {
const points = [];
group.rows.forEach(row => {
if(!row.di_lat || !row.di_lng) return;
points.push({
lat: parseFloat(row.di_lat),
lng: parseFloat(row.di_lng)
});
});
if(points.length === 0) return;
// CENTER
const avgLat = points.reduce((a,b)=>a+b.lat,0) / points.length;
const avgLng = points.reduce((a,b)=>a+b.lng,0) / points.length;
const center = {
lat: avgLat,
lng: avgLng
};
// COLOR
const color = getDriverColor(group.driverUid);
// POLYGON
if(points.length >= 3){
const polygon =
new google.maps.Polygon({
paths: points,
strokeColor: color,
strokeOpacity: 0.9,
strokeWeight: 2,
fillColor: color,
fillOpacity: 0.12
});
polygon.setMap(map);
}
// DATE
const [year, month, day] = group.installDate.split('-');
const displayDate = `${parseInt(month)}/${parseInt(day)}`;
const cityList = Object.keys(group.cityCounts);
// MARKER
const offsetLat = (Math.random() - 0.5) * 0.03;
const offsetLng = (Math.random() - 0.5) * 0.03;
const marker = new google.maps.marker.AdvancedMarkerElement({
map,
position: {
lat: center.lat + offsetLat,
lng: center.lng + offsetLng
},
zIndex: 1,
content: createPreviewMarker({
date: displayDate,
cities: cityList,
color: color
})
});
// MOUSE OVER
const markerEl = marker.content;
markerEl.addEventListener('mouseenter', () => {
marker.zIndex = 9999;
});
markerEl.addEventListener('mouseleave', () => {
marker.zIndex = 1;
});
// INFO
const infoWindow =
new google.maps.InfoWindow({
content: `
<div style="min-width:220px;">
<div class="fw-bold mb-2">${group.city}</div>
<div><b>Date:</b>${group.installDate}</div>
<div><b>Jobs:</b>${group.rows.length}</div>
</div>
`
});
/*
marker.addListener('gmp-click', () => {
infoWindow.open({
anchor: marker,
map
});
});
*/
bounds.extend(center);
});
// AUTO FIT
if(installData.length > 0){
map.fitBounds(bounds);
}
}
window.initMap = initMap;
</script>
<!-- GOOGLE MAP -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDg9u03mGrBhyOisp7VGc27CTPI9QXp8sY&libraries=marker&callback=initMap"></script>
</body>
</html>