1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

UI changes, accessibility features, ffmpeg adjustments

This commit is contained in:
NoobishSVK
2024-01-31 21:28:25 +01:00
parent 525ae519d7
commit 68e60223a3
18 changed files with 1056 additions and 228 deletions

49
web/js/dropdown.js Normal file
View File

@@ -0,0 +1,49 @@
// Variables
const $dropdowns = $('.dropdown');
const $input = $('input');
const $listOfOptions = $('.option');
let currentDropdown = null; // Track the currently clicked dropdown
// Functions
const toggleDropdown = (event) => {
event.stopPropagation();
const $currentDropdown = $(event.currentTarget);
// Close the previously opened dropdown if any
$dropdowns.not($currentDropdown).removeClass('opened');
$currentDropdown.toggleClass('opened');
currentDropdown = $currentDropdown.hasClass('opened') ? $currentDropdown : null;
};
const selectOption = (event) => {
const $currentDropdown = currentDropdown;
$currentDropdown.find('input').val($(event.currentTarget).text());
if($currentDropdown.attr('id') == 'data-ant') {
socket.send("Z" + $(event.currentTarget).attr('data-value'));
}
// Use setTimeout to delay class removal
setTimeout(() => {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}, 10); // Adjust the delay as needed
};
const closeDropdownFromOutside = (event) => {
const $currentDropdown = currentDropdown && $(currentDropdown);
const isClickedInsideDropdown = $currentDropdown && $currentDropdown.has(event.target).length > 0;
if (!isClickedInsideDropdown && $currentDropdown && $currentDropdown.hasClass('opened')) {
$currentDropdown.removeClass('opened');
currentDropdown = null;
}
};
// Event Listeners
$(document).on('click', closeDropdownFromOutside);
$listOfOptions.on('click', selectOption);
$dropdowns.on('click', toggleDropdown);

View File

@@ -4,6 +4,8 @@ var port = hostParts[1] || '8080'; // Extract the port or use a default (e.g., 8
var socketAddress = 'ws://' + hostname + ':' + port + '/text'; // Use 'wss' for secure WebSocket connections (recommended for external access)
var socket = new WebSocket(socketAddress);
var parsedData;
var data = [];
let signalChart;
const europe_programmes = [
"No PTY", "News", "Current Affairs", "Info",
@@ -16,130 +18,16 @@ const europe_programmes = [
];
$(document).ready(function() {
var dataContainer = $('#data-container');
var canvas = $('#signal-canvas')[0];
var context = canvas.getContext('2d');
var signalToggle = $("#signal-units-toggle");
canvas.width = canvas.parentElement.clientWidth;
var data = [];
var maxDataPoints = 300;
var pointWidth = (canvas.width - 80) / maxDataPoints;
canvas.height = canvas.parentElement.clientHeight;
getInitialSettings();
// Start updating the canvas
updateCanvas();
function updateCanvas() {
const color2 = getComputedStyle(document.documentElement).getPropertyValue('--color-2').trim();
const color4 = getComputedStyle(document.documentElement).getPropertyValue('--color-4').trim();
while (data.length >= maxDataPoints) {
data.shift();
}
// Modify the WebSocket onmessage callback
socket.onmessage = (event) => {
parsedData = JSON.parse(event.data);
updatePanels(parsedData);
// Push the new signal data to the array
data.push(parsedData.signal);
const actualLowestValue = Math.min(...data);
const actualHighestValue = Math.max(...data);
zoomMinValue = actualLowestValue - ((actualHighestValue - actualLowestValue) / 2);
zoomMaxValue = actualHighestValue + ((actualHighestValue - actualLowestValue) / 2);
zoomAvgValue = (zoomMaxValue - zoomMinValue) / 2 + zoomMinValue;
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw the signal graph with smooth shifting
context.beginPath();
const startingIndex = Math.max(0, data.length - maxDataPoints);
for (let i = startingIndex; i < data.length; i++) {
const x = canvas.width - (data.length - i) * pointWidth - 40;
const y = canvas.height - (data[i] - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
if (i === startingIndex) {
context.moveTo(x, y);
} else {
const prevX = canvas.width - (data.length - i + 1) * pointWidth - 40;
const prevY = canvas.height - (data[i - 1] - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
// Interpolate between the current and previous points
const interpolatedX = (x + prevX) / 2;
const interpolatedY = (y + prevY) / 2;
context.quadraticCurveTo(prevX, prevY, interpolatedX, interpolatedY);
}
}
context.strokeStyle = color4;
context.lineWidth = 1;
context.stroke();
// Draw horizontal lines for lowest, highest, and average values
context.strokeStyle = color2;
context.lineWidth = 1;
// Draw the lowest value line
const lowestY = canvas.height - (zoomMinValue - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
context.beginPath();
context.moveTo(40, lowestY - 18);
context.lineTo(canvas.width - 40, lowestY - 18);
context.stroke();
// Draw the highest value line
const highestY = canvas.height - (zoomMaxValue - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
context.beginPath();
context.moveTo(40, highestY + 10);
context.lineTo(canvas.width - 40, highestY + 10);
context.stroke();
const avgY = canvas.height / 2;
context.beginPath();
context.moveTo(40, avgY - 7);
context.lineTo(canvas.width - 40, avgY - 7);
context.stroke();
// Label the lines with their values
context.fillStyle = color4;
context.font = '12px Titillium Web';
const signalUnit = localStorage.getItem('signalUnit');
let offset;
if (signalUnit === 'dbuv') {
offset = 11.25;
} else if (signalUnit === 'dbm') {
offset = 120;
} else {
offset = 0;
}
context.textAlign = 'right';
context.fillText(`${(zoomMinValue - offset).toFixed(1)}`, 35, lowestY - 14);
context.fillText(`${(zoomMaxValue - offset).toFixed(1)}`, 35, highestY + 14);
context.fillText(`${(zoomAvgValue - offset).toFixed(1)}`, 35, avgY - 3);
context.textAlign = 'left';
context.fillText(`${(zoomMinValue - offset).toFixed(1)}`, canvas.width - 35, lowestY - 14);
context.fillText(`${(zoomMaxValue - offset).toFixed(1)}`, canvas.width - 35, highestY + 14);
context.fillText(`${(zoomAvgValue - offset).toFixed(1)}`, canvas.width - 35, avgY - 3);
// Update the data container with the latest data
dataContainer.html(event.data + '<br>');
};
requestAnimationFrame(updateCanvas);
}
initCanvas();
signalToggle.on("change", function() {
const signalText = localStorage.getItem('signalUnit');
@@ -250,6 +138,128 @@ function getInitialSettings() {
}
});
}
function initCanvas(parsedData) {
signalToggle = $("#signal-units-toggle");
// Check if signalChart is already initialized
if (!signalChart) {
signalChart = {
canvas: $('#signal-canvas')[0],
context: $('#signal-canvas')[0].getContext('2d'),
parsedData: parsedData,
maxDataPoints: 300,
}
signalChart.pointWidth = (signalChart.canvas.width - 80) / signalChart.maxDataPoints;
}
updateCanvas(parsedData, signalChart);
}
function updateCanvas(parsedData, signalChart) {
const color2 = getComputedStyle(document.documentElement).getPropertyValue('--color-2').trim();
const color4 = getComputedStyle(document.documentElement).getPropertyValue('--color-4').trim();
const {context, canvas, maxDataPoints, pointWidth} = signalChart;
while (data.length >= signalChart.maxDataPoints) {
data.shift();
}
const actualLowestValue = Math.min(...data);
const actualHighestValue = Math.max(...data);
zoomMinValue = actualLowestValue - ((actualHighestValue - actualLowestValue) / 2);
zoomMaxValue = actualHighestValue + ((actualHighestValue - actualLowestValue) / 2);
zoomAvgValue = (zoomMaxValue - zoomMinValue) / 2 + zoomMinValue;
// Clear the canvas
if(context) {
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw the signal graph with smooth shifting
context.beginPath();
}
const startingIndex = Math.max(0, data.length - maxDataPoints);
for (let i = startingIndex; i < data.length; i++) {
const x = canvas.width - (data.length - i) * pointWidth - 40;
const y = canvas.height - (data[i] - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
if (i === startingIndex) {
context.moveTo(x, y);
} else {
const prevX = canvas.width - (data.length - i + 1) * pointWidth - 40;
const prevY = canvas.height - (data[i - 1] - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
// Interpolate between the current and previous points
const interpolatedX = (x + prevX) / 2;
const interpolatedY = (y + prevY) / 2;
context.quadraticCurveTo(prevX, prevY, interpolatedX, interpolatedY);
}
}
context.strokeStyle = color4;
context.lineWidth = 1;
context.stroke();
// Draw horizontal lines for lowest, highest, and average values
context.strokeStyle = color2;
context.lineWidth = 1;
// Draw the lowest value line
const lowestY = canvas.height - (zoomMinValue - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
context.beginPath();
context.moveTo(40, lowestY - 18);
context.lineTo(canvas.width - 40, lowestY - 18);
context.stroke();
// Draw the highest value line
const highestY = canvas.height - (zoomMaxValue - zoomMinValue) * (canvas.height / (zoomMaxValue - zoomMinValue));
context.beginPath();
context.moveTo(40, highestY + 10);
context.lineTo(canvas.width - 40, highestY + 10);
context.stroke();
const avgY = canvas.height / 2;
context.beginPath();
context.moveTo(40, avgY - 7);
context.lineTo(canvas.width - 40, avgY - 7);
context.stroke();
// Label the lines with their values
context.fillStyle = color4;
context.font = '12px Titillium Web';
const signalUnit = localStorage.getItem('signalUnit');
let offset;
if (signalUnit === 'dbuv') {
offset = 11.25;
} else if (signalUnit === 'dbm') {
offset = 120;
} else {
offset = 0;
}
context.textAlign = 'right';
context.fillText(`${(zoomMinValue - offset).toFixed(1)}`, 35, lowestY - 14);
context.fillText(`${(zoomMaxValue - offset).toFixed(1)}`, 35, highestY + 14);
context.fillText(`${(zoomAvgValue - offset).toFixed(1)}`, 35, avgY - 3);
context.textAlign = 'left';
context.fillText(`${(zoomMinValue - offset).toFixed(1)}`, canvas.width - 35, lowestY - 14);
context.fillText(`${(zoomMaxValue - offset).toFixed(1)}`, canvas.width - 35, highestY + 14);
context.fillText(`${(zoomAvgValue - offset).toFixed(1)}`, canvas.width - 35, avgY - 3);
requestAnimationFrame(() => updateCanvas(parsedData, signalChart));
}
socket.onmessage = (event) => {
parsedData = JSON.parse(event.data);
updatePanels(parsedData);
data.push(parsedData.signal);
};
function compareNumbers(a, b) {
return a - b;
@@ -444,6 +454,7 @@ function updateDataElements(parsedData) {
$('#data-rt0').html(processString(parsedData.rt0, parsedData.rt0_errors));
$('#data-rt1').html(processString(parsedData.rt1, parsedData.rt1_errors));
$('.data-flag').html(`<i title="${parsedData.country_name}" class="flag-sm flag-sm-${parsedData.country_iso}"></i>`);
$('#data-ant').find('input').val($(parsedData.ant).text());
}
let isEventListenerAdded = false;
@@ -500,9 +511,9 @@ function createListItem(element) {
function updateButtonState(buttonId, value) {
var button = $("#" + buttonId);
if (value === 0) {
button.addClass("bg-gray");
button.addClass("btn-disabled");
} else {
button.removeClass("bg-gray");
button.removeClass("btn-disabled");
}
}

View File

@@ -1,53 +1,59 @@
/* Themes */
const themes = {
theme1: ['#111', '#aaa'],
theme2: ['#1f0c0c', '#ff7070'],
theme3: ['#121c0c', '#a9ff70'],
theme4: ['#0c1c1b', '#68f7ee'],
theme5: ['#171106', '#f5b642'],
theme6: ['#21091d', '#ed51d3'],
theme7: ['#1d1838', '#8069fa'],
theme8: ['#000', '#888'],
};
// Themes
const themes = {
theme1: ['#111', '#aaa'],
theme2: ['#1f0c0c', '#ff7070'],
theme3: ['#121c0c', '#a9ff70'],
theme4: ['#0c1c1b', '#68f7ee'],
theme5: ['#171106', '#f5b642'],
theme6: ['#21091d', '#ed51d3'],
theme7: ['#1d1838', '#8069fa'],
theme8: ['#000', '#888'],
};
/* Signal Units */
const signalUnits = {
dbf: ['dBf'],
dbuv: ['dBµV'],
dbm: ['dBm'],
};
// Signal Units
const signalUnits = {
dbf: ['dBf'],
dbuv: ['dBµV'],
dbm: ['dBm'],
};
$(document).ready(() => {
const themeSelector = $('#theme-selector');
const savedTheme = localStorage.getItem('theme');
$(document).ready(() => {
// Theme Selector
const themeSelector = $('#theme-selector');
const savedTheme = localStorage.getItem('theme');
const savedUnit = localStorage.getItem('signalUnit');
if (savedTheme && themes[savedTheme]) {
setTheme(savedTheme);
themeSelector.val(savedTheme);
}
if (savedTheme && themes[savedTheme]) {
setTheme(savedTheme);
themeSelector.find('input').val(themeSelector.find('.option[data-value="' + savedTheme + '"]').text());
}
themeSelector.on('change', (event) => {
const selectedTheme = event.target.value;
setTheme(selectedTheme);
localStorage.setItem('theme', selectedTheme);
});
themeSelector.on('click', '.option', (event) => {
const selectedTheme = $(event.target).data('value');
setTheme(selectedTheme);
themeSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
localStorage.setItem('theme', selectedTheme);
});
const signalSelector = $('#signal-selector');
// Signal Selector
const signalSelector = $('#signal-selector');
if (localStorage.getItem('signalUnit')) {
signalSelector.val(localStorage.getItem('signalUnit'));
}
if (localStorage.getItem('signalUnit')) {
signalSelector.find('input').val(signalSelector.find('.option[data-value="' + savedUnit + '"]').text());
}
signalSelector.on('change', (event) => {
const selectedSignalUnit = event.target.value;
localStorage.setItem('signalUnit', selectedSignalUnit);
});
signalSelector.on('click', '.option', (event) => {
const selectedSignalUnit = $(event.target).data('value');
signalSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
localStorage.setItem('signalUnit', selectedSignalUnit);
});
});
function setTheme(themeName) {
const themeColors = themes[themeName];
if (themeColors) {
$(':root').css('--color-main', themeColors[0]);
$(':root').css('--color-main-bright', themeColors[1]);
}
}
function setTheme(themeName) {
const themeColors = themes[themeName];
if (themeColors) {
$(':root').css('--color-main', themeColors[0]);
$(':root').css('--color-main-bright', themeColors[1]);
}
}

View File

@@ -1,3 +1,4 @@
$.getScript('/js/main.js');
$.getScript('/js/dropdown.js');
$.getScript('/js/modal.js');
$.getScript('/js/settings.js');