|
|
@ -111,75 +111,120 @@ clearCacheBtn.addEventListener("click", async () => { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
jsonFileInput.addEventListener("change", (event) => { |
|
|
jsonFileInput.addEventListener("change", (event) => { |
|
|
|
|
|
|
|
|
const file = event.target.files[0]; |
|
|
const file = event.target.files[0]; |
|
|
|
|
|
|
|
|
if (!file) return; |
|
|
if (!file) return; |
|
|
|
|
|
|
|
|
appState.jsonFilename = file.name; |
|
|
appState.jsonFilename = file.name; |
|
|
|
|
|
|
|
|
localStorage.setItem("jsonFilename", appState.jsonFilename); |
|
|
localStorage.setItem("jsonFilename", appState.jsonFilename); |
|
|
|
|
|
|
|
|
calculateAndSetOffset(); |
|
|
calculateAndSetOffset(); |
|
|
|
|
|
|
|
|
saveFileToDB("json", file); // Save the file object for the next session
|
|
|
saveFileToDB("json", file); // Save the file object for the next session
|
|
|
|
|
|
|
|
|
// 1. Show a loading modal immediately.
|
|
|
// 1. Show a loading modal immediately.
|
|
|
|
|
|
|
|
|
showModal("Parsing large JSON file, please wait..."); |
|
|
showModal("Parsing large JSON file, please wait..."); |
|
|
|
|
|
|
|
|
// 2. Create a temporary URL for the streaming parser.
|
|
|
// 2. Create a temporary URL for the streaming parser.
|
|
|
|
|
|
|
|
|
const fileURL = URL.createObjectURL(file); |
|
|
const fileURL = URL.createObjectURL(file); |
|
|
|
|
|
|
|
|
// 3. Use the robust streaming parser.
|
|
|
// 3. Use the robust streaming parser.
|
|
|
|
|
|
|
|
|
parseJsonWithOboe( |
|
|
parseJsonWithOboe( |
|
|
|
|
|
|
|
|
fileURL, |
|
|
fileURL, |
|
|
|
|
|
|
|
|
async (parsedData) => { |
|
|
async (parsedData) => { |
|
|
|
|
|
|
|
|
// This is the success callback, running after the file is parsed.
|
|
|
// This is the success callback, running after the file is parsed.
|
|
|
|
|
|
|
|
|
// We make it async so we can `await` the next step.
|
|
|
// We make it async so we can `await` the next step.
|
|
|
|
|
|
|
|
|
const result = await parseVisualizationJson( |
|
|
const result = await parseVisualizationJson( |
|
|
|
|
|
|
|
|
parsedData, |
|
|
parsedData, |
|
|
|
|
|
|
|
|
appState.radarStartTimeMs, |
|
|
appState.radarStartTimeMs, |
|
|
|
|
|
|
|
|
appState.videoStartDate |
|
|
appState.videoStartDate |
|
|
|
|
|
|
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
// Revoke the temporary URL to free up memory.
|
|
|
// Revoke the temporary URL to free up memory.
|
|
|
|
|
|
|
|
|
URL.revokeObjectURL(fileURL); |
|
|
URL.revokeObjectURL(fileURL); |
|
|
|
|
|
|
|
|
if (result.error) { |
|
|
if (result.error) { |
|
|
|
|
|
|
|
|
showModal(result.error); |
|
|
showModal(result.error); |
|
|
|
|
|
|
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
appState.vizData = result.data; |
|
|
appState.vizData = result.data; |
|
|
|
|
|
|
|
|
appState.globalMinSnr = result.minSnr; |
|
|
appState.globalMinSnr = result.minSnr; |
|
|
|
|
|
|
|
|
appState.globalMaxSnr = result.maxSnr; |
|
|
appState.globalMaxSnr = result.maxSnr; |
|
|
|
|
|
|
|
|
// Update UI with the correct, awaited data.
|
|
|
// Update UI with the correct, awaited data.
|
|
|
|
|
|
|
|
|
snrMinInput.value = appState.globalMinSnr.toFixed(1); |
|
|
snrMinInput.value = appState.globalMinSnr.toFixed(1); |
|
|
|
|
|
|
|
|
snrMaxInput.value = appState.globalMaxSnr.toFixed(1); |
|
|
snrMaxInput.value = appState.globalMaxSnr.toFixed(1); |
|
|
|
|
|
|
|
|
resetVisualization(); |
|
|
resetVisualization(); |
|
|
|
|
|
|
|
|
canvasPlaceholder.style.display = "none"; |
|
|
canvasPlaceholder.style.display = "none"; |
|
|
|
|
|
|
|
|
featureToggles.classList.remove("hidden"); |
|
|
featureToggles.classList.remove("hidden"); |
|
|
|
|
|
|
|
|
if (!appState.p5_instance) { |
|
|
if (!appState.p5_instance) { |
|
|
|
|
|
|
|
|
appState.p5_instance = new p5(radarSketch); |
|
|
appState.p5_instance = new p5(radarSketch); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (appState.speedGraphInstance) { |
|
|
if (appState.speedGraphInstance) { |
|
|
|
|
|
|
|
|
appState.speedGraphInstance.setData( |
|
|
appState.speedGraphInstance.setData( |
|
|
|
|
|
|
|
|
appState.canData, |
|
|
appState.canData, |
|
|
|
|
|
|
|
|
appState.vizData, |
|
|
appState.vizData, |
|
|
|
|
|
|
|
|
videoPlayer.duration |
|
|
videoPlayer.duration |
|
|
|
|
|
|
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Close the loading modal.
|
|
|
// Close the loading modal.
|
|
|
|
|
|
|
|
|
document.getElementById("modal-ok-btn").click(); |
|
|
document.getElementById("modal-ok-btn").click(); |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
(error) => { |
|
|
(error) => { |
|
|
|
|
|
|
|
|
// This is the error callback for the streaming parser.
|
|
|
// This is the error callback for the streaming parser.
|
|
|
|
|
|
|
|
|
showModal(error); |
|
|
showModal(error); |
|
|
|
|
|
|
|
|
URL.revokeObjectURL(fileURL); |
|
|
URL.revokeObjectURL(fileURL); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Event listener for video file input change.
|
|
|
// Event listener for video file input change.
|
|
|
videoFileInput.addEventListener("change", (event) => { |
|
|
videoFileInput.addEventListener("change", (event) => { |
|
|
const file = event.target.files[0]; |
|
|
const file = event.target.files[0]; |
|
|
|