feat: Add pulsating ring effect for tracked aircraft/vessels

Makes it much clearer which vehicle is being tracked on the map by adding
two animated concentric rings that pulse outward from the selected marker.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-01-29 09:07:47 +00:00
parent 9f7dc8f995
commit c67fa39e30
4 changed files with 104 additions and 2 deletions

View File

@@ -1146,6 +1146,55 @@ body {
50% { opacity: 0.5; transform: scale(0.8); }
}
/* ============================================
TRACKED AIRCRAFT PULSATING RING
============================================ */
.aircraft-marker.selected {
position: relative;
}
.tracking-ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 2px solid var(--accent-cyan);
border-radius: 50%;
animation: tracking-pulse 1.5s ease-out infinite;
pointer-events: none;
}
.tracking-ring-inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 28px;
height: 28px;
border: 1px solid var(--accent-cyan);
border-radius: 50%;
animation: tracking-pulse 1.5s ease-out infinite 0.3s;
pointer-events: none;
}
@keyframes tracking-pulse {
0% {
transform: translate(-50%, -50%) scale(0.8);
opacity: 1;
border-color: rgba(74, 158, 255, 1);
}
50% {
opacity: 0.6;
}
100% {
transform: translate(-50%, -50%) scale(1.8);
opacity: 0;
border-color: rgba(74, 158, 255, 0);
}
}
/* ============== MOBILE/TABLET FIXES ============== */
@media (max-width: 1023px) {
/* Dashboard - allow scrolling */

View File

@@ -759,6 +759,55 @@ body {
filter: drop-shadow(0 0 8px rgba(255,255,255,0.8)) !important;
}
/* ============================================
TRACKED VESSEL PULSATING RING
============================================ */
.vessel-marker.selected {
position: relative;
}
.tracking-ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 2px solid var(--accent-cyan);
border-radius: 50%;
animation: tracking-pulse 1.5s ease-out infinite;
pointer-events: none;
}
.tracking-ring-inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 28px;
height: 28px;
border: 1px solid var(--accent-cyan);
border-radius: 50%;
animation: tracking-pulse 1.5s ease-out infinite 0.3s;
pointer-events: none;
}
@keyframes tracking-pulse {
0% {
transform: translate(-50%, -50%) scale(0.8);
opacity: 1;
border-color: rgba(74, 158, 255, 1);
}
50% {
opacity: 0.6;
}
100% {
transform: translate(-50%, -50%) scale(1.8);
opacity: 0;
border-color: rgba(74, 158, 255, 0);
}
}
/* Range rings */
.range-ring {
fill: none;

View File

@@ -2970,9 +2970,11 @@ sudo make install</code>
const size = iconType === 'helicopter' ? 22 : 24;
const glowColor = isSelected ? 'rgba(255,255,255,0.9)' : color;
const glowSize = isSelected ? '10px' : '5px';
const trackingRing = isSelected ?
'<div class="tracking-ring"></div><div class="tracking-ring-inner"></div>' : '';
return L.divIcon({
className: `aircraft-marker aircraft-${iconType}${isSelected ? ' selected' : ''}`,
html: `<svg width="${size}" height="${size}" viewBox="0 0 24 24" style="transform: rotate(${rotation}deg); color: ${color}; filter: drop-shadow(0 0 ${glowSize} ${glowColor});">
html: `${trackingRing}<svg width="${size}" height="${size}" viewBox="0 0 24 24" style="transform: rotate(${rotation}deg); color: ${color}; filter: drop-shadow(0 0 ${glowSize} ${glowColor});">
<path fill="currentColor" d="${path}"/>
</svg>`,
iconSize: [size, size],

View File

@@ -329,10 +329,12 @@
const size = 24;
const glowColor = isSelected ? 'rgba(255,255,255,0.8)' : color;
const glowSize = isSelected ? '8px' : '4px';
const trackingRing = isSelected ?
'<div class="tracking-ring"></div><div class="tracking-ring-inner"></div>' : '';
return L.divIcon({
className: 'vessel-marker' + (isSelected ? ' selected' : ''),
html: `<svg width="${size}" height="${size}" viewBox="0 0 24 24" style="transform: rotate(${rotation}deg); filter: drop-shadow(0 0 ${glowSize} ${glowColor});">
html: `${trackingRing}<svg width="${size}" height="${size}" viewBox="0 0 24 24" style="transform: rotate(${rotation}deg); filter: drop-shadow(0 0 ${glowSize} ${glowColor});">
<path fill="${color}" d="${path}"/>
</svg>`,
iconSize: [size, size],