feat(timeroverlaytouch): add timeroverlay with buttons
This commit is contained in:
187
timeroverlaytouch/app.js
Normal file
187
timeroverlaytouch/app.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/*eslint-env browser*/
|
||||
/**
|
||||
* This is a very minimal example for a websocket client
|
||||
* You could use this as a starting point to creating your own interfaces
|
||||
*/
|
||||
|
||||
// Data that the user needs to provide depending on the Ontime URL
|
||||
const isSecure = window.location.protocol === 'https:';
|
||||
const userProvidedSocketUrl = `${isSecure ? 'wss' : 'ws'}://${window.location.host}${getStageHash()}/ws`;
|
||||
let websocket = null
|
||||
|
||||
connectSocket();
|
||||
|
||||
let reconnectTimeout;
|
||||
const reconnectInterval = 1000;
|
||||
let reconnectAttempts = 0;
|
||||
|
||||
/**
|
||||
* Connects to the websocket server
|
||||
* @param {string} socketUrl
|
||||
*/
|
||||
function connectSocket(socketUrl = userProvidedSocketUrl) {
|
||||
websocket = new WebSocket(socketUrl);
|
||||
|
||||
websocket.onopen = () => {
|
||||
clearTimeout(reconnectTimeout);
|
||||
reconnectAttempts = 0;
|
||||
console.warn('WebSocket connected');
|
||||
};
|
||||
|
||||
websocket.onclose = () => {
|
||||
console.warn('WebSocket disconnected');
|
||||
reconnectTimeout = setTimeout(() => {
|
||||
console.warn(`WebSocket: attempting reconnect ${reconnectAttempts}`);
|
||||
if (websocket && websocket.readyState === WebSocket.CLOSED) {
|
||||
reconnectAttempts += 1;
|
||||
connectSocket();
|
||||
}
|
||||
}, reconnectInterval);
|
||||
};
|
||||
websocket.onerror = (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
};
|
||||
|
||||
websocket.onmessage = (event) => {
|
||||
// all objects from ontime are structured with tag and payload
|
||||
const { tag, payload } = JSON.parse(event.data);
|
||||
|
||||
/**
|
||||
* runtime-data is sent
|
||||
* - on connect with the full state
|
||||
* - and then on every update with a patch
|
||||
*/
|
||||
if (tag === 'runtime-data') {
|
||||
handleOntimePayload(payload);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let localData = {};
|
||||
let localVars = {};
|
||||
|
||||
/**
|
||||
* Handles the ontime payload updates
|
||||
* @param {object} payload - The payload object containing the updates
|
||||
*/
|
||||
function handleOntimePayload(payload) {
|
||||
// 1. apply the patch into your local copy of the data
|
||||
localData = { ...localData, ...payload };
|
||||
|
||||
if ('eventNow' in payload) {
|
||||
let imgelement = document.getElementById("image");
|
||||
let timerelement = document.getElementById("timer");
|
||||
|
||||
localVars.nowid = payload.eventNow.id;
|
||||
localVars.layoutimg = payload.eventNow.custom["layoutimage"] ?? null;
|
||||
|
||||
let newready = payload.eventNow.custom["ready"] == "true";
|
||||
if (localVars.ready != newready) {
|
||||
localVars.ready = newready;
|
||||
updateReady();
|
||||
}
|
||||
|
||||
newready = payload.eventNow.custom["stageready"] == "true";
|
||||
if (localVars.stageready != newready) {
|
||||
localVars.stageready = newready;
|
||||
updateStageButton();
|
||||
}
|
||||
|
||||
imgelement.src = localVars.layoutimg;
|
||||
if (localVars.layoutimg) {
|
||||
imgelement.classList.remove("hidden");
|
||||
timerelement.classList.add("hidden");
|
||||
}else {
|
||||
imgelement.classList.add("hidden");
|
||||
timerelement.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function blink(id) {
|
||||
document.getElementById(id).classList.add("blink");
|
||||
setTimeout(() => {
|
||||
document.getElementById(id).classList.remove("blink");
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function onReadyClick() {
|
||||
const message = {
|
||||
tag: "change",
|
||||
payload: {
|
||||
[localVars.nowid]: {
|
||||
"custom:stageready": !localVars.stageready
|
||||
}
|
||||
}
|
||||
};
|
||||
websocket.send(JSON.stringify(message));
|
||||
}
|
||||
|
||||
function updateStageButton() {
|
||||
let stagereadybutton = document.getElementById("stageready");
|
||||
if (localVars.stageready) {
|
||||
stagereadybutton.classList.remove("redoutline");
|
||||
stagereadybutton.classList.add("greenoutline");
|
||||
}else {
|
||||
stagereadybutton.classList.add("redoutline");
|
||||
stagereadybutton.classList.remove("greenoutline");
|
||||
}
|
||||
}
|
||||
|
||||
function updateReady() {
|
||||
let fohreadybutton = document.getElementById("fohready");
|
||||
let container = document.getElementById("container");
|
||||
|
||||
if (localVars.ready) {
|
||||
container.classList.remove("redoutline");
|
||||
container.classList.add("greenoutline");
|
||||
blink("container")
|
||||
fohreadybutton.classList.remove("redoutline");
|
||||
fohreadybutton.classList.add("greenoutline");
|
||||
}else {
|
||||
container.classList.add("redoutline");
|
||||
container.classList.remove("greenoutline");
|
||||
fohreadybutton.classList.add("redoutline");
|
||||
fohreadybutton.classList.remove("greenoutline");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the DOM with a given payload
|
||||
* @param {string} field - The runtime data field
|
||||
* @param {object} payload - The patch object for the field
|
||||
*/
|
||||
function updateDOM(field, payload) {
|
||||
const domElement = document.getElementById(field);
|
||||
if (domElement) {
|
||||
domElement.innerText = payload;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stringifies an object into a pretty string
|
||||
* @param {object} data - The data object to format
|
||||
* @returns {string} The formatted data string
|
||||
*/
|
||||
function formatObject(data) {
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to handle a demo deployed in an ontime stage
|
||||
* You can likely ignore this in your app
|
||||
*
|
||||
* an url looks like
|
||||
* https://cloud.getontime.no/stage-hash/external/demo/ -> /stage-hash
|
||||
* @returns {string} - The stage hash if the app is running in an ontime stage
|
||||
*/
|
||||
function getStageHash() {
|
||||
const href = window.location.href;
|
||||
if (!href.includes('getontime.no')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const hash = href.split('/');
|
||||
const stageHash = hash.at(3);
|
||||
return stageHash ? `/${stageHash}` : '';
|
||||
}
|
||||
Reference in New Issue
Block a user