mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
CAT coloring
This commit is contained in:
@@ -33,10 +33,12 @@
|
||||
<h5 class="mb-0">DX Cluster - spot list</h5>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="fullscreen-wavelog-text" style="display: none; font-weight: 500; color: var(--bs-body-color);">www.wavelog.org</span>
|
||||
<button type="button" class="btn btn-sm" id="fullscreenToggle" title="<?= __("Toggle Fullscreen"); ?>" style="background: none; border: none; padding: 0;">
|
||||
<i class="fas fa-expand" id="fullscreenIcon" style="font-size: 1.2rem;"></i>
|
||||
</button>
|
||||
<a href="https://www.wavelog.org" target="_blank" class="fullscreen-wavelog-text" style="display: none; font-weight: 500; color: var(--bs-body-color); text-decoration: none;">www.wavelog.org</a>
|
||||
<div id="fullscreenToggleWrapper" style="cursor: pointer; padding: 0.5rem; margin: -0.5rem;">
|
||||
<button type="button" class="btn btn-sm" id="fullscreenToggle" title="<?= __("Toggle Fullscreen"); ?>" style="background: none; border: none; padding: 0.5rem;">
|
||||
<i class="fas fa-expand" id="fullscreenIcon" style="font-size: 1.2rem;"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-1">
|
||||
|
||||
@@ -153,6 +153,78 @@ tbody a {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* CAT Control - Locked Sorting */
|
||||
.spottable.cat-sorting-locked thead th {
|
||||
cursor: not-allowed !important;
|
||||
pointer-events: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.spottable.cat-sorting-locked thead th:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.spottable.cat-sorting-locked thead th.sorting_asc::after,
|
||||
.spottable.cat-sorting-locked thead th.sorting_desc::after {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* CAT Control - Frequency Gradient */
|
||||
.cat-frequency-gradient {
|
||||
transition: background-color 0.3s ease, var(--bs-table-bg) 0.3s ease !important;
|
||||
}
|
||||
|
||||
/* Force gradient background to override Bootstrap striping AND spot lifecycle colors - MAXIMUM SPECIFICITY */
|
||||
/* Override normal rows */
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient,
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient,
|
||||
table.table-striped tbody tr.cat-frequency-gradient,
|
||||
.table-striped > tbody > tr.cat-frequency-gradient,
|
||||
table tbody tr.cat-frequency-gradient {
|
||||
background-color: var(--bs-table-bg) !important;
|
||||
}
|
||||
|
||||
/* Override expiring spots (red) */
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient.spot-expiring,
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient.spot-expiring,
|
||||
table tbody tr.cat-frequency-gradient.spot-expiring {
|
||||
background-color: var(--bs-table-bg) !important;
|
||||
}
|
||||
|
||||
/* Override very new spots (green) */
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient.spot-very-new,
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient.spot-very-new,
|
||||
table tbody tr.cat-frequency-gradient.spot-very-new {
|
||||
background-color: var(--bs-table-bg) !important;
|
||||
}
|
||||
|
||||
/* Override fresh spots - force gradient color over fresh blue */
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient.fresh,
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient.fresh,
|
||||
table tbody tr.cat-frequency-gradient.fresh {
|
||||
/* Override both the variable and background directly */
|
||||
background-color: var(--bs-table-bg) !important;
|
||||
/* Prevent .fresh class from setting its own --bs-table-bg */
|
||||
transition: background-color 0.3s ease !important;
|
||||
}
|
||||
|
||||
/* Override even and odd striping */
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient:nth-of-type(odd),
|
||||
table.table.table-sm.table-bordered.table-hover.table-striped.spottable tbody tr.cat-frequency-gradient:nth-of-type(even),
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient:nth-of-type(odd),
|
||||
table.dataTable.table-striped tbody tr.cat-frequency-gradient:nth-of-type(even),
|
||||
table.table-striped tbody tr.cat-frequency-gradient:nth-of-type(odd),
|
||||
table.table-striped tbody tr.cat-frequency-gradient:nth-of-type(even),
|
||||
.table-striped > tbody > tr.cat-frequency-gradient:nth-of-type(odd),
|
||||
.table-striped > tbody > tr.cat-frequency-gradient:nth-of-type(even) {
|
||||
--bs-table-accent-bg: transparent !important;
|
||||
--bs-table-striped-bg: transparent !important;
|
||||
}
|
||||
|
||||
.cat-frequency-gradient:hover {
|
||||
filter: brightness(0.95);
|
||||
}
|
||||
|
||||
/* Status bar styling */
|
||||
.status-bar {
|
||||
font-size: 0.875rem;
|
||||
@@ -301,6 +373,55 @@ tbody a {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Fullscreen toggle button wrapper - large clickable area */
|
||||
#fullscreenToggleWrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border-radius: 0.25rem;
|
||||
transition: background-color 150ms ease;
|
||||
}
|
||||
|
||||
#fullscreenToggleWrapper:hover {
|
||||
background-color: rgba(0, 0, 0, 0.08) !important;
|
||||
}
|
||||
|
||||
/* Fullscreen toggle button - ensure proper clickable area */
|
||||
#fullscreenToggle {
|
||||
min-width: 48px;
|
||||
min-height: 48px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer !important;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#fullscreenToggle:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
#fullscreenIcon {
|
||||
pointer-events: none; /* Icon shouldn't intercept clicks */
|
||||
font-size: 1.4rem !important; /* Make icon slightly bigger too */
|
||||
}
|
||||
|
||||
/* Ensure wavelog text doesn't overlap button */
|
||||
.fullscreen-wavelog-text {
|
||||
pointer-events: auto;
|
||||
flex-shrink: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fullscreen-wavelog-text:hover {
|
||||
text-decoration: underline !important;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Fullscreen mode - CLEAN REBUILD */
|
||||
.bandmap-logo-fullscreen {
|
||||
display: none;
|
||||
|
||||
@@ -384,16 +384,17 @@ $(function() {
|
||||
'orderable': false
|
||||
}
|
||||
],
|
||||
search: { smart: true },
|
||||
drawCallback: function(settings) {
|
||||
// Update status bar after table is drawn (including after search)
|
||||
let totalRows = cachedSpotData ? cachedSpotData.length : 0;
|
||||
let displayedRows = this.api().rows({ search: 'applied' }).count();
|
||||
updateStatusBar(totalRows, displayedRows, getServerFilterText(), getClientFilterText(), false, false);
|
||||
}
|
||||
});
|
||||
search: { smart: true },
|
||||
drawCallback: function(settings) {
|
||||
// Update status bar after table is drawn (including after search)
|
||||
let totalRows = cachedSpotData ? cachedSpotData.length : 0;
|
||||
let displayedRows = this.api().rows({ search: 'applied' }).count();
|
||||
updateStatusBar(totalRows, displayedRows, getServerFilterText(), getClientFilterText(), false, false);
|
||||
|
||||
$('.spottable tbody').off('click', 'tr').on('click', 'tr', function(e) {
|
||||
// Note: CAT frequency gradient is now updated only from updateCATui (every 3s)
|
||||
// to prevent recursion issues with table redraws
|
||||
}
|
||||
}); $('.spottable tbody').off('click', 'tr').on('click', 'tr', function(e) {
|
||||
// Don't trigger row click if clicking on a link (LoTW, POTA, SOTA, WWFF, QRZ, etc.)
|
||||
if ($(e.target).is('a') || $(e.target).closest('a').length) {
|
||||
return;
|
||||
@@ -1039,18 +1040,36 @@ $(function() {
|
||||
}
|
||||
|
||||
// Add row with appropriate class
|
||||
let addedRow = table.rows.add(data).draw().nodes().to$();
|
||||
|
||||
if (rowClass) {
|
||||
let addedRow = table.rows.add(data).draw().nodes().to$();
|
||||
addedRow.addClass(rowClass);
|
||||
if (ttl === 0) {
|
||||
console.log('Added expiring class to row:', addedRow.hasClass('spot-expiring'));
|
||||
}
|
||||
} else {
|
||||
table.rows.add(data).draw();
|
||||
}
|
||||
|
||||
// Apply CAT frequency gradient AFTER adding lifecycle classes to ensure it overrides
|
||||
if (isCatTrackingEnabled && currentRadioFrequency) {
|
||||
const spotFreqKhz = single.frequency * 1000; // Convert MHz to kHz
|
||||
const gradientColor = getFrequencyGradientColor(spotFreqKhz, currentRadioFrequency);
|
||||
if (gradientColor) {
|
||||
// Store gradient color and frequency for later reapplication
|
||||
addedRow.attr('data-spot-frequency', spotFreqKhz);
|
||||
addedRow.attr('data-gradient-color', gradientColor);
|
||||
// Use setProperty with priority 'important' to force override
|
||||
addedRow.each(function() {
|
||||
this.style.setProperty('--bs-table-bg', gradientColor, 'important');
|
||||
this.style.setProperty('--bs-table-accent-bg', gradientColor, 'important');
|
||||
this.style.setProperty('background-color', gradientColor, 'important');
|
||||
});
|
||||
addedRow.addClass('cat-frequency-gradient');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove "fresh" highlight after 10 seconds
|
||||
// (CAT gradient is updated every 3s from updateCATui, no need to force here)
|
||||
setTimeout(function () {
|
||||
$(".fresh").removeClass("fresh");
|
||||
}, 10000);
|
||||
@@ -1532,23 +1551,7 @@ $(function() {
|
||||
startRefreshTimer();
|
||||
});
|
||||
} // Highlight rows within ±20 kHz of specified frequency (for CAT integration)
|
||||
function highlight_current_qrg(qrg) {
|
||||
var table = get_dtable();
|
||||
table.rows().eq(0).each( function ( index ) {
|
||||
let row = table.row( index );
|
||||
var d=row.data();
|
||||
var distance=Math.abs(parseInt(d[1])-qrg);
|
||||
if (distance<=20) {
|
||||
distance++;
|
||||
alpha=(.5/distance);
|
||||
$(row.node()).css('--bs-table-bg', 'rgba(0,0,255,' + alpha + ')');
|
||||
$(row.node()).css('--bs-table-accent-bg', 'rgba(0,0,255,' + alpha + ')');
|
||||
} else {
|
||||
$(row.node()).css('--bs-table-bg', '');
|
||||
$(row.node()).css('--bs-table-accent-bg', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
// Old highlight_current_qrg function removed - now using updateFrequencyGradientColors
|
||||
|
||||
// Initialize DataTable
|
||||
var table=get_dtable();
|
||||
@@ -2022,8 +2025,109 @@ $(function() {
|
||||
|
||||
var isCatTrackingEnabled = false; // Track CAT Control button state
|
||||
window.isCatTrackingEnabled = isCatTrackingEnabled; // Expose to window for cat.js
|
||||
var currentRadioFrequency = null; // Store current radio frequency in kHz
|
||||
var lastGradientFrequency = null; // Track last frequency used for gradient update
|
||||
|
||||
// Save reference to cat.js's updateCATui if it exists
|
||||
/**
|
||||
* Calculate frequency gradient color based on distance from radio frequency
|
||||
* @param {number} spotFreqKhz - Spot frequency in kHz
|
||||
* @param {number} radioFreqKhz - Radio frequency in kHz
|
||||
* @returns {string|null} - CSS background color or null if outside gradient range
|
||||
*/
|
||||
function getFrequencyGradientColor(spotFreqKhz, radioFreqKhz) {
|
||||
if (!radioFreqKhz || !isCatTrackingEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Determine if we're in LSB or USB mode (below/above 10 MHz)
|
||||
const isLSB = radioFreqKhz < 10000;
|
||||
|
||||
// Calculate frequency difference in kHz
|
||||
// For LSB: lower frequencies are "closer" to tune (radio freq - spot freq)
|
||||
// For USB: higher frequencies are "closer" to tune (spot freq - radio freq)
|
||||
let freqDiff;
|
||||
if (isLSB) {
|
||||
freqDiff = Math.abs(radioFreqKhz - spotFreqKhz);
|
||||
} else {
|
||||
freqDiff = Math.abs(spotFreqKhz - radioFreqKhz);
|
||||
}
|
||||
|
||||
// Maximum gradient range: 2.5 kHz
|
||||
const maxGradientKhz = 2.5;
|
||||
|
||||
if (freqDiff > maxGradientKhz) {
|
||||
return null; // Outside gradient range, use default color
|
||||
}
|
||||
|
||||
// Calculate gradient factor: 0 (perfectly tuned) to 1 (2.5 kHz away)
|
||||
const gradientFactor = freqDiff / maxGradientKhz;
|
||||
|
||||
// Violet color for perfectly tuned: rgb(138, 43, 226) - BlueViolet
|
||||
// Fade to transparent as we move away
|
||||
const alpha = 1 - gradientFactor; // 1 at perfect tune, 0 at 2.5 kHz
|
||||
const intensity = 0.3 + (alpha * 0.4); // Range from 0.3 to 0.7 alpha
|
||||
|
||||
return `rgba(138, 43, 226, ${intensity})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update frequency gradient colors for all visible table rows
|
||||
* Called when radio frequency changes
|
||||
*/
|
||||
function updateFrequencyGradientColors(forceUpdate = false) {
|
||||
if (!isCatTrackingEnabled || !currentRadioFrequency) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip update if frequency hasn't changed significantly (unless forced)
|
||||
// Only update if frequency changed by more than 500 Hz to reduce flickering
|
||||
if (!forceUpdate && lastGradientFrequency !== null) {
|
||||
const freqDiff = Math.abs(currentRadioFrequency - lastGradientFrequency);
|
||||
if (freqDiff < 0.5) { // 500 Hz threshold
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lastGradientFrequency = currentRadioFrequency;
|
||||
var table = get_dtable();
|
||||
let coloredCount = 0;
|
||||
|
||||
// Iterate through all visible rows
|
||||
table.rows({ search: 'applied' }).every(function() {
|
||||
const row = this.node();
|
||||
const rowData = this.data();
|
||||
|
||||
if (!rowData || !rowData[2]) return;
|
||||
|
||||
// Get spot frequency (column 2, in MHz)
|
||||
const spotFreqMhz = parseFloat(rowData[2]);
|
||||
const spotFreqKhz = spotFreqMhz * 1000;
|
||||
|
||||
// Calculate gradient color
|
||||
const gradientColor = getFrequencyGradientColor(spotFreqKhz, currentRadioFrequency);
|
||||
|
||||
// Store gradient data for persistence
|
||||
$(row).attr('data-spot-frequency', spotFreqKhz);
|
||||
|
||||
if (gradientColor) {
|
||||
coloredCount++;
|
||||
// Store and apply gradient color directly to override Bootstrap striping
|
||||
$(row).attr('data-gradient-color', gradientColor);
|
||||
// Use setProperty with 'important' priority to force override .fresh, .spot-expiring, etc.
|
||||
row.style.setProperty('--bs-table-bg', gradientColor, 'important');
|
||||
row.style.setProperty('--bs-table-accent-bg', gradientColor, 'important');
|
||||
row.style.setProperty('background-color', gradientColor, 'important');
|
||||
$(row).addClass('cat-frequency-gradient');
|
||||
} else {
|
||||
// Remove gradient styling if outside range
|
||||
$(row).removeAttr('data-gradient-color');
|
||||
$(row).removeClass('cat-frequency-gradient');
|
||||
row.style.removeProperty('--bs-table-bg');
|
||||
row.style.removeProperty('--bs-table-accent-bg');
|
||||
row.style.removeProperty('background-color');
|
||||
}
|
||||
});
|
||||
} // Save reference to cat.js's updateCATui if it exists
|
||||
var catJsUpdateCATui = window.updateCATui;
|
||||
|
||||
// Override updateCATui to add bandmap-specific behavior
|
||||
@@ -2034,6 +2138,9 @@ $(function() {
|
||||
|
||||
console.log('Bandmap CAT Update - Frequency:', data.frequency, 'Band:', band, 'Control enabled:', isCatTrackingEnabled);
|
||||
|
||||
// Store current radio frequency (convert Hz to kHz)
|
||||
currentRadioFrequency = data.frequency / 1000;
|
||||
|
||||
// Bandmap-specific: Update band filter if CAT Control is enabled
|
||||
if (isCatTrackingEnabled) {
|
||||
const currentBands = $("#band").val() || [];
|
||||
@@ -2067,12 +2174,10 @@ $(function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bandmap-specific: Highlight current QRG in the spot list
|
||||
if (data.frequency) {
|
||||
highlight_current_qrg((parseInt(data.frequency))/1000);
|
||||
}
|
||||
// Update frequency gradient colors for all visible rows
|
||||
updateFrequencyGradientColors();
|
||||
}
|
||||
|
||||
// Call cat.js's original updateCATui for standard CAT UI updates
|
||||
if (typeof catJsUpdateCATui === 'function') {
|
||||
@@ -2098,7 +2203,13 @@ $(function() {
|
||||
|
||||
let isFullscreen = false;
|
||||
|
||||
$('#fullscreenToggle').on('click', function() {
|
||||
// Handle clicks on both the button and wrapper
|
||||
$('#fullscreenToggle, #fullscreenToggleWrapper').on('click', function(e) {
|
||||
// Prevent double firing if clicking directly on button
|
||||
if (e.target.id === 'fullscreenToggle' && this.id === 'fullscreenToggleWrapper') {
|
||||
return;
|
||||
}
|
||||
|
||||
const container = $('#bandmapContainer');
|
||||
const icon = $('#fullscreenIcon');
|
||||
|
||||
@@ -2106,7 +2217,7 @@ $(function() {
|
||||
container.addClass('bandmap-fullscreen');
|
||||
$('body').addClass('fullscreen-active');
|
||||
icon.removeClass('fa-expand').addClass('fa-compress');
|
||||
$(this).attr('title', 'Exit Fullscreen');
|
||||
$('#fullscreenToggle').attr('title', 'Exit Fullscreen');
|
||||
|
||||
isFullscreen = true;
|
||||
|
||||
@@ -3001,6 +3112,87 @@ $(function() {
|
||||
$('.cat-control-info').remove();
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// CAT CONTROL - TABLE SORTING LOCK
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Lock table sorting to frequency column only (descending) when CAT Control is active
|
||||
*/
|
||||
function lockTableSortingToFrequency() {
|
||||
var table = get_dtable();
|
||||
|
||||
// Add class to table for CSS styling
|
||||
$('.spottable').addClass('cat-sorting-locked');
|
||||
|
||||
// Force sort by frequency (column 2) descending
|
||||
table.order([2, 'desc']).draw();
|
||||
|
||||
// Disable sorting on all columns
|
||||
table.settings()[0].aoColumns.forEach(function(col, index) {
|
||||
col.bSortable = false;
|
||||
});
|
||||
|
||||
// Disable click events on all column headers
|
||||
$('.spottable thead th').off('click.DT');
|
||||
|
||||
// Redraw column headers to update sort icons
|
||||
table.columns.adjust();
|
||||
|
||||
console.log('Table sorting locked to Frequency (DESC) only');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock table sorting when CAT Control is disabled
|
||||
*/
|
||||
function unlockTableSorting() {
|
||||
var table = get_dtable();
|
||||
|
||||
// Remove class from table
|
||||
$('.spottable').removeClass('cat-sorting-locked');
|
||||
|
||||
// Re-enable sorting on all columns that were originally sortable
|
||||
// Based on columnDefs: columns 5, 6, 7, 11, 12, 13, 14 are not sortable
|
||||
const nonSortableColumns = [5, 6, 7, 11, 12, 13, 14];
|
||||
|
||||
table.settings()[0].aoColumns.forEach(function(col, index) {
|
||||
if (!nonSortableColumns.includes(index)) {
|
||||
col.bSortable = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Re-enable DataTables default click handlers
|
||||
table.off('click.DT', 'thead th');
|
||||
|
||||
// Reset to default sort (frequency ascending)
|
||||
table.order([2, 'asc']).draw();
|
||||
|
||||
// Redraw column headers to update sort icons
|
||||
table.columns.adjust();
|
||||
|
||||
// Clear frequency gradient colors
|
||||
clearFrequencyGradientColors();
|
||||
|
||||
console.log('Table sorting unlocked');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all frequency gradient colors from table rows
|
||||
*/
|
||||
function clearFrequencyGradientColors() {
|
||||
var table = get_dtable();
|
||||
|
||||
table.rows().every(function() {
|
||||
const row = this.node();
|
||||
$(row).removeClass('cat-frequency-gradient');
|
||||
$(row).css({
|
||||
'--bs-table-bg': '',
|
||||
'--bs-table-accent-bg': '',
|
||||
'background-color': ''
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle CAT Control
|
||||
$('#toggleCatTracking').on('click', function() {
|
||||
let btn = $(this);
|
||||
@@ -3017,6 +3209,9 @@ $(function() {
|
||||
|
||||
// Re-enable band filter controls
|
||||
enableBandFilterControls();
|
||||
|
||||
// Unlock table sorting
|
||||
unlockTableSorting();
|
||||
} else {
|
||||
// Enable CAT Control
|
||||
btn.removeClass('btn-secondary').addClass('btn-success');
|
||||
@@ -3034,6 +3229,9 @@ $(function() {
|
||||
// Disable band filter controls
|
||||
disableBandFilterControls();
|
||||
|
||||
// Lock table sorting to frequency only
|
||||
lockTableSortingToFrequency();
|
||||
|
||||
// Immediately apply current radio frequency if available
|
||||
if (window.lastCATData && window.lastCATData.frequency) {
|
||||
console.log('Applying current radio frequency:', window.lastCATData.frequency);
|
||||
|
||||
Reference in New Issue
Block a user