Webcam: Zaehler-Box als verschiebbares HTML-Overlay (per Maus)
Statt ins Bild gebrannt ist der Zaehler jetzt ein HTML-Overlay, das frei mit der Maus positioniert werden kann; Position wird in localStorage gemerkt. Werte kommen ueber /api/counts (Live-Polling). - draw_overlay/render_static/process_frame: draw_counter-Flag (Webcam laesst Box weg, Video-Upload behaelt sie eingebrannt) - Grabber-State auf self.state -> /api/counts liest live mit - Drag-Logik + Counts-Polling im Frontend Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,24 @@
|
||||
.offline-overlay .icon { font-size: 54px; }
|
||||
.offline-overlay .msg { font-size: 22px; font-weight: 600; }
|
||||
.offline-overlay .sub { font-size: 14px; opacity: 0.8; }
|
||||
.counter-box {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: rgba(0, 0, 0, 0.78);
|
||||
color: #fff;
|
||||
padding: 8px 14px 10px;
|
||||
border-radius: 6px;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
z-index: 4;
|
||||
min-width: 150px;
|
||||
}
|
||||
.counter-box .cb-total { font-size: 18px; font-weight: bold; margin-bottom: 2px; }
|
||||
.counter-box .cb-grip { opacity: 0.5; font-size: 11px; margin-top: 4px; }
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 1020px;
|
||||
@@ -143,6 +161,14 @@
|
||||
<div class="video-container">
|
||||
<img id="videoFeed" src="{{ url_for('webcam_feed') }}" />
|
||||
<canvas id="lineCanvas"></canvas>
|
||||
<div id="counterBox" class="counter-box" title="Zum Verschieben ziehen">
|
||||
<div class="cb-total">Gesamt: <span id="cTotal">0</span></div>
|
||||
<div>Autos: <span id="cCar">0</span></div>
|
||||
<div>LKW: <span id="cTruck">0</span></div>
|
||||
<div>Busse: <span id="cBus">0</span></div>
|
||||
<div>Motorräder: <span id="cMoto">0</span></div>
|
||||
<div class="cb-grip">⠿ ziehen</div>
|
||||
</div>
|
||||
<div id="offlineOverlay" class="offline-overlay">
|
||||
<div class="icon" id="ovIcon">📷</div>
|
||||
<div class="msg" id="ovMsg">Kamera offline</div>
|
||||
@@ -369,6 +395,57 @@
|
||||
|
||||
checkCamStatus();
|
||||
setInterval(checkCamStatus, 2000);
|
||||
|
||||
// --- Zaehler-Box: Werte pollen ---
|
||||
const cEl = {
|
||||
total: document.getElementById('cTotal'),
|
||||
car: document.getElementById('cCar'),
|
||||
truck: document.getElementById('cTruck'),
|
||||
bus: document.getElementById('cBus'),
|
||||
moto: document.getElementById('cMoto'),
|
||||
};
|
||||
async function updateCounts() {
|
||||
try {
|
||||
const d = await (await fetch('/api/counts', { cache: 'no-store' })).json();
|
||||
cEl.total.textContent = d.total;
|
||||
cEl.car.textContent = d.car;
|
||||
cEl.truck.textContent = d.truck;
|
||||
cEl.bus.textContent = d.bus;
|
||||
cEl.moto.textContent = d.motorcycle;
|
||||
} catch (e) { /* ignorieren */ }
|
||||
}
|
||||
updateCounts();
|
||||
setInterval(updateCounts, 1000);
|
||||
|
||||
// --- Zaehler-Box: per Maus verschiebbar (Position gemerkt) ---
|
||||
const counterBox = document.getElementById('counterBox');
|
||||
const videoContainer = document.querySelector('.video-container');
|
||||
const savedPos = JSON.parse(localStorage.getItem('counterPos') || 'null');
|
||||
if (savedPos) {
|
||||
counterBox.style.left = savedPos.x + 'px';
|
||||
counterBox.style.top = savedPos.y + 'px';
|
||||
}
|
||||
let dragging = false, offX = 0, offY = 0;
|
||||
counterBox.addEventListener('mousedown', (e) => {
|
||||
dragging = true;
|
||||
offX = e.clientX - counterBox.offsetLeft;
|
||||
offY = e.clientY - counterBox.offsetTop;
|
||||
e.preventDefault();
|
||||
});
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (!dragging) return;
|
||||
const maxX = videoContainer.clientWidth - counterBox.offsetWidth;
|
||||
const maxY = videoContainer.clientHeight - counterBox.offsetHeight;
|
||||
const x = Math.max(0, Math.min(e.clientX - offX, maxX));
|
||||
const y = Math.max(0, Math.min(e.clientY - offY, maxY));
|
||||
counterBox.style.left = x + 'px';
|
||||
counterBox.style.top = y + 'px';
|
||||
});
|
||||
document.addEventListener('mouseup', () => {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
localStorage.setItem('counterPos', JSON.stringify({ x: counterBox.offsetLeft, y: counterBox.offsetTop }));
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
function applyThemeBtn(){var d=document.documentElement.getAttribute('data-theme')==='dark';var b=document.getElementById('themeToggle');if(b)b.textContent=d?'☀️':'🌙';}
|
||||
|
||||
Reference in New Issue
Block a user