mirror of
https://github.com/cjfranko/NTP-Timeturner.git
synced 2025-11-08 18:32:02 +00:00
Compare commits
4 commits
d814b05a26
...
3df9466754
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3df9466754 | ||
|
|
0745883e0d | ||
|
|
0c6e1b0f43 | ||
|
|
871fd192b0 |
1 changed files with 69 additions and 4 deletions
|
|
@ -1,4 +1,7 @@
|
|||
document.addEventListener('DOMContentLoaded', () => {
|
||||
let lastApiData = null;
|
||||
let lastApiFetchTime = null;
|
||||
|
||||
const statusElements = {
|
||||
ltcStatus: document.getElementById('ltc-status'),
|
||||
ltcTimecode: document.getElementById('ltc-timecode'),
|
||||
|
|
@ -38,7 +41,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
statusElements.frameRate.textContent = data.frame_rate;
|
||||
statusElements.lockRatio.textContent = data.lock_ratio.toFixed(2);
|
||||
statusElements.systemClock.textContent = data.system_clock;
|
||||
|
||||
|
||||
statusElements.ntpActive.textContent = data.ntp_active ? 'Active' : 'Inactive';
|
||||
statusElements.ntpActive.className = data.ntp_active ? 'active' : 'inactive';
|
||||
|
||||
|
|
@ -47,7 +50,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
statusElements.deltaMs.textContent = data.timecode_delta_ms;
|
||||
statusElements.deltaFrames.textContent = data.timecode_delta_frames;
|
||||
|
||||
|
||||
statusElements.jitterStatus.textContent = data.jitter_status;
|
||||
statusElements.jitterStatus.className = data.jitter_status.toLowerCase();
|
||||
|
||||
|
|
@ -65,14 +68,75 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
}
|
||||
|
||||
function animateClocks() {
|
||||
if (!lastApiData || !lastApiFetchTime) return;
|
||||
|
||||
const elapsedMs = new Date() - lastApiFetchTime;
|
||||
|
||||
// Animate System Clock
|
||||
if (lastApiData.system_clock && lastApiData.system_clock.includes(':')) {
|
||||
const parts = lastApiData.system_clock.split(/[:.]/);
|
||||
if (parts.length === 4) {
|
||||
const baseDate = new Date();
|
||||
baseDate.setHours(parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10));
|
||||
baseDate.setMilliseconds(parseInt(parts[3], 10));
|
||||
|
||||
const newDate = new Date(baseDate.getTime() + elapsedMs);
|
||||
|
||||
const h = String(newDate.getHours()).padStart(2, '0');
|
||||
const m = String(newDate.getMinutes()).padStart(2, '0');
|
||||
const s = String(newDate.getSeconds()).padStart(2, '0');
|
||||
const ms = String(newDate.getMilliseconds()).padStart(3, '0');
|
||||
statusElements.systemClock.textContent = `${h}:${m}:${s}.${ms}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Animate LTC Timecode - only if status is LOCK
|
||||
if (lastApiData.ltc_status === 'LOCK' && lastApiData.ltc_timecode && lastApiData.ltc_timecode.includes(':') && lastApiData.frame_rate) {
|
||||
const tcParts = lastApiData.ltc_timecode.split(':');
|
||||
const frameRate = parseFloat(lastApiData.frame_rate);
|
||||
if (tcParts.length === 4 && !isNaN(frameRate) && frameRate > 0) {
|
||||
let h = parseInt(tcParts[0], 10);
|
||||
let m = parseInt(tcParts[1], 10);
|
||||
let s = parseInt(tcParts[2], 10);
|
||||
let f = parseInt(tcParts[3], 10);
|
||||
|
||||
const msPerFrame = 1000.0 / frameRate;
|
||||
const elapsedFrames = Math.floor(elapsedMs / msPerFrame);
|
||||
|
||||
f += elapsedFrames;
|
||||
|
||||
const frameRateInt = Math.round(frameRate);
|
||||
|
||||
s += Math.floor(f / frameRateInt);
|
||||
f %= frameRateInt;
|
||||
|
||||
m += Math.floor(s / 60);
|
||||
s %= 60;
|
||||
|
||||
h += Math.floor(m / 60);
|
||||
m %= 60;
|
||||
|
||||
h %= 24;
|
||||
|
||||
statusElements.ltcTimecode.textContent =
|
||||
`${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}:${String(f).padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchStatus() {
|
||||
try {
|
||||
const response = await fetch('/api/status');
|
||||
if (!response.ok) throw new Error('Failed to fetch status');
|
||||
const data = await response.json();
|
||||
updateStatus(data);
|
||||
lastApiData = data;
|
||||
lastApiFetchTime = new Date();
|
||||
} catch (error) {
|
||||
console.error('Error fetching status:', error);
|
||||
lastApiData = null;
|
||||
lastApiFetchTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,10 +164,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
autoSyncEnabled: autoSyncCheckbox.checked,
|
||||
defaultNudgeMs: parseInt(nudgeValueInput.value, 10) || 0,
|
||||
timeturnerOffset: {
|
||||
hours: parseInt(offsetInputs.h.value, 10) || 0,
|
||||
hours: parseInt(offsetInputs.h.value, 10) || 0,
|
||||
minutes: parseInt(offsetInputs.m.value, 10) || 0,
|
||||
seconds: parseInt(offsetInputs.s.value, 10) || 0,
|
||||
frames: parseInt(offsetInputs.f.value, 10) || 0,
|
||||
frames: parseInt(offsetInputs.f.value, 10) || 0,
|
||||
milliseconds: parseInt(offsetInputs.ms.value, 10) || 0,
|
||||
}
|
||||
};
|
||||
|
|
@ -193,4 +257,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
// Refresh data every 2 seconds
|
||||
setInterval(fetchStatus, 2000);
|
||||
setInterval(fetchLogs, 2000);
|
||||
setInterval(animateClocks, 50); // High-frequency clock animation
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue