UNPKG

nmea-streamer

Version:

The plugin streams a file with NMEA0183 messages to the SignalK server at a configurable speed. It also provides a web app with play controls.

242 lines (202 loc) 7.61 kB
// Base URL for the playback API const API_BASE_URL = '/plugins/nmea-streamer'; const progressBar = document.getElementById('progressBar'); const markerStart = document.getElementById('markerStart'); const markerEnd = document.getElementById('markerEnd'); const markerCurrent = document.getElementById('markerCurrent'); const markerTarget = document.getElementById('markerTarget'); const speedSelect = document.getElementById('speedSelect'); markerStart.endpoint = "setStart"; markerStart.position = 0; markerEnd.endpoint = "setEnd"; markerEnd.position = 100; markerCurrent.endpoint = "setCurrent"; markerCurrent.position = 0; markerTarget.endpoint = "setTarget"; markerTarget.position = null; const play = { markerCurrent: null, markerTarget: null, markerStart: null, markerEnd: null, speed: 1, status: "stopped" }; const file = { baseName: null, path: null, start: null, end: null, }; function enableDragging(marker) { marker.addEventListener('mousedown', (event) => { event.preventDefault(); // Bind the onDrag function to this marker instance const onDragWithMarker = (e) => onDrag(e, marker); marker.currentPosition = 0; // Start dragging document.addEventListener('mousemove', onDragWithMarker); document.addEventListener('mouseup', () => { document.removeEventListener('mousemove', onDragWithMarker); }, { once: true }); }); } function onDrag(event, marker) { const barRect = progressBar.getBoundingClientRect(); const barWidth = barRect.width; const offsetX = event.clientX - barRect.left; position = Math.min(100, Math.max(0, (offsetX / barWidth) * 100)); postToServer(marker.id, PercentageToDate(position).toISOString()) .then(data => { const date = new Date(data); play[marker.id] = date; placeMarker(marker, date); }) } function dateToPercentage(date) { if (date === null) return null; return 100.0 * (date.getTime() - file.start.getTime()) / (file.end.getTime() - file.start.getTime()); } function PercentageToDate(perc) { return new Date((perc / 100.0) * (file.end.getTime() - file.start.getTime()) + file.start.getTime()); } function getFile() { getFromServer("getFile") .then(data => { file.baseName = data.baseName; file.path = data.path; file.start = new Date(data.start); file.end = new Date(data.end); }) .catch(error => { updateStatus("Error connecting to server"); console.error("Error while getting file", error); }); } function getPlay() { getFromServer("getPlay") .then(data => { updatePlay(data); updateMarkers(); updateSpeed(); updateStatus( play.status); }) .catch(error => { updateStatus("Error connecting to server"); console.error("Error while getting play", error); }); } function setMarker(id, position) { postToServer(id, PercentageToDate(position).toISOString()) .then(data => {}) .catch(error => { updateStatus("Error connecting to server"); console.error("Error while setting play", error); }); } function updatePlay(data) { play.status = data.status; play.speed = data.speed; play.markerCurrent = data.markerCurrent === null ? null : new Date(data.markerCurrent); play.markerTarget = data.markerTarget === null ? null : new Date(data.markerTarget); play.markerStart = data.markerStart === null ? null : new Date(data.markerStart); play.markerEnd = data.markerEnd === null ? null : new Date(data.markerEnd); } function updateMarkers() { placeMarker(markerStart, play.markerStart); placeMarker(markerEnd, play.markerEnd); placeMarker(markerCurrent, play.markerCurrent); placeMarker(markerTarget, play.markerTarget); } function updateSpeed() { speedSelect.value = play.speed; } function placeMarker(marker, date) { if (date === null) { marker.style.visibility = "hidden"; } else { marker.style.visibility = "visible"; marker.style.left = `${dateToPercentage(date)}%`; marker.firstElementChild.innerHTML = date.toLocaleTimeString(); } } async function postToServer(endpoint, value = null) { try { const response = await fetch(`${API_BASE_URL}/${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value }) }); const data = await response.json(); return data; } catch (error) { throw error; // Re-throw the error if needed } } async function getFromServer(endpoint) { try { const response = await fetch(`${API_BASE_URL}/${endpoint}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); return data; } catch (error) { throw error; // Re-throw the error if needed } } function updateStatus(message) { document.getElementById('status').textContent = message; } function requestStatusUpdate() { getFromServer("status") .then(status => { // Update the UI with the current status markerCurrent.style.left = `${status.currentPosition}%`; markerCurrent.position = status.currentPosition; markerStart.style.left = `${status.loopStart}%`; markerStart.position = status.loopStart; markerEnd.style.left = `${status.loopEnd}%`; markerEnd.position = status.loopEnd; const speedselect = document.getElementById('speedSelect'); speedselect.value = status.speed; const statusline = document.getElementById('status'); statusline.textContent = status.status; }) .catch(error => { console.error('Error fetching status from the server:', error); }); } function update() { setInterval(() => { getPlay(); }, 1000); } /* progressBar.addEventListener('click', (event) => { if (event.offsetX) { //mouse drag interferes with click event, quick and dirty solution const barWidth = progressBar.offsetWidth; markerTarget.position = event.offsetX / barWidth * 100; // Get percentage postMarker(markerTarget); markerTarget.style.visibility = "visible"; markerTarget.style.left = `${markerTarget.position}%`; } }); */ window.onload = () => { updateMarkers(); enableDragging(markerStart); enableDragging(markerEnd); // Add event listeners to buttons document.getElementById('rewindButton').addEventListener('click', () => { postToServer("markerTarget",play.markerStart); getPlay(); }); document.getElementById('playButton').addEventListener('click', () => { postToServer("status","playing"); getPlay(); }); document.getElementById('pauseButton').addEventListener('click', () => { postToServer("status","paused"); getPlay(); }); document.getElementById('speedSelect').addEventListener('change', (event) => { postToServer("speed", event.target.value); getPlay(); }); getFile(); update(); };