регулировка ресайза

This commit is contained in:
Maxim
2026-06-17 15:59:53 +03:00
parent 30923eb9ce
commit 580b78e5c0
3 changed files with 241 additions and 83 deletions

View File

@@ -166,7 +166,7 @@ h1 {
.fill {
height: 100%;
width: 0%;
width: 0;
background: #e6852d;
box-shadow:
inset 0 0 4px rgba(255,255,255,0.2),
@@ -177,7 +177,7 @@ h1 {
.fill.no-connection {
background: #555555 !important;
box-shadow: none !important;
width: 0% !important;
width: 0 !important;
}
/* ===== SIGNAL ICON ===== */
@@ -194,7 +194,7 @@ h1 {
flex: 1;
border-radius: 2px;
min-width: 5px;
border: 1.5px solid #e6852d;
border: 2px solid #e6852d;
background-color: transparent;
transition: background-color 0.3s, border-color 0.3s;
}

View File

@@ -1,23 +1,18 @@
// camera.ts
import { updateResizerVisibility } from './layout.js';
import { updateResizerVisibility, openRightPanel, closeRightPanel } from './layout.js';
let rightPanel: HTMLElement | null = null;
let camImage: HTMLImageElement | null = null;
let crosshair: HTMLElement | null = null;
let isOpen: boolean = false;
let streamCheckInterval: number | null = null;
interface StreamResponse {
cam: string;
available: boolean;
source: string;
}
let resizer: HTMLElement | null = null;
export function initCamera(): void {
rightPanel = document.getElementById("rightPanel");
camImage = document.getElementById("camImage") as HTMLImageElement;
crosshair = document.getElementById("crosshair");
resizer = document.getElementById("dragBar");
const btn = document.getElementById("camToggle");
@@ -28,9 +23,8 @@ export function initCamera(): void {
isOpen = true;
if (rightPanel) {
rightPanel.classList.remove("hidden");
}
// Открываем правую панель через layout
openRightPanel();
// Показываем перекрестие
if (crosshair) {
@@ -44,13 +38,15 @@ export function initCamera(): void {
if (btn) {
const textSpan = btn.querySelector('.cam-btn-text');
if (textSpan) textSpan.textContent = 'Скрыть';
if (textSpan) {
textSpan.textContent = 'Скрыть';
} else {
btn.innerHTML = '📷 Скрыть';
}
}
console.log("[camera] opened");
updateResizerVisibility();
// Запускаем мониторинг потока
startStreamMonitoring();
}
@@ -65,24 +61,25 @@ export function initCamera(): void {
crosshair.style.display = "none";
}
// остановка stream
// Останавливаем поток
if (camImage) {
camImage.src = "";
}
if (rightPanel) {
rightPanel.classList.add("hidden");
}
// Закрываем правую панель через layout
closeRightPanel();
if (btn) {
const textSpan = btn.querySelector('.cam-btn-text');
if (textSpan) textSpan.textContent = 'Камера';
if (textSpan) {
textSpan.textContent = 'Камера';
} else {
btn.innerHTML = '📷 Камера';
}
}
console.log("[camera] closed");
updateResizerVisibility();
// Останавливаем мониторинг
stopStreamMonitoring();
}
@@ -139,7 +136,15 @@ export function initCamera(): void {
}
}
// Экспортируем для возможности ручного управления
// ============================================
// ПУБЛИЧНЫЕ ФУНКЦИИ (используются в других модулях)
// ============================================
/**
* Показать/скрыть перекрестие на видео
* @param show - показывать или скрыть
*/
// noinspection JSUnusedGlobalSymbols
export function showCrosshair(show: boolean = true): void {
const crosshairElem = document.getElementById("crosshair");
if (crosshairElem) {
@@ -147,6 +152,11 @@ export function showCrosshair(show: boolean = true): void {
}
}
/**
* Установить прозрачность перекрестия
* @param opacity - значение прозрачности (0-1)
*/
// noinspection JSUnusedGlobalSymbols
export function setCrosshairOpacity(opacity: string | number): void {
const crosshairElem = document.getElementById("crosshair");
if (crosshairElem) {

View File

@@ -1,88 +1,236 @@
// layout.ts
let resizer: HTMLElement | null = null;
let leftPanel: HTMLElement | null = null;
let rightPanel: HTMLElement | null = null;
let dragBar: HTMLElement | null = null;
let isDragging: boolean = false;
let pendingX: number | null = null;
let isOpen: boolean = false;
let lastLeftWidth: number = 0;
let lastRightWidth: number = 0;
export function initResize(): void {
resizer = document.getElementById("dragBar");
leftPanel = document.getElementById("leftPanel");
rightPanel = document.getElementById("rightPanel");
dragBar = document.getElementById("dragBar");
if (!leftPanel || !rightPanel || !dragBar) return;
const savedRatio = localStorage.getItem('layoutRatio');
if (savedRatio) {
applyRatio(parseFloat(savedRatio));
if (!resizer || !leftPanel || !rightPanel) {
console.warn("[layout] Элементы не найдены");
return;
}
dragBar.addEventListener("mousedown", (e) => {
if (rightPanel!.classList.contains("hidden")) return;
// Проверяем видимость при инициализации
updateResizerVisibility();
let isDragging = false;
// Обработчик начала перетаскивания
resizer.addEventListener("mousedown", (e: MouseEvent) => {
// Сохраняем ссылки на элементы в локальные переменные
const left = leftPanel;
const right = rightPanel;
// Проверяем, что элементы существуют
if (!left || !right) {
console.warn("[layout] Панели не найдены");
return;
}
// Проверяем, что правая панель видима
if (right.classList.contains("hidden")) {
return;
}
isDragging = true;
document.body.style.cursor = "col-resize";
e.preventDefault();
});
document.body.style.userSelect = "none";
document.addEventListener("mouseup", () => {
// Сохраняем начальные размеры
const startX = e.clientX;
const leftWidth = left.getBoundingClientRect().width;
const rightWidth = right.getBoundingClientRect().width;
const totalWidth = leftWidth + rightWidth;
function onMouseMove(moveEvent: MouseEvent): void {
if (!isDragging) return;
// Проверяем, что элементы всё ещё существуют
if (!left || !right) return;
const deltaX = moveEvent.clientX - startX;
let newLeftWidth = leftWidth + deltaX;
// Ограничиваем минимальные размеры
const minWidth = 200;
newLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth));
const newRightWidth = totalWidth - newLeftWidth;
left.style.flex = `0 0 ${newLeftWidth}px`;
right.style.flex = `0 0 ${newRightWidth}px`;
// Сохраняем последние размеры
lastLeftWidth = newLeftWidth;
lastRightWidth = newRightWidth;
}
function onMouseUp(): void {
isDragging = false;
document.body.style.cursor = "default";
document.body.style.cursor = "";
document.body.style.userSelect = "";
if (rightPanel && !rightPanel.classList.contains("hidden")) {
const total = window.innerWidth;
const leftWidth = leftPanel!.getBoundingClientRect().width;
localStorage.setItem('layoutRatio', String(leftWidth / total));
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
});
document.addEventListener("mousemove", (e) => {
if (!isDragging) return;
if (rightPanel && rightPanel.classList.contains("hidden")) return;
pendingX = e.clientX;
requestAnimationFrame(() => {
if (pendingX === null) return;
if (!leftPanel || !rightPanel || !dragBar) return;
const total = window.innerWidth;
let leftWidth = pendingX;
const min = 300;
if (leftWidth < min) leftWidth = min;
if (leftWidth > total - min) leftWidth = total - min;
const rightWidth = total - leftWidth - dragBar.offsetWidth;
leftPanel.style.flex = `0 0 ${leftWidth}px`;
rightPanel.style.flex = `0 0 ${rightWidth}px`;
pendingX = null;
});
// Обработчик изменения размера окна
window.addEventListener("resize", () => {
handleWindowResize();
});
}
function applyRatio(ratio: number): void {
const total = window.innerWidth;
const leftWidth = Math.floor(total * ratio);
const rightWidth = total - leftWidth;
/**
* Обработка изменения размера окна
*/
function handleWindowResize(): void {
if (!leftPanel || !rightPanel) return;
if (leftPanel && rightPanel) {
leftPanel.style.flex = `0 0 ${leftWidth}px`;
rightPanel.style.flex = `0 0 ${rightWidth}px`;
// Если правая панель видима, пересчитываем размеры
if (!rightPanel.classList.contains("hidden")) {
// Если есть сохраненные размеры, используем их пропорционально
if (lastLeftWidth > 0 && lastRightWidth > 0) {
const totalWidth = window.innerWidth;
const ratio = lastLeftWidth / (lastLeftWidth + lastRightWidth);
const newLeftWidth = totalWidth * ratio;
const newRightWidth = totalWidth - newLeftWidth;
// Ограничиваем минимальные размеры
const minWidth = 200;
const finalLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth));
const finalRightWidth = totalWidth - finalLeftWidth;
leftPanel.style.flex = `0 0 ${finalLeftWidth}px`;
rightPanel.style.flex = `0 0 ${finalRightWidth}px`;
lastLeftWidth = finalLeftWidth;
lastRightWidth = finalRightWidth;
} else {
// Если нет сохраненных размеров, делим пополам
const totalWidth = window.innerWidth;
const halfWidth = totalWidth / 2;
leftPanel.style.flex = `0 0 ${halfWidth}px`;
rightPanel.style.flex = `0 0 ${halfWidth}px`;
lastLeftWidth = halfWidth;
lastRightWidth = halfWidth;
}
}
}
/**
* Обновление видимости разделителя в зависимости от состояния правой панели
*/
export function updateResizerVisibility(): void {
if (!dragBar || !rightPanel || !leftPanel) return;
if (!resizer || !rightPanel) return;
// Если правая панель скрыта - скрываем разделитель
if (rightPanel.classList.contains("hidden")) {
resizer.classList.add("hidden");
} else {
resizer.classList.remove("hidden");
}
}
/**
* Открыть правую панель
*/
export function openRightPanel(): void {
if (!leftPanel || !rightPanel) return;
// Убираем класс hidden
rightPanel.classList.remove("hidden");
// Обновляем разделитель
updateResizerVisibility();
// Устанавливаем размеры
const totalWidth = window.innerWidth;
const halfWidth = totalWidth / 2;
// Проверяем, есть ли сохраненные размеры
if (lastLeftWidth > 0 && lastRightWidth > 0) {
// Используем сохраненные пропорции
const ratio = lastLeftWidth / (lastLeftWidth + lastRightWidth);
const newLeftWidth = totalWidth * ratio;
const newRightWidth = totalWidth - newLeftWidth;
const minWidth = 200;
const finalLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth));
const finalRightWidth = totalWidth - finalLeftWidth;
leftPanel.style.flex = `0 0 ${finalLeftWidth}px`;
rightPanel.style.flex = `0 0 ${finalRightWidth}px`;
lastLeftWidth = finalLeftWidth;
lastRightWidth = finalRightWidth;
} else {
// Делим пополам
leftPanel.style.flex = `0 0 ${halfWidth}px`;
rightPanel.style.flex = `0 0 ${halfWidth}px`;
lastLeftWidth = halfWidth;
lastRightWidth = halfWidth;
}
}
/**
* Закрыть правую панель
*/
export function closeRightPanel(): void {
if (!rightPanel) return;
// Добавляем класс hidden
rightPanel.classList.add("hidden");
// Обновляем разделитель
updateResizerVisibility();
// Сбрасываем flex для левой панели
if (leftPanel) {
leftPanel.style.flex = "1 1 auto";
}
}
// ============================================
// ПУБЛИЧНЫЕ ФУНКЦИИ (используются в других модулях)
// ============================================
/**
* Установить видимость разделителя вручную
* @param visible - показывать или скрыть
*/
// noinspection JSUnusedGlobalSymbols
export function setResizerVisible(visible: boolean): void {
if (resizer) {
if (visible) {
resizer.classList.remove("hidden");
} else {
resizer.classList.add("hidden");
}
}
}
/**
* Переключить состояние правой панели
*/
// noinspection JSUnusedGlobalSymbols
export function toggleRightPanel(): void {
if (!rightPanel) return;
if (rightPanel.classList.contains("hidden")) {
dragBar.classList.add("hidden");
leftPanel.style.flex = "1";
openRightPanel();
} else {
dragBar.classList.remove("hidden");
closeRightPanel();
}
}