ArgusSite/static/templates/videos/playback.html
2024-01-09 01:39:00 +03:00

1149 lines
41 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Записи</title>
<link rel="stylesheet" href="../styles/main.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<style>
.stream-cameras {
width: 100%;
max-height: 450px;
display: none;
}
</style>
</head>
<body>
<div id="video-popup" class="video-popup">
<div id="video-popup-content" class="video-popup-content">
<span class="close-popup" id="close-popup">&times;</span>
<div id="popup-video-container" class="popup-video-container">
</div>
</div>
</div>
<header>
<img src="../img/argus.png">
<h1>Аргус</h1>
<h2><span>/</span> {{Organisation}}</h2>
</header>
<section class="account-info">
<div id="account-main">
<img id="person" src="../img/person.svg">
<span>{{User}}</span>
<img id="down" src="../img/down.svg">
<img id="up" src="../img/up.svg">
</div>
<a href="/logout"><div id="account-additional" class="additional">Выйти</div></a>
</section>
<section class="navigation">
<a href="/">
<div><img src="../img/chart.svg">Главная</div>
</a>
<a href="/devices">
<div><img src="../img/cloud.svg">Устройства</div>
</a>
<a href="/reports">
<div><img src="../img/bubble.svg">Отчёты</div>
</a>
<a href="/live">
<div><img src="../img/waves.svg">Трансляция</div>
</a>
<a href="/videos">
<div class="selected"><img src="../img/play.svg">Записи</div>
</a>
<a href="https://forms.yandex.ru/cloud/6515ecda3e9d08f17262c332/" target="_blank">
<div><img src="../img/bug.svg">Собщить об ошибке</div>
</a>
{{#if isAdmin}}
<a class="admin-panel" href="/admin">
<div><img src="../img/keyboard.svg">Админка</div>
</a>
{{/if}}
<a class="settings" href="/settings">
<div><img src="../img/gear.svg">Настройки</div>
</a>
</section>
<section class="main">
<section style="display: none;" class="dberror" id="dataLoading" >
<div class="loader-container">
<div class="loader">
<div class="square" id="sq11"></div>
<div class="square" id="sq12"></div>
<div class="square" id="sq13"></div>
<div class="square" id="sq14"></div>
<div class="square" id="sq15"></div>
<div class="square" id="sq16"></div>
<div class="square" id="sq17"></div>
<div class="square" id="sq18"></div>
<div class="square" id="sq19"></div>
</div>
</div>
</section>
{{#if ifDBError}}
<section class="dberror">
<div class="erorr-container">
<img src="../img/warning.svg"> <br>
<h1>Ошибка </h1> <br>
<span>Не удалось получить данные из БД</span>
<button type="button" onclick="location.reload();">Повторить попытку</button>
</div>
</section>
{{/if}}
<nav>
<a class="selected" href="/videos">Воспроизведение</a>
<a href="/videos/export">Экспорт</a>
</nav>
<section class="bg">
<section class="content">
<section style="min-height: 800px;" class="for-table">
<section class="organisation">
<h1>Организация</h1>
<ul class="area">
{{#each Groups}}
<li class="area-name"><img src="../img/ul.svg"><input type="checkbox" id="{{name}}" class="checkbox-input" hidden checked><label for="{{name}}" class="checkbox-label checkbox-name"><span class="text">{{name}}</span></label>
<ul class="area-devices" id="devices-1">
{{#each devices}}
<li class="device">
<img>
<input type="number" id="channels-{{this.serial}}" value="{{this.channels}}" hidden>
<input type="radio" name="camera-serial" id="radio-{{this.serial}}" class="radio-input" value="{{this.serial}}" hidden>
<input type="text" id="ourreg-{{this.serial}}" value="{{this.ourreg}}" hidden>
<label for="radio-{{this.serial}}" class="radio-label active-{{this.status}}">
{{#if this.number}}
{{this.number}}
{{else}}
{{this.serial}}
{{/if}}
</label>
</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
</section>
<section class="table" style="position: relative;">
<div class="map">
<div id="map"></div>
</div>
<div style="background: white;" class="cameras">
<section style="border: 0;" class="whole-width">
<h1>Запустить запись с камеры</h1>
<h3 id="cameras-title">Выберите камеру, время и нажмите кнопку "Запустить запись"</h3>
<form id="edit-group-form">
<div class="parameters-input">
<label for="group-id">Камера</label>
<select name="group-id" id="group-id">
<option value="">Выберите номер камеры</option>
<option value="1">Камера 1</option>
<option value="2">Камера 2</option>
<option value="3">Камера 3</option>
<option value="4">Камера 4</option>
<option value="5">Камера 5</option>
<option value="6">Камера 6</option>
<option value="7">Камера 7</option>
<option value="8">Камера 8</option>
<option value="9">Камера 9</option>
<option value="10">Камера 10</option>
<option value="11">Камера 11</option>
<option value="12">Камера 12</option>
<option value="13">Камера 13</option>
</select>
</div>
</form>
<div style="margin-left: 44px; margin-right: 72px; width: calc(100% - 44px - 72px);" class="horizontal-line"></div>
<button style="margin-top: 15px;" id="group-edit" class="button-purple" type="button" onclick="playVideo();">Запустить запись</button>
<h3 id="warning">Могут возникнуть проблемы с блокировкой всплывающих окон в браузере, при возникновении проблем проверьте что открытие новых окон из этого сайта у вас работает (обычно иконка отображается в правом верхнем углу).</h3>
<br>
<!-- <video id="playback-camera"></video> -->
<div id="playback-cameras" class="stream-cameras">
<div class="stream-video-container">
<video id="camera-1"></video>
<video id="camera-2"></video>
<video id="camera-3"></video>
<video id="camera-4"></video>
<video style="display: none;" id="camera-5"></video>
</div>
<button onclick="switchCameras(-1)">Назад</button>
<button onclick="switchCameras(1)">Вперед</button>
</div>
</section>
</div>
<div class="calendar">
<div class="calendar-header">
<button id="prevMonth"></button>
<h2 id="monthYear"></h2>
<button id="nextMonth"></button>
</div>
<div class="daysOfWeek">
<div>Пн</div>
<div>Вт</div>
<div>Ср</div>
<div>Чт</div>
<div>Пт</div>
<div>Сб</div>
<div>Вс</div>
</div>
<div class="dates" id="dates">
</div>
</div>
<input type="hidden" id="selectedDate" name="selectedDate" hidden>
<div class="speedometr">
<div style="display: none;" id="speed-bg" class="speed-bg">
<h1>Данных для выбранного периода нет.</h1>
</div>
<h1>Скорость</h1>
<span>км/ч</span>
<span style="float: right; font-size: 18px;">1 ч</span>
<div>
<canvas id="speed"></canvas>
</div>
</div>
<div class="video-time">
<!-- <span id="from-time-label" style="margin-left: 15px; display: none;">с</span> -->
<input name="videoTime" type="time" id="video-time" step="1">
<!-- <span id="end-time-label" style="display: none;">до</span> -->
<!-- <input name="videoEndTime" type="time" id="video-end-time" step="1" style="display: none;"> -->
</div>
</section>
</section>
</section>
</section>
</section>
<style>
.table {
background-color:#f7f7fa !important;
}
.speedometr {
position: absolute;
right: 0;
bottom: 62px;
width: calc(75% - 300px - 10px - 32px);
height: 220px;
border-radius: 15px;
background-color: white;
padding-right: 32px;
}
.speedometr div {
height: 190px;
}
</style>
<script src="../scripts/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.5.0/flv.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
var containers = document.querySelectorAll('.checkbox-name');
containers.forEach(function (container) {
var text = container.querySelector('.text');
if (text.clientWidth > container.clientWidth) {
text.classList.add('animated');
}
});
});
document.addEventListener('DOMContentLoaded', function () {
var radioLabels = document.querySelectorAll('.radio-label');
radioLabels.forEach(function (label) {
var labelText = label.textContent.trim();
if (labelText.length > 10) {
label.textContent = '';
label.appendChild(document.createTextNode(labelText.slice(0, 9) + '...'));
}
});
});
</script>
<script>
function updateCameraOptions() {
var selectedSerial = document.querySelector('input[name="camera-serial"]:checked').value;
var channelsInput = document.querySelector('#channels-' + selectedSerial);
var numChannels = parseInt(channelsInput.value, 10);
var select = document.querySelector('#group-id');
select.innerHTML = '';
var defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Выберите номер камеры';
select.appendChild(defaultOption);
for (var i = 1; i <= numChannels; i++) {
var option = document.createElement('option');
option.value = i;
option.textContent = 'Камера ' + i;
select.appendChild(option);
}
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const areaNames = document.querySelectorAll('.area-name');
areaNames.forEach(function (areaName) {
const areaCheckbox = areaName.querySelector('.checkbox-input');
const deviceCheckboxes = areaName.querySelectorAll('.device .checkbox-input');
const deviceList = areaName.querySelector('.area-devices');
// Функция для скрытия/показа дочерних элементов
function toggleChildDevices(show) {
if (show) {
deviceList.style.display = 'block';
} else {
deviceList.style.display = 'none';
}
}
// Инициализация состояния чекбоксов и скрытия/показа дочерних элементов
toggleChildDevices(areaCheckbox.checked);
deviceCheckboxes.forEach(function (deviceCheckbox) {
deviceCheckbox.checked = areaCheckbox.checked;
});
areaCheckbox.addEventListener('change', function () {
const isChecked = areaCheckbox.checked;
deviceCheckboxes.forEach(function (deviceCheckbox) {
deviceCheckbox.checked = isChecked;
});
toggleChildDevices(isChecked);
});
deviceCheckboxes.forEach(function (deviceCheckbox) {
deviceCheckbox.addEventListener('change', function () {
const allUnchecked = Array.from(deviceCheckboxes).every(function (checkbox) {
return !checkbox.checked;
});
if (allUnchecked) {
areaCheckbox.checked = false;
toggleChildDevices(false);
} else {
areaCheckbox.checked = true;
toggleChildDevices(true);
}
});
});
});
});
</script>
<script>
function combineDateTime(dateString, timeString) {
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
// Разбиение времени на часы, минуты и секунды
const timeParts = timeString.split(":");
const hours = timeParts[0].padStart(2, "0");
const minutes = timeParts[1].padStart(2, "0");
const seconds = timeParts[2].padStart(2, "0");
// Собираем дату и время в нужном формате
const combinedDateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
return combinedDateTime;
}
let HasData;
var selectedChannel = 1;
async function sendPostRequest() {
stopAllCameras();
let serial = $("input[name=camera-serial]:checked").val()
if ($(`#ourreg-${serial}`).val() == "true") {
$("#warning").hide();
$("#playback-cameras").show();
$("#edit-group-form").hide();
$("#cameras-title").hide();
// $("#from-time-label").show();
// $("#end-time-label").show();
// $("#video-end-time").show();
} else {
$("#warning").show();
$("#playback-cameras").hide();
$("#edit-group-form").show();
$("#cameras-title").show();
// $("#from-time-label").hide();
// $("#end-time-label").hide();
// $("#video-end-time").hide();
}
updateCameraOptions();
document.getElementById("dataLoading").style.display = 'flex';
// Получение данных из полей ввода
const selectedDate = document.getElementById("selectedDate").value;
const videoTime = document.getElementById("video-time").value;
const selectedSerial = document.querySelector('input[name="camera-serial"]:checked').value;
// Объединяем дату и время и преобразуем в нужный формат
const combinedDateTime = combineDateTime(selectedDate, videoTime);
const response = await fetch(`/getData?serial=${selectedSerial}&selectedDate=${formatDate(selectedDate)}&selectedTime=${formatTime(videoTime)}&selectedChannel=${selectedChannel}`);
const data = await response.json();
console.log(data);
HasData = data.success;
if (data.success) {
console.log(`Данные доступны. DATAID: ${data.dataId}`)
document.getElementById("speed-bg").style.display = "none";
const requestData = {
serial: selectedSerial,
datetime: combinedDateTime,
};
fetch("/getspeedarchive", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestData),
})
.then((response) => response.json())
.then((data) => {
document.getElementById("dataLoading").style.display = 'none';
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const numberOfLabels = data.speeds.length;
// const labels = Array.from({ length: numberOfLabels }, () => "");
// Обновление данных графика
const chart = new Chart("speed", {
type: "line",
data: {
labels: data.names,
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: data.speeds,
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
ticks: {
autoSkip: false,
callback: function(value, index, values) {
const data = this.chart.data.labels;
if (index === 0 || index === values.length - 1) {
return data[index];
} else {
return '';
}
},
position: 'bottom',
maxRotation: 0,
},
grid: {
display: false,
},
},
},
},
});
const geoData = data.geo;
// Очищаем все слои на карте
map.eachLayer(layer => {
if (layer !== map) {
map.removeLayer(layer);
}
});
// Добавляем слой с плитками OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// Создаем слой для маршрута
const routeLayer = L.layerGroup().addTo(map);
// Создаем слой для маркеров
const markerLayer = L.layerGroup().addTo(map);
// Преобразуем координаты точек маршрута
const routePoints = geoData.map(point => [point.latitude, point.longitude]);
// Создаем линию маршрута
const route = L.polyline(routePoints, { color: 'red',weight: 5 }).addTo(routeLayer);
// Находим границы координат для центрирования карты
const bounds = L.latLngBounds(routePoints);
// Центрируем карту по первой координате
map.fitBounds(bounds, { padding: [50, 50] });
})
.catch((error) => {
document.getElementById("dataLoading").style.display = 'none';
var h1Element = document.querySelector('.speedometr h1');
h1Element.textContent = 'Ошибка отправки запроса.';
console.error("Ошибка при отправке запроса:", error);
});
} else {
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const chart = new Chart("speed", {
type: "line",
data: {
labels: "",
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
},
});
document.getElementById("dataLoading").style.display = 'none';
const speedBG = document.getElementById("speed-bg");
speedBG.style.display = 'flex';
}
}
const radioInputs = document.querySelectorAll(".radio-input");
radioInputs.forEach((input) => {
input.addEventListener("change", sendPostRequest);
});
const selectedDateInput = document.getElementById("selectedDate");
selectedDateInput.addEventListener("change", sendPostRequest);
const videoTimeInput = document.getElementById("video-time");
videoTimeInput.addEventListener("blur", sendPostRequest);
</script>
<script>
var now = new Date();
now.setHours(now.getHours() - 1);
var formattedTime = now.toISOString().substr(11, 8);
document.getElementById("video-time").value = formattedTime;
// const startTimeInput = document.getElementById('video-time');
// const endTimeInput = document.getElementById('video-end-time');
// const startTime = new Date(`1970-01-01T${startTimeInput.value}Z`);
// startTime.setHours(startTime.getHours() - 3);
// startTime.setSeconds(startTime.getSeconds() + 60);
// const hours = startTime.getHours().toString().padStart(2, '0');
// const minutes = startTime.getMinutes().toString().padStart(2, '0');
// const seconds = startTime.getSeconds().toString().padStart(2, '0');
// const endTimeString = `${hours}:${minutes}:${seconds}`;
// endTimeInput.value = endTimeString;
</script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const prevMonthBtn = document.getElementById("prevMonth");
const nextMonthBtn = document.getElementById("nextMonth");
const monthYear = document.getElementById("monthYear");
const datesContainer = document.getElementById("dates");
const dateForm = document.getElementById("dateForm");
const selectedDateInput = document.getElementById("selectedDate");
let currentDate = new Date();
let selectedDate = currentDate;
selectedDateInput.value = selectedDate.toISOString();
function renderCalendar() {
// Очистить предыдущий календарь
datesContainer.innerHTML = "";
// Установить заголовок с месяцем и годом
const options = { year: "numeric", month: "long" };
const formattedDate = currentDate.toLocaleDateString("ru-RU", options);
const formattedMonthYear = formattedDate.charAt(0).toUpperCase() + formattedDate.slice(1);
monthYear.textContent = formattedMonthYear.replace('г.', '');
// Найти первый день текущего месяца
const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
// Определить день недели, с которого начнется месяц
const startingDay = firstDayOfMonth.getDay() - 1;
// Определить количество дней в текущем месяце
const daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0).getDate();
// Создать дни месяца
for (let i = 0; i < startingDay; i++) {
const emptyDay = document.createElement("div");
emptyDay.classList.add("empty-day");
datesContainer.appendChild(emptyDay);
}
for (let day = 1; day <= daysInMonth; day++) {
const dateCell = document.createElement("div");
dateCell.textContent = day;
dateCell.classList.add("date");
if (selectedDate.getDate() === day && selectedDate.getMonth() === currentDate.getMonth() && selectedDate.getFullYear() === currentDate.getFullYear()) {
dateCell.classList.add("selected");
}
dateCell.addEventListener("click", () => {
selectedDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), day);
renderCalendar();
selectedDateInput.value = selectedDate.toISOString();
sendPostRequest();
});
datesContainer.appendChild(dateCell);
}
}
// Перейти на предыдущий месяц
prevMonthBtn.addEventListener("click", () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
renderCalendar();
});
// Перейти на следующий месяц
nextMonthBtn.addEventListener("click", () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
renderCalendar();
});
// Инициализировать календарь
renderCalendar();
});
</script>
<script>
function formatDate(selectedDate) {
const date = new Date(selectedDate);
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}${month}${day}`;
}
function formatTime(videoTime) {
const parts = videoTime.split(':');
const hours = parts[0].toString().padStart(2, '0');
const minutes = parts[1].toString().padStart(2, '0');
const seconds = parts[2].toString().padStart(2, '0');
return `${hours}${minutes}${seconds}`;
}
function addOneHourToTime(videoTime) {
const parts = videoTime.split(':');
let hours = parseInt(parts[0], 10);
hours += 1;
const minutes = parts[1].toString().padStart(2, '0');
const seconds = parts[2].toString().padStart(2, '0');
return formatTime(`${hours}:${minutes}:${seconds}`);
}
function playVideo() {
const channel = document.getElementById("group-id").value;
const selectedDevice = document.querySelector('input[name="camera-serial"]:checked');
if (!selectedDevice) {
alert('Пожалуйста, выберите устройство из списка.');
return;
}
const startTimeInput = document.getElementById('video-time');
const selectedDateInput = document.getElementById('selectedDate');
const startTime = formatTime(startTimeInput.value);
const selectedDate = formatDate(selectedDateInput.value);
const endTime = addOneHourToTime(startTimeInput.value);
const serial = selectedDevice.value;
selectedChannel = channel;
if ($(`#ourreg-${serial}`).val() == "true") {
playNextCamerasInGroup();
} else {
if (channel === "") {
alert('Пожалуйста, выберите камеру из списка.');
return;
}
if (!HasData) {
alert('Пожалуйста, выберите другой временной период.');
return;
}
const url = `http://localhost:8081/playback?url=https%3A%2F%2F{{VIRTUAL_HOST}}%2Fhttp%2Fplayback.flv%3Fserial%3D${serial}%26channel%3D${channel}%26quality%3D1%26queryTime%3D${selectedDate}%26startTime%3D${startTime}%26endTime%3D${endTime}`;
window.open(url, '_blank');
}
}
</script>
<script>
let flvPlayers = [];
let currentCameraGroup = 1;
const camerasPerGroup = 5;
var totalCameras = 12 - 1;
const isSecure = window.location.protocol === "https:";
const baseURL = "https://{{VIRTUAL_HOST}}/http/playback.flv";
function stopAllCameras() {
flvPlayers.forEach(player => {
player.pause();
player.unload();
player.detachMediaElement();
player.destroy();
});
flvPlayers = [];
}
async function playNextCamerasInGroup() {
const channel = document.getElementById("group-id").value;
const selectedDevice = document.querySelector('input[name="camera-serial"]:checked');
const startTimeInput = document.getElementById('video-time');
// const endTimeInput = document.getElementById('video-end-time');
const selectedDateInput = document.getElementById('selectedDate');
const startTime = formatTime(startTimeInput.value);
// const endTime = formatTime(endTimeInput.value);
const selectedDate = formatDate(selectedDateInput.value);
// const endTime = addOneHourToTime(startTimeInput.value);
const serial = selectedDevice.value;
selectedChannel = channel;
let startCamera;
let endCamera;
if ($(`#ourreg-${serial}`).val() == "true") {
startCamera = currentCameraGroup === 1 ? 1 : (currentCameraGroup - 1) * camerasPerGroup;
endCamera = startCamera + camerasPerGroup - 1;
} else {
startCamera = currentCameraGroup === 1 ? 2 : (currentCameraGroup - 1) * camerasPerGroup + 1;
endCamera = startCamera + camerasPerGroup - 1;
}
if (startCamera > totalCameras) {
return;
}
stopAllCameras();
let videoElementIndex = 1;
for (let i = startCamera; i <= endCamera && i <= totalCameras; i++) {
const videoElement = document.getElementById(`camera-${videoElementIndex}`);
let flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive: true,
cors: true,
url: `${baseURL}?serial=${serial}&channel=${i}&quality=1&queryTime=${selectedDate}&startTime=${startTime}`,
}, {
enableWorker: true,
enableStashBuffer: false,
autoCleanupSourceBuffer: true,
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
flvPlayers.push(flvPlayer);
let hasStarted = false;
const checkStarted = () => {
if (!hasStarted && videoElement.readyState >= 2) {
hasStarted = true;
console.log(`Трансляция началась для камеры ${i}`);
}
};
const checkInterval = setInterval(checkStarted, 1000);
setTimeout(() => {
clearInterval(checkInterval);
if (!hasStarted) {
console.log(`Трансляция для камеры ${i} не началась, запрашиваем повторно...`);
flvPlayer.unload();
flvPlayer.load();
flvPlayer.play();
// if (i > 0) {
// i--;
// }
}
}, 3000);
videoElementIndex++;
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
function switchCameras(direction) {
if ((currentCameraGroup === 1 && direction === -1) || (currentCameraGroup === Math.ceil(totalCameras / camerasPerGroup) && direction === 1)) {
return;
}
currentCameraGroup += direction;
if (currentCameraGroup < 1) {
currentCameraGroup = Math.ceil(totalCameras / camerasPerGroup);
} else if (currentCameraGroup > Math.ceil(totalCameras / camerasPerGroup)) {
currentCameraGroup = 1;
}
playNextCamerasInGroup();
}
</script>
<script>
window.addEventListener('DOMContentLoaded', function() {
var mapContainer = document.querySelector('.map');
var mapArea = document.getElementById('map');
mapArea.style.height = (mapContainer.clientHeight) + 'px';
mapArea.style.width = (mapContainer.clientWidth) + 'px';
});
window.addEventListener("resize", function (event) {
var mapContainer = document.querySelector('.map');
var mapArea = document.getElementById('map');
mapArea.style.height = (mapContainer.clientHeight) + 'px';
mapArea.style.width = (mapContainer.clientWidth) + 'px';
});
var startPoint = [0, 0];
var endPoint = [0, 0];
let map;
// Создаем карту Leaflet
map = L.map('map').setView([59.855198, 30.282995], 10);
// Добавляем базовый слой OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// Создаем маркеры
var startMarker = L.marker(startPoint, {
icon: L.divIcon({
className: 'custom-icon',
html: '<div style="background-color: red; width: 14px; height: 14px; border: 2px solid white; border-radius: 50%;"></div>'
})
}).addTo(map);
var endMarker = L.marker(endPoint, {
icon: L.divIcon({
className: 'custom-icon',
html: '<div style="background-color: red; width: 14px; height: 14px; border: 2px solid white; border-radius: 50%;"></div>'
})
}).addTo(map);
// Создаем линию маршрута
var route = L.polyline([startPoint, endPoint], { color: 'red', weight: 6 }).addTo(map);
// Скрыть кнопки приближения/отдаления
map.zoomControl.remove();
// Скрыть информационную панель
map.attributionControl.remove();
</script>
<script>
// Скрытие/Показ дополнительных меню аккаунта
const accountMain = document.getElementById('account-main');
const accountAdditional = document.getElementById('account-additional');
const accountUp = document.getElementById('up');
const accountDown = document.getElementById('down');
accountAdditional.style.display = 'none';
accountUp.style.display = 'none';
accountMain.addEventListener('click', () => {
if (accountAdditional.style.display === 'none') {
accountAdditional.style.display = 'flex';
accountUp.style.display = 'unset';
accountDown.style.display = 'none';
} else {
accountAdditional.style.display = 'none';
accountUp.style.display = 'none';
accountDown.style.display = 'unset';
}
});
</script>
<script>
Chart.defaults.color = "rgba(0, 0, 0, 0.4)";
Chart.defaults.font.size = 15;
Chart.defaults.font.weight = 400;
var speedData = {
labels: [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
],
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
};
var speedOptions = {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
};
new Chart("speed", {
type: "line",
data: speedData,
options: speedOptions,
});
</script>
<script>
// Получаем ссылки на элементы
const videoContainers = document.querySelectorAll('.stream-video-container video');
const popup = document.getElementById('video-popup');
const popupVideo = document.getElementById('popup-video');
const closePopup = document.getElementById('close-popup');
const popupVideoContainer = document.getElementById('popup-video-container');
const popupContainer = document.getElementById('video-popup-content');
let originalVideo = null; // Сохраняем оригинальное видео элемент
// Функция для открытия попапа с видео
function openVideoPopup(video) {
// Сохраняем оригинальное видео
originalVideo = video;
// Меняем стили видео
video.style.position = 'fixed';
video.style.top = '10%';
video.style.right = '0';
video.style.width = '90%';
video.style.height = '80%';
video.style.zIndex = '1001';
popup.style.display = 'block';
popupContainer.style.width = '100%';
popupContainer.style.height = '80%';
}
// Функция для закрытия попапа с видео
function closeVideoPopup() {
// Восстанавливаем оригинальные стили видео
if (originalVideo) {
originalVideo.style.position = '';
originalVideo.style.top = '';
originalVideo.style.left = '';
originalVideo.style.width = '';
originalVideo.style.height = '';
originalVideo.style.zIndex = '';
// Очищаем контейнер попапа
popup.style.display = 'none';
// Сбрасываем оригинальное видео
originalVideo = null;
}
}
// Добавляем обработчики событий для клика на видео и кнопку закрытия
videoContainers.forEach((video) => {
video.addEventListener('click', () => {
openVideoPopup(video);
});
});
closePopup.addEventListener('click', () => {
closeVideoPopup();
});
// Закрыть попап при клике вне его области
window.addEventListener('click', (event) => {
if (event.target === popup) {
closeVideoPopup();
}
});
// Закрыть попап при нажатии на клавишу Esc
window.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
closeVideoPopup();
}
});
</script>
</body>
</html>