Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions src/Components/HMI/ui/public/css/HMI_style.css
Original file line number Diff line number Diff line change
Expand Up @@ -2867,3 +2867,213 @@ z-index: 1;
#animalNotifications .node-status {
font-weight: 600;
}

/* Pulse animation for nodes */
.pulse {
animation: pulseAnim 1.5s infinite;
}

@keyframes pulseAnim {
0% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7);
}
70% {
transform: scale(1.2);
box-shadow: 0 0 0 15px rgba(76, 175, 80, 0);
}
100% {
transform: scale(1);
}
}

/* ================================
Sprint 2 Detection Animation CSS
================================ */

.notification-success {
border-left: 5px solid #4caf50;
}

.notification-error {
border-left: 5px solid #ff4444;
}

.notification-info {
border-left: 5px solid #ffd700;
}

.latest-detection-panel {
position: fixed;
right: 20px;
bottom: 120px;
width: 260px;
background: rgba(10, 10, 25, 0.92);
color: rgba(247, 186, 206, 1);
border: 1px solid rgba(247, 186, 206, 0.5);
border-radius: 12px;
padding: 15px;
z-index: 1200;
font-family: 'Roboto', sans-serif;
box-shadow: 0 0 18px rgba(255, 215, 0, 0.25);
}

.latest-detection-panel h4 {
margin: 0 0 8px 0;
color: #ffd700;
font-size: 18px;
}

.latest-detection-panel p {
margin: 4px 0;
font-size: 14px;
}

.detection-flash {
animation: detectionFlash 1.2s ease-in-out;
}

@keyframes detectionFlash {
0% {
background: rgba(255, 215, 0, 0.95);
color: black;
transform: scale(1.04);
}

50% {
background: rgba(255, 215, 0, 0.45);
color: white;
}

100% {
background: rgba(10, 10, 25, 0.92);
color: rgba(247, 186, 206, 1);
transform: scale(1);
}
}

.detection-badge {
position: absolute;
top: -6px;
right: -6px;
background: #ff3333;
color: white;
font-size: 11px;
min-width: 18px;
height: 18px;
padding: 2px 5px;
border-radius: 999px;
font-weight: bold;
display: inline-flex;
align-items: center;
justify-content: center;
z-index: 1300;
}


#live-detection-panel{
margin-top:20px;
width:100%;
}

.detection-stats{
display:flex;
gap:15px;
margin-bottom:20px;
}

.stat-card{
flex:1;
background:rgba(0,0,0,0.45);
border:1px solid rgba(0,255,170,0.25);
border-radius:12px;
padding:15px;
backdrop-filter: blur(10px);
box-shadow:0 0 15px rgba(0,255,170,0.15);
text-align:center;
}

.stat-number{
display:block;
font-size:28px;
font-weight:bold;
color:#00ffaa;
}

.stat-label{
color:white;
font-size:13px;
}

#timeline-container{
display:flex;
flex-direction:column;
gap:12px;
max-height:400px;
overflow-y:auto;
padding-right:5px;
}

.timeline-card{
background:rgba(255,255,255,0.05);
border-left:4px solid #00ffaa;
padding:14px;
border-radius:10px;
animation:slideIn 0.4s ease;
box-shadow:0 0 12px rgba(0,255,170,0.12);
}

.timeline-header{
display:flex;
justify-content:space-between;
margin-bottom:6px;
}

.timeline-animal{
color:#00ffaa;
font-weight:bold;
font-size:16px;
}

.timeline-time{
color:#bbbbbb;
font-size:12px;
}

.timeline-location{
color:white;
font-size:14px;
}

.timeline-node{
margin-top:6px;
color:#ffcc70;
font-size:13px;
}

@keyframes slideIn{
from{
opacity:0;
transform:translateX(30px);
}
to{
opacity:1;
transform:translateX(0);
}
}

@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}

to {
opacity: 1;
transform: translateY(0);
}
}

