добавление креста метки на видео
This commit is contained in:
@@ -341,6 +341,70 @@ h1 {
|
||||
object-fit: contain;
|
||||
background: black;
|
||||
}
|
||||
/* ===== CAMERA OVERLAY ===== */
|
||||
.cam-frame-wrapper {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background: black;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cam-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
background: black;
|
||||
}
|
||||
|
||||
/* Перекрестие (crosshair) */
|
||||
.cam-crosshair {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* Вертикальная линия */
|
||||
.crosshair-v {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background: #00ff88;
|
||||
box-shadow: 0 0 4px rgba(0, 255, 136, 0.3);
|
||||
}
|
||||
|
||||
/* Горизонтальная линия */
|
||||
.crosshair-h {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: #00ff88;
|
||||
box-shadow: 0 0 4px rgba(0, 255, 136, 0.3);
|
||||
}
|
||||
|
||||
/* Центральный квадрат */
|
||||
.crosshair-box {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px solid #00ff88;
|
||||
box-shadow:
|
||||
0 0 10px rgba(0, 255, 136, 0.3),
|
||||
inset 0 0 10px rgba(0, 255, 136, 0.1);
|
||||
}
|
||||
|
||||
/* ===== MOBILE ===== */
|
||||
@media (max-width: 500px) {
|
||||
|
||||
@@ -86,7 +86,19 @@
|
||||
<div class="cam-header">
|
||||
<span>Видео с камеры</span>
|
||||
</div>
|
||||
<img id="camImage" src="" alt="Camera" class="cam-frame">
|
||||
<div class="cam-frame-wrapper">
|
||||
<img id="camImage" src="" alt="Camera" class="cam-frame">
|
||||
|
||||
<!-- ПЕРЕКРЕСТИЕ -->
|
||||
<div class="cam-crosshair" id="crosshair">
|
||||
<!-- Основные линии -->
|
||||
<div class="crosshair-v"></div>
|
||||
<div class="crosshair-h"></div>
|
||||
|
||||
<!-- Центральный квадрат -->
|
||||
<div class="crosshair-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,14 +3,17 @@ import { updateResizerVisibility } from './layout.js';
|
||||
|
||||
let rightPanel;
|
||||
let camImage;
|
||||
let camClose;
|
||||
|
||||
let crosshair;
|
||||
let isOpen = false;
|
||||
let streamCheckInterval = null;
|
||||
|
||||
export function initCamera() {
|
||||
rightPanel = document.getElementById("rightPanel");
|
||||
camImage = document.getElementById("camImage");
|
||||
camClose = document.getElementById("camClose");
|
||||
crosshair = document.getElementById("crosshair");
|
||||
|
||||
// Проверяем доступность потока
|
||||
checkStreamAvailability();
|
||||
|
||||
const btn = document.getElementById("camToggle");
|
||||
|
||||
@@ -23,6 +26,11 @@ export function initCamera() {
|
||||
|
||||
rightPanel.classList.remove("hidden");
|
||||
|
||||
// Показываем перекрестие
|
||||
if (crosshair) {
|
||||
crosshair.style.display = "block";
|
||||
}
|
||||
|
||||
camImage.src = streamUrl;
|
||||
|
||||
if (btn) {
|
||||
@@ -32,6 +40,9 @@ export function initCamera() {
|
||||
console.log("[camera] opened");
|
||||
|
||||
updateResizerVisibility();
|
||||
|
||||
// Запускаем мониторинг потока
|
||||
startStreamMonitoring();
|
||||
}
|
||||
|
||||
function close() {
|
||||
@@ -39,6 +50,11 @@ export function initCamera() {
|
||||
|
||||
isOpen = false;
|
||||
|
||||
// Скрываем перекрестие
|
||||
if (crosshair) {
|
||||
crosshair.style.display = "none";
|
||||
}
|
||||
|
||||
// остановка stream
|
||||
camImage.src = "";
|
||||
|
||||
@@ -51,6 +67,9 @@ export function initCamera() {
|
||||
console.log("[camera] closed");
|
||||
|
||||
updateResizerVisibility();
|
||||
|
||||
// Останавливаем мониторинг
|
||||
stopStreamMonitoring();
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
@@ -63,14 +82,80 @@ export function initCamera() {
|
||||
|
||||
camImage.onload = () => {
|
||||
console.log("[camera] stream started");
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '1';
|
||||
}
|
||||
};
|
||||
|
||||
camImage.onerror = (e) => {
|
||||
console.error("[camera] stream error", e);
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '0.3';
|
||||
}
|
||||
};
|
||||
|
||||
btn?.addEventListener("click", toggle);
|
||||
|
||||
// автозапуск
|
||||
open();
|
||||
// Проверка доступности камеры
|
||||
async function checkStreamAvailability() {
|
||||
try {
|
||||
const response = await fetch('/api/stream');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.available && data.cam) {
|
||||
console.log("[camera] stream available:", data.source);
|
||||
// Автозапуск если камера доступна
|
||||
if (!isOpen) {
|
||||
open();
|
||||
}
|
||||
} else {
|
||||
console.log("[camera] stream not available");
|
||||
if (crosshair) {
|
||||
crosshair.style.display = 'none';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[camera] check failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Мониторинг состояния потока
|
||||
function startStreamMonitoring() {
|
||||
stopStreamMonitoring();
|
||||
streamCheckInterval = setInterval(() => {
|
||||
if (isOpen && camImage) {
|
||||
if (!camImage.complete || camImage.naturalWidth === 0) {
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '0.3';
|
||||
}
|
||||
} else {
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '1';
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function stopStreamMonitoring() {
|
||||
if (streamCheckInterval) {
|
||||
clearInterval(streamCheckInterval);
|
||||
streamCheckInterval = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Экспортируем для возможности ручного управления
|
||||
export function showCrosshair(show = true) {
|
||||
const crosshair = document.getElementById("crosshair");
|
||||
if (crosshair) {
|
||||
crosshair.style.display = show ? "block" : "none";
|
||||
}
|
||||
}
|
||||
|
||||
export function setCrosshairOpacity(opacity) {
|
||||
const crosshair = document.getElementById("crosshair");
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = opacity;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user