<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Include Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<!-- Include Bootstrap JavaScript (optional) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<title>20230815-inLaneTicker</title>
<style>
html, body {
height: 100%;
margin: 0;
}
.flex-fill {
flex: 1;
}
.border-grid {
border: 1px solid #ddd;
}
.middle-content {
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(2, 1fr);
gap: 10px;
flex-grow: 1;
padding: 10px;
background-color: #272822; /* Monokai Dark background color */
}
.middle-column {
border: 1px solid #ddd;
padding: 10px;
display: flex;
flex-direction: column;
overflow: auto; /* Enable scrolling for content */
word-wrap: break-word; /* Wrap long words */
background-color: #2C2D2E; /* Monokai Dark column background color */
color: #F8F8F2; /* Text color for Monokai Dark theme */
}
.cell-content {
flex-grow: 1;
}
</style>
</head>
<body class="d-flex flex-column">
<header class="bg-dark text-white p-3">Top Bar</header>
<main class="middle-content">
<div id="row1-col1" class="middle-column border-grid">
<div class="cell-content">YuShei inLaneTicker.</div>
</div>
<div id="row1-col2" class="middle-column border-grid">
<div class="cell-content">Row 1, Column 2</div>
</div>
<div id="row2-col1" class="middle-column border-grid">
<div class="cell-content">Row 2, Column 1</div>
</div>
<div id="row2-col2" class="middle-column border-grid">
<div class="cell-content">Row 2, Column 2. Another long piece of content that might overflow.</div>
</div>
<div id="row3-col1" class="middle-column border-grid">
<div class="cell-content">Row 3, Column 1. Short content.</div>
</div>
<div id="row3-col2" class="middle-column border-grid">
<div class="cell-content">Row 3, Column 2</div>
</div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"></script>
<script>
const socket = io('http://hc4nas01.yushei.com.tw:48599'); // Connect to the backend WebSocket server
const maxEntries = 1; // Set the maximum number of visible entries
// Create an object to store picture counts for each cameraSource
let pictureCounts = JSON.parse(localStorage.getItem('pictureCounts')) || {};
// Function to reset pictureCounts at midnight
function resetPictureCountsAtMidnight() {
const now = new Date();
const midnight = new Date(now);
let today = new Date();
let month = String(today.getMonth() + 1).padStart(2, '0'); // Months are zero-based
let day = String(today.getDate()).padStart(2, '0');
let formattedDate = `${month}-${day}`;
let keyWithDate = `pictureCountsData_${formattedDate}`;
midnight.setHours(24, 0, 0, 0); // Set time to midnight
const lastResetTime = localStorage.getItem('lastResetTime');
if (!lastResetTime || new Date(lastResetTime) < now) {
const timeUntilMidnight = midnight - now;
setTimeout(() => {
today = new Date();
// Get the month and day
month = String(today.getMonth() + 1).padStart(2, '0'); // Months are zero-based
day = String(today.getDate()).padStart(2, '0');
// Create the MM-DD format
formattedDate = `${month}-${day}`;
// console.log(formattedDate); // Outputs something like "08-13"
keyWithDate = `pictureCountsData_${formattedDate}`;
localStorage.setItem(keyWithDate, JSON.stringify(pictureCounts));
pictureCounts = {}; // Reset pictureCounts
localStorage.setItem('lastResetTime', new Date().toISOString()); // Store the reset time
localStorage.setItem('pictureCounts', JSON.stringify(pictureCounts)); // Store pictureCounts
resetPictureCountsAtMidnight(); // Schedule the next reset
}, timeUntilMidnight);
}
}
// Start the initial reset
resetPictureCountsAtMidnight();
// Save pictureCounts to localStorage when the browser is reloaded or closed
window.addEventListener('beforeunload', () => {
localStorage.setItem('pictureCounts', JSON.stringify(pictureCounts));
});
socket.on('change', (change) => {
const { operationType, fullDocument } = change;
if (operationType === 'insert') {
const { _id, plateText, cameraSource, inTime, inCarJpg } = fullDocument;
// Get the target cell based on cameraSource
let targetCellId;
if (cameraSource == 1) {
targetCellId = 'row1-col2';
} else if (cameraSource == 2) {
targetCellId = 'row2-col1';
} else if (cameraSource == 3) {
targetCellId = 'row2-col2';
}
const changesDiv = document.getElementById(targetCellId);
// const changesDiv = document.getElementById('row1-col1');
pictureCounts[cameraSource] = (pictureCounts[cameraSource] || 0) + 1;
// Create a new entry
const changeElement = document.createElement('div');
// p>Change ID: ${_id}</p>
changeElement.innerHTML = `
<p>Plate Text: ${plateText}</p>
<p>Camera Source: ${cameraSource}</p>
<p>Toal Pictures Taken: ${pictureCounts[cameraSource]}</p>
<p>In Time: ${inTime}</p>
<p><img src="data:image/jpeg;base64,${inCarJpg}" alt="Car Image" width="200"></p>
<hr>
`;
// Limit the number of visible entries
while (changesDiv.children.length >= maxEntries) {
changesDiv.removeChild(changesDiv.lastChild);
}
// Insert the new entry at the top
changesDiv.insertBefore(changeElement, changesDiv.firstChild);
}
});
// Listen for the replicationStatus event
socket.on('replicationStatus', (simpleLog) => {
const rsStatusDiv = document.getElementById('row1-col1');
// Create a new entry
const rsStatusElement = document.createElement('div');
rsStatusElement.innerHTML = `
<p><strong>Replication Status:</strong></p>
<table class="table table-bordered">
<thead>
<tr>
<th>_id</th>
<th>Name</th>
<th>Health</th>
<th>State</th>
<th>StateStr</th>
</tr>
</thead>
<tbody>
${simpleLog.map(member => `
<tr>
<td>${member._id}</td>
<td>${member.name}</td>
<td>${member.health}</td>
<td>${member.state}</td>
<td>${member.stateStr}</td>
</tr>
`).join('')}
</tbody>
</table>
<p><em>Last Updated: ${new Date().toLocaleString()}</em></p>
<hr>
`;
// Limit the number of visible entries
while (rsStatusDiv.children.length >= maxEntries) {
rsStatusDiv.removeChild(rsStatusDiv.lastChild);
}
// Insert the new entry at the top
rsStatusDiv.insertBefore(rsStatusElement, rsStatusDiv.firstChild);
});
</script>
<footer class="bg-dark text-white p-3">Bottom Bar</footer>
</body>
</html>