#notification {
animation: fadeIn 0.4s ease;
}
104 changes: 83 additions & 21 deletions src/Components/HMI/ui/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
src="./js/ol.js"
></script>

<!-- Bootstrap -->
<!-- Bootstrap --
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://kit.fontawesome.com/8aa980d912.js" crossorigin="anonymous"></script>

Expand All @@ -30,6 +30,12 @@
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
/>
<div id="notification" class="hidden">
<div id="notification-content">
<span id="notification-text">Your notification text here</span>
<span id="notification-close" class="exit-icon">x</span>
</div>
</div>

<script src="https://unpkg.com/boxicons@2.1.4/dist/boxicons.js"></script>

Expand Down Expand Up @@ -387,6 +393,27 @@ <h2>Select Simulator Mode</h2>
<form action="/api/notifications/animals" method="POST">
<div id="notification-contents">
<h2>Animal Notifications</h2>
<h2>Live Detection Timeline</h2>

<div id="live-detection-panel">

<div class="detection-stats">
<div class="stat-card">
<span class="stat-number" id="totalDetections">0</span>
<span class="stat-label">Total Detections</span>
</div>

<div class="stat-card">
<span class="stat-number" id="activeNodes">5</span>
<span class="stat-label">Active Nodes</span>
</div>
</div>

<div id="timeline-container">

</div>

</div>

<!-- Animal Search and Selection -->
<div class="markup_form">
Expand Down Expand Up @@ -2248,25 +2275,23 @@ <h2 style="text-align: left; color: rgba(247, 186, 206, 1) !important;">
var requestData;

const notification = document.getElementById('notification');
const notificationText = document.getElementById('notification-text');
const notificationClose = document.getElementById('notification-close');
const notificationText = document.getElementById('notification-text');
const notificationClose = document.getElementById('notification-close');

//This function receives text as a parameter and generates a visual response with it
//It is responsible for generating a response once a user submits a edit request
//The visual response appears in the bottom left of the screen like a notification
function generateVisualResponse(text) {
function generateVisualResponse(text) {
notificationText.textContent = text;
notification.style.display = 'block';
}

// Function to show the notification
notificationText.textContent = text;
notification.style.display = 'block';
}
window.showNotification = function(text) {
generateVisualResponse(text);
};

//The notification is hidden once the user clicks on the 'x'
function hideNotification() {
notification.style.display = 'none';
}
// Event listener for the close button
notificationClose.addEventListener('click', hideNotification);
function hideNotification() {
notification.style.display = 'none';
}

notificationClose.addEventListener('click', hideNotification);

let username;
let email;
Expand Down Expand Up @@ -2618,10 +2643,46 @@ <h2 style="text-align: left; color: rgba(247, 186, 206, 1) !important;">
simulatorOl.addEventListener("click", openSIMULATOR)

window.onload = function () {
console.log("Website loaded!");
initialiseHMI(hmiState);
//sim is usually on by default, but this functionality is disabled during development
};

console.log("Website loaded!");

initialiseHMI(hmiState);

setInterval(() => {

const animals = [
"Koala",
"Frogmouth",
"Kangaroo",
"Possum",
"Tasmanian Devil",
"Sugar Glider",
"Wombat"
];

const randomAnimal =
animals[Math.floor(Math.random() * animals.length)];

const randomNode =
"NODE-" + Math.floor(Math.random() * 5 + 1);

const currentTime =
new Date().toLocaleTimeString();

showNotification(
`${randomAnimal} detected by ${randomNode}`
);

document.getElementById("notification-text").innerHTML = `
<strong>Latest Detection</strong><br>
Animal: ${randomAnimal}<br>
Node: ${randomNode}<br>
Type: sensor<br>
Time: ${currentTime}
`;

}, 5000);
};

//Microphone show/hide
function updateMics() {
Expand Down Expand Up @@ -2925,6 +2986,7 @@ <h2 style="text-align: left; color: rgba(247, 186, 206, 1) !important;">
setTheme(savedTheme);
});
</script>

</body>

</html>
Loading