////////////////// /// Connection ////////////////// var socket = io.connect({ transports: ['websocket'], path: "/web/socket" }); let first_camera_update = true socket.on('connect', function() { console.log('Connected to server'); }); socket.on('disconnect', function() { console.log('Disconnected from server'); }); socket.on('timestamp', function(server_unix_time) { var diff = difftime(server_unix_time) $('[data-status=timestamp-diff]').text(diff) //console.log(diff) }); ////////////////// /// Dome stream ////////////////// socket.on("all-dome",function(e) { // Disable if not /ping: if (e["dome-ping"].raw !== true) { $("#Dome").addClass("pe-none").css({"opacity":"0.4"}) .find('*') .attr('tabindex', '-1') } else { $("#Dome").removeClass("pe-none").css({"opacity": "1.0"}) .find('*') .removeAttr('tabindex') } $.each(e, function(k,v){ /// Depth 1 var elem = $("[data-status="+k+"]") if (elem) { elem.text(v.response) } /// Depth 2 if (k == "dome-position") { $("[data-status="+k+"-azimuth]").text(e[k].response.azimuth) $("[data-status="+k+"-parked]").text(e[k].response.parked) } // pulse(elem) }); }); //////////////////// /// Telescope stream //////////////////// socket.on("all-telescope",function(e) { // Disable if not /ping: if (e["telescope-ping"].raw !== true) { $("#Telescope").addClass("pe-none").css({"opacity":"0.4"}) .find('*') .attr('tabindex', '-1') } else { $("#Telescope").removeClass("pe-none").css({"opacity": "1.0"}) .find('*') .removeAttr('tabindex') } $.each(e, function(k,v){ var elem = $("[data-status="+k+"]") /// Depth 1 if (elem) { //console.log(k) elem.text(v.response) } /// Depth 2 if (k == "telescope-coordinates") { $("[data-status="+k+"-ra]").text(e[k].response.radec[0]) $("[data-status="+k+"-dec]").text(e[k].response.radec[1]) $("[data-status="+k+"-alt]").text(e[k].response.altaz[0].toFixed(3)) $("[data-status="+k+"-az]").text(e[k].response.altaz[1].toFixed(3)) $("[data-status="+k+"-ha]").text(e[k].response.ha) $("[data-status="+k+"-lst]").text(e[k].response.lst) } if (k == "telescope-coordinates-offset") { $("[data-status="+k+"-zd]").text((e[k].response[0]*3600).toFixed(1)) $("[data-status="+k+"-az]").text((e[k].response[1]*3600).toFixed(1)) } // pulse(elem) }) }); ////////////////// /// Camera stream ////////////////// socket.on("all-camera",function(e) { //console.log(e) // Disable if not /ping: if (e["camera-ping"].raw !== true) { $("#Camera").addClass("pe-none").css({"opacity":"0.4"}) .find('*') .attr('tabindex', '-1') } else { $("#Camera").removeClass("pe-none").css({"opacity": "1.0"}) .find('*') .removeAttr('tabindex') // Update the input fields with the real data, at first page load if (first_camera_update) { $('#filter').prop("value", e["camera-filter"].response) $("#binning").prop("value", e["camera-settings"].response.binning[0]) // [0,0] $('#x0').prop("value", e["camera-settings"].response.xystart[0]) $('#y0').prop("value", e["camera-settings"].response.xystart[1]) $('#xf').prop("value", e["camera-settings"].response.xyend[0]) $('#yf').prop("value", e["camera-settings"].response.xyend[1]) first_camera_update = false } } $.each(e, function(k,v){ /// Depth 1 var elem = $("[data-status="+k+"]") if (elem) { elem.text(v.response) } /// Depth 2 (settings) if (k == "camera-settings") { $.each(v.response, function(kk,vv){ var elem = $("[data-status=camera-"+kk+"]") if (elem) { elem.text(vv) } }); } }); }); ///////////////////// /// Sequencer stream ///////////////////// socket.on("api-sequencer",function(e) { var res = e //JSON.parse(e.data) $.each(res.response, function(k,v){ /// sequencer has just 1 response var elem = $("[data-status=sequencer-"+k) if (elem) { elem.text(v) } }); /// For the JS9 display var auto_display = $("#auto-display").prop("checked") if (auto_display) { if (typeof JS9 != "undefined") { JS9.Load("/static/temp.fits", {refresh:true, colormap:"heat"} ) } } /// For the d3.js focus output var auto_output = $("#auto-output").prop("checked") if (auto_output) { if (res.response.output && res.response.output.focus) { const focus = res.response.output.focus const data = focus.m2.map((x, i) => ({ x, y: focus.fwhm[i] })); if (typeof chart1 != "undefined") { chart1.update(data); } } } }); /////////////////////// /// Environment stream /////////////////////// socket.on("api-environment", function(e) { var res = e //JSON.parse(e.data) // console.log(res) if (res && res.external) { $.each(res.external, function(k,v){ var elem = $("[data-status=environment-external-"+k) if (elem) { elem.text(v) } }); } if (res && res.internal) { $.each(res.internal, function(k,v){ var elem = $("[data-status=environment-internal-"+k) if (elem) { elem.text(v) } }); } }); /////////////////////// /// Webcam stream /////////////////////// socket.on("api-webcam", function(e) { const elem = $("[data-status=webcam-snapshot") //console.log(e) if (e) { const url = btoa(String.fromCharCode(...new Uint8Array(e))); elem.attr("src", 'data:image/jpeg;base64,' + url) } else { console.log("no image?") } }); /////////////////////// /// Logfile stream /////////////////////// var ansi_up = new AnsiUp; socket.on("new_lines", function(lines) { var log_level_list = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]; var log_level = ""; $.each(log_level_list, function(index, value) { //console.log(lines) if (lines.indexOf(value) !== -1) { log_level = value+'-level-line'; return false; } }); lines.forEach(function(line){ $("#stream-output").prepend( '
'+ansi_up.ansi_to_html(line)+'
' ); }) }); /////////////////////// /// Pulse on changes /////////////////////// function pulse(selector) { // var done = "bg-success" // var delay = 200 selector.fadeTo('slow', 0.5, function() { selector.fadeTo('slow', 1.0) //.removeClass(done); }); // setTimeout(function() { // selector.removeClass(done); // }, delay); } $(document).ready(function(){ // Select all elements with data-status attribute const elements = document.querySelectorAll('[data-status]'); // Object to store previous text content of each element const previousTextContent = {}; // Function to monitor text changes function observeChanges(element) { const observer = new MutationObserver(mutationsList => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { const previousText = previousTextContent[element.getAttribute('data-status')]; const currentText = element.textContent.trim(); if (previousText !== currentText) { pulse($(element)) previousTextContent[element.getAttribute('data-status')] = currentText; } } } }); observer.observe(element, { subtree: true, childList: true }); } // Apply observeChanges function to each element elements.forEach(element => { previousTextContent[element.getAttribute('data-status')] = element.textContent.trim(); observeChanges(element); }); });