/**
* @file ui.js
* @description This file contains every fonction called via an event firing. Some fonctions are also called via user inputs on sub-menus.
*
* Functions included in this file :
* - **changeChannelButtonStatus**
* - **toggleDisplayForVerticalCursorScrollers + sub-functions**
* - **toggleDisplayForHorizontalCursorScrollers + sub-functions**
* - **changeScreenSize + sub-functions**
* - **changeScreenLightMode**
* - **setScrollersEvents + sub-functions**
* - **setupTriggerCursor + sub-functions**
*
* @version 1.0.0
* @since 2024-05-31
* @author Owen Pichot
* @license Public Domain
*/
/**
* @module UI
*/
/**
* This function executes whenever a user clicks on one of the channel buttons :
* The button will be grayed out if it is already in focus.
* The button will be 'activated/colored' if it is grayed out.
* The button will be focused if not already focused.
*
* @function changeChannelButtonStatus
* @memberof module:UI
* @param {string} channelKey Object key corresponding to a certain signal saved within 'channelData'.
* @throws Will throw an error if the button clicked on is not linked to an active channel. We then warn the user.
* @returns {void}
*/
function changeChannelButtonStatus(channelKey) {
let button = document.getElementById(channelKey);
// Here we make sure only one button can be focused
Object.keys(channelData).forEach(key => {
let otherButton = document.getElementById(key);
otherButton.classList.remove('button-focused');
if (key !== channelKey) {
channelData[key].focused = false;
}
});
try {//in case the channel clicked is not active (= not in the channelData dictionnary)
if (!channelData[channelKey].focused) {//if channel is not focused, then
button.classList.add('button-focused');
channelData[channelKey].focused = true;
//Here we also set the correct values for the vertical scaling of this channel to the knob of the html page
document.getElementById('vertical-scaling').value = channelData[channelKey].verticalScale;
//here we update the z-index of that cursor to make it easy for the user to interact with.
Object.keys(channelData).forEach(key => {
if (key == channelKey){
document.getElementById('scroller-' + channelKey).style.zIndex = 50000;
}else{
document.getElementById('scroller-' + key).style.zIndex = 10000;
}
})
// If channel is not displayed, display it
if (!channelData[channelKey].display) {
button.classList.remove("channel-not-displayed");
button.classList.add("channel-displayed");
button.classList.add(channelData[channelKey].colorDark);
channelData[channelKey].display = true;
document.getElementById('scroller-' + channelKey).style.display = 'block';
document.getElementById('scroller-' + channelKey).style.top = channelData[channelKey].verticalOffsetRelativeCursorPosition;
}
} else {
if (channelData[channelKey].display) {//If button was focused, remove its styles.
button.classList.remove("channel-displayed");
button.classList.add("channel-not-displayed");
button.classList.remove(channelData[channelKey].colorDark);
channelData[channelKey].display = false;
document.getElementById('scroller-' + channelKey).style.display = 'none';
}
// remove the focus since the button was clicked a second time
button.classList.remove('button-focused');
channelData[channelKey].focused = false;
}
} catch (error) {
if (error instanceof TypeError) {//Button not linked to an active channel
console.error(error)
showToast("This channel is not active.", "toast-error");
} else {
alert("An unknown error occured, please look at the console.")
console.error(error);
}
}
// console.log(channelData);
};
/**
* @type {boolean}
* @description This variable is necessary for the function 'toggleDisplayForVerticalCursorScrollers' in order to prevent adding multiple listeners onto the same element.
*/
let isVerticalMouseDownListenerSet = false;
/**
* @type {boolean}
* @description This variable is necessary for the function 'toggleDisplayForHorizontalCursorScrollers' in order to prevent adding multiple listeners onto the same element.
*/
let isHorizontalMouseDownListenerSet = false;
/**
* This function is fired when a user chooses to display the vertical cursors.
* It will start by displaying the corresponding cursors and assign event listeners to them.
* If the cursors have been previously hidden then showned again, the listeners won't be set again.
*
* @function toggleDisplayForVerticalCursorScrollers
* @memberof module:UI
* @returns {void}
*/
function toggleDisplayForVerticalCursorScrollers(){
const scrollerA = document.getElementById("vertical-scroller-A");
const scrollerB = document.getElementById("vertical-scroller-B");
const scrollBar = document.getElementById("scrollbar-horizontal");
let isDragging = false;
let currentMoveListener = null;
let currentUpListener = null;
/**
* This fonction keeps track of a moving vertical cursor being dragged by a user.
* We get the cursor's position anytime it is being moved and save these values to the config relative to the cursors.
*
* @function onMouseMoveScrollerVertical
* @memberof module:UI
* @param {object} scroller Scroller element on the top of the screen.
* @param {number} startX Position from where the cursor started moving (abs value in pixels).
* @param {String} whichCursor Which of the 2 scrollers are we moving.
* @listens MouseMove For a user dragging the mouse.
* @returns {function} Returns the entire fonction in order to assign it to a variable and easily keep track of the listeners.
*/
function onMouseMoveScrollerVertical(scroller, startX, whichCursor){
return function(event) {
let newX = event.clientX - startX;
newX = Math.max(newX, 0);
newX = Math.min(newX, scrollBar.clientWidth - scroller.clientWidth);
scroller.style.left = newX + 'px';
if (whichCursor == "A"){
cursorOptions.verticalAPosition = newX + ((parseInt(window.getComputedStyle(scrollerA).width)) / 2);
}else{
cursorOptions.verticalBPosition = newX + ((parseInt(window.getComputedStyle(scrollerB).width)) / 2);
}
};
}
/**
* This fonction handles the final part of a moving vertical cursor which is when a user finally releases it.
* We then remove all listeners assigned to this cursor and reset the variables responsible for keeping track of the events.
*
* @function onMouseUpScrollerVertical
* @memberof module:UI
* @listens Mouseup For a user releasing the mouse.
* @returns {void}
*/
function onMouseUpScrollerVertical(){
if (!isDragging) return;
isDragging = false;
document.removeEventListener('mousemove', currentMoveListener);
document.removeEventListener('mouseup', currentUpListener);
currentMoveListener = null;
currentUpListener = null;
}
/**
* This functions sets up listeners to allow the user to move one of the two vertical cursors by dragging it along the scrollbar.
*
* @function setupDragListeners
* @memberof module:UI
* @param {Object} scroller Scroller element on top of the screen.
* @param {string} whichCursor Which of the two vertical cursors we are sending (A / B).
* @returns {void}
*
* @listens Mousedown For a user clicking on one of the vertical measure cursors.
* When a user clicks on one, we attach two new listeners to the cursor to track where it is dragged to and when the user relases the mouse.
*/
function setupDragListeners(scroller, whichCursor) {
scroller.addEventListener('mousedown', function(event) {
if (isDragging) return; // Prevents adding multiple listeners during an active drag
isDragging = true;
let startX = event.clientX - scroller.getBoundingClientRect().left + scrollBar.getBoundingClientRect().left;
currentMoveListener = onMouseMoveScrollerVertical(scroller, startX, whichCursor);
currentUpListener = onMouseUpScrollerVertical;
document.addEventListener('mousemove', currentMoveListener);
document.addEventListener('mouseup', currentUpListener);
});
}
if (cursorOptions.isVerticalCursorOn === "true"){
scrollerA.style.display = "block";
scrollerA.style.left = (cursorOptions.verticalAPosition - (parseInt(window.getComputedStyle(scrollerA).width)) / 2) + "px";
scrollerB.style.display = "block";
scrollerB.style.left = (cursorOptions.verticalBPosition - (parseInt(window.getComputedStyle(scrollerB).width)) / 2) + "px";
if (!isVerticalMouseDownListenerSet){
setupDragListeners(scrollerA, "A");
setupDragListeners(scrollerB, "B");
}
isVerticalMouseDownListenerSet = true;
} else {
// Hide scrollers (A & B)
scrollerA.style.display = "none";
scrollerB.style.display = "none";
}
};
/**
* Similarly to 'toggleDisplayForVerticalCursorScrollers' this function is fired when a user chooses to display the horizontal cursors.
* It will start by displaying the corresponding cursors and assign event listeners to them.
* If the cursors have been previously hidden then showned again, the listeners won't be set again.
*
* @function toggleDisplayForHorizontalCursorScrollers
* @memberof module:UI
* @returns {void}
*/
function toggleDisplayForHorizontalCursorScrollers(){
const scrollerA = document.getElementById("scroller-horizontal-A");
const scrollerB = document.getElementById("scroller-horizontal-B");
const scrollBar = document.getElementById("scroll-bar-horizontal-cursors");
let isDragging = false;
let currentMoveListener = null;
let currentUpListener = null;
/**
* This fonction keeps track of a moving horizontal cursor being dragged by a user.
* We get the cursor's position anytime it is being moved and save these values to the config relative to the cursors.
*
* @function onMouseMoveScrollerHorizontal
* @memberof module:UI
* @param {object} scroller Scroller element on the top of the screen.
* @param {number} startY Position from where the cursor started moving (abs value in pixels).
* @param {string} whichCursor Which of the 2 scrollers are we moving.
* @listens MouseMove For a user dragging the mouse.
* @returns {function} Returns the entire fonction in order to assign it to a variable and easily keep track of the listeners.
*/
function onMouseMoveScrollerHorizontal(scroller, startY, whichCursor){
return function(event) {
let newY = event.clientY - startY;
newY = Math.max(newY, 0);
newY = Math.min(newY, scrollBar.clientHeight - scroller.clientHeight);
scroller.style.top = newY + 'px';
if (whichCursor == "A"){
cursorOptions.horizontalAPosition = newY + ((parseInt(window.getComputedStyle(scrollerA).height)) / 2);
}else{
cursorOptions.horizontalBPosition = newY + ((parseInt(window.getComputedStyle(scrollerA).height)) / 2);
}
};
};
/**
* This fonction handles the final part of a moving horizontal cursor which is when a user finally releases it.
* We then remove all listeners assigned to this cursor and reset the variables responsible for keeping track of the events.
*
* @function onMouseUpScrollerHorizontal
* @memberof module:UI
* @listens Mouseup For a user releasing the mouse.
* @returns {void}
*/
function onMouseUpScrollerHorizontal(){
if (!isDragging) return;
isDragging = false;
document.removeEventListener('mousemove', currentMoveListener);
document.removeEventListener('mouseup', currentUpListener);
currentMoveListener = null;
currentUpListener = null;
};
/**
* This functions sets up listeners to allow the user to move one of the two horizontal cursors by dragging it along the scrollbar.
*
* @function setupDragListeners
* @memberof module:UI
* @param {Object} scroller Scroller element on top of the screen.
* @param {string} whichCursor Which of the two horizontal cursors we are sending (A / B).
* @returns {void}
*
* @listens Mousedown For a user clicking on one of the horizontal measure cursors.
* When a user clicks on one, we attach two new listeners to the cursor to track where it is dragged to and when the user relases the mouse.
*/
function setupDragListeners(scroller, whichCursor) {
scroller.addEventListener('mousedown', function(event) {
if (isDragging) return; // Prevents adding multiple listeners during an active drag
isDragging = true;
let startY = event.clientY - scroller.getBoundingClientRect().top + scrollBar.getBoundingClientRect().top;
currentMoveListener = onMouseMoveScrollerHorizontal(scroller, startY, whichCursor);
currentUpListener = onMouseUpScrollerHorizontal;
document.addEventListener('mousemove', currentMoveListener);
document.addEventListener('mouseup', currentUpListener);
});
}
if (cursorOptions.isHorizontalCursorOn === "true"){
scrollerA.style.display = "block";
scrollerA.style.top = (cursorOptions.horizontalAPosition - (parseInt(window.getComputedStyle(scrollerA).height)) / 2) + "px";
scrollerB.style.display = "block";
scrollerB.style.top = (cursorOptions.horizontalBPosition - (parseInt(window.getComputedStyle(scrollerB).height)) / 2) + "px";
if (!isHorizontalMouseDownListenerSet){
setupDragListeners(scrollerA, "A");
setupDragListeners(scrollerB, "B");
}
isHorizontalMouseDownListenerSet = true;
} else {
// Hide scrollers (A & B)
scrollerA.style.display = "none";
scrollerB.style.display = "none";
}
};
/**
* This function resizes the oscilloscope's screen.
* It will also move around some elements and/or resize them to make them fit within the new layout of the page.
*
* @function changeScreenSize
* @memberof module:UI
* @param {string} size Size, in pixels, to assign to the canvas (width|height).
* @returns {void}
* @listens Escape When the screen is maximized, part of this function will listen for the 'Escape' key being pressed and reset the view back to standard.
*
* @example
* changeScreenSize("1200|800");
* changeScreenSize("400|267");
*/
function changeScreenSize(size){
const width = parseInt(size.split("|")[0]);
const height = parseInt(size.split("|")[1]);
CANVAS.width = width;
CANVAS.height = height;
const horizontalScrollBar = document.getElementById("scrollbar-horizontal");
const leftVerticalScrollBar = document.getElementById("scroll-bar");
const rightVerticalScrollBar = document.getElementById("scroll-bar-horizontal-cursors");
const scrollerHorizontal = document.getElementById("scroller-Horizontal");
const scrollers = document.querySelectorAll(".scrollers")
const channelButtons = document.querySelectorAll(".ch-button");
const channelButtonsContainer = document.getElementById("channel-select-div");
const functionButtons = document.querySelectorAll(".function-buttons");
const measurementsHolder = document.getElementById("info-display-oscilloscope");
horizontalScrollBar.style.width = width + "px";
leftVerticalScrollBar.style.height = height + "px";
rightVerticalScrollBar.style.height = height + "px";
scrollerHorizontal.style.left = (width / 2) - 10 + "px";
scrollers.forEach(scroller => {
scroller.style.top = (height / 2) - 5 + "px";
});
if (cursorOptions.isHorizontalCursorOn && size != "TD"){
cursorOptions.horizontalAPosition = CANVAS.height / 3;
cursorOptions.horizontalBPosition = (CANVAS.height / 3) * 2;
document.getElementById("scroller-horizontal-A").style.top = (cursorOptions.horizontalAPosition - 5) + 'px';
document.getElementById("scroller-horizontal-B").style.top = (cursorOptions.horizontalBPosition - 5) + 'px';
}
if (cursorOptions.isVerticalCursorOn && size != "TD"){
cursorOptions.verticalAPosition = CANVAS.width / 3;
cursorOptions.verticalBPosition = (CANVAS.width / 3) * 2;
document.getElementById("vertical-scroller-A").style.left = (cursorOptions.verticalAPosition - 5) + 'px';
document.getElementById("vertical-scroller-B").style.left = (cursorOptions.verticalBPosition - 5) + 'px';
}
function setTinyScreenSize(){//Set specific styles for the tiny screen.
channelButtons.forEach(button => {
button.style.width = "20px";
button.style.height = "10px";
button.style.fontSize = "10px";
button.style.lineHeight = "3px";
button.firstElementChild.style.position = "absolute";
button.firstElementChild.style.left = "8px";
});
functionButtons.forEach(button => {
button.style.width = "105px";
button.style.height = "20";
button.style.fontSize = "13px";
button.style.lineHeight = "5px";
});
channelButtonsContainer.style.margin = "1em auto";
measurementsHolder.style.flexDirection = "column";
document.getElementById("vpdiv-mesurements").style.width = "fit-content";
document.getElementById("vpdiv-mesurements").style.margin = "0px";
document.querySelectorAll(".chanmeasures").forEach(p => {
p.style.width = "fit-content";
});
document.getElementById("mathres-measurements").style.display = "none";
};
function setSmallScreenSize(){//Set specific styles for the small screen.
channelButtons.forEach(button => {
button.style.width = "40px";
button.style.height = "15px";
button.style.fontSize = "15px";
button.style.lineHeight = "3px";
button.firstElementChild.style.position = "absolute";
button.firstElementChild.style.left = "13px";
});
functionButtons.forEach(button => {
button.style.width = "150px";
button.style.height = "40px";
button.style.fontSize = "18px";
button.style.lineHeight = "5px";
});
channelButtonsContainer.style.margin = "1em auto";
measurementsHolder.style.flexDirection = "column";
document.getElementById("vpdiv-mesurements").style.width = "fit-content";
document.getElementById("vpdiv-mesurements").style.margin = "0px";
document.querySelectorAll(".chanmeasures").forEach(p => {
p.style.width = "fit-content";
});
document.getElementById("mathres-measurements").style.display = "none";
document.getElementById("tpdiv-measurement").width = "fit-content";
document.getElementById("tpdiv-measurement").margin = "0px";
};
function setStandardScreenSize(){//Set specific styles for the standard screen.
channelButtons.forEach(button => {
button.style.width = "";
button.style.height = "";
button.style.fontSize = "";
button.style.lineHeight = "";
button.firstElementChild.style.position = "";
button.firstElementChild.style.left = "";
});
functionButtons.forEach(button => {
button.style.width = "";
button.style.height = "";
button.style.fontSize = "";
button.style.lineHeight = "";
});
channelButtonsContainer.style.margin = "";
measurementsHolder.style.flexDirection = "row";
document.getElementById("vpdiv-mesurements").style.width = "";
document.getElementById("vpdiv-mesurements").style.margin = "";
document.querySelectorAll(".chanmeasures").forEach(p => {
p.style.width = "";
});
document.getElementById("mathres-measurements").style.display = "flex";
document.getElementById("tpdiv-measurement").width = "";
document.getElementById("tpdiv-measurement").margin = "";
};
function setLargeScreenSize(){//Set specific styles for the large screen.
document.querySelectorAll("#channel-select-div span").forEach(span => {
span.style.flexWrap = "wrap";
span.style.justifyContent = "space-evenly";
});
channelButtons.forEach(button => {
button.style.width = "";
button.style.height = "";
button.style.fontSize = "";
button.style.lineHeight = "";
button.firstElementChild.style.position = "";
button.firstElementChild.style.left = "";
button.style.margin = "0px 0.2em 1em 0.2em"
});
functionButtons.forEach(button => {
button.style.width = "";
button.style.height = "";
button.style.fontSize = "";
button.style.lineHeight = "";
});
channelButtonsContainer.style.margin = "";
measurementsHolder.style.flexDirection = "row";
document.getElementById("vpdiv-mesurements").style.width = "";
document.getElementById("vpdiv-mesurements").style.margin = "";
document.querySelectorAll(".chanmeasures").forEach(p => {
p.style.width = "";
});
document.getElementById("mathres-measurements").style.display = "flex";
document.getElementById("tpdiv-measurement").width = "";
document.getElementById("tpdiv-measurement").margin = "";
};
function exitFullScreen(event){//Function associated to a listener to allow the user to quit the fullscreen mode.
if (event.key === "Escape"){
CANVAS.width = 1200;
CANVAS.height = 800;
document.getElementById("aside").style.display = "flex";
horizontalScrollBar.style.width = CANVAS.width + "px";
leftVerticalScrollBar.style.height = CANVAS.height + "px";
rightVerticalScrollBar.style.height = CANVAS.height + "px";
scrollerHorizontal.style.left = (CANVAS.width / 2) - 10 + "px";
scrollers.forEach(scroller => {
scroller.style.top = (CANVAS.height / 2) - 5 + "px";
})
document.getElementById("info-display-oscilloscope").style.display = "flex";
document.getElementById("auto-measures-display").style.display = "flex";
setStandardScreenSize();
document.removeEventListener("keydown", exitFullScreen);
showToast("Back to standard screen size.", "toast-info");
clearCanvas();
drawGrid('rgba(128, 128, 128, 0.5)', 3);
}
}
function setMaximizedScreenSize(){//Set specific styles for the maximized screen.
const bodyWidth = document.body.clientWidth;
const bodyHeight = document.body.clientHeight;
CANVAS.width = bodyWidth - 40;
CANVAS.height = bodyHeight - 20;
document.getElementById("aside").style.display = "none";
document.getElementById("middle-line").style.marginLeft = "0px";
horizontalScrollBar.style.width = CANVAS.width + "px";
leftVerticalScrollBar.style.height = CANVAS.height + "px";
rightVerticalScrollBar.style.height = CANVAS.height + "px";
scrollerHorizontal.style.left = (CANVAS.width / 2) - 10 + "px";
scrollers.forEach(scroller => {
scroller.style.top = (CANVAS.height / 2) - 5 + "px";
});
if (cursorOptions.isHorizontalCursorOn){
cursorOptions.horizontalAPosition = CANVAS.height / 3;
cursorOptions.horizontalBPosition = (CANVAS.height / 3) * 2;
document.getElementById("scroller-horizontal-A").style.top = (cursorOptions.horizontalAPosition - 5) + 'px';
document.getElementById("scroller-horizontal-B").style.top = (cursorOptions.horizontalBPosition - 5) + 'px';
}
if (cursorOptions.isVerticalCursorOn){
cursorOptions.verticalAPosition = CANVAS.width / 3;
cursorOptions.verticalBPosition = (CANVAS.width / 3) * 2;
document.getElementById("vertical-scroller-A").style.left = (cursorOptions.verticalAPosition - 5) + 'px';
document.getElementById("vertical-scroller-B").style.left = (cursorOptions.verticalBPosition - 5) + 'px';
}
document.getElementById("info-display-oscilloscope").style.display = "none";
document.getElementById("auto-measures-display").style.display = "none";
showToast("To escape full-screen, press 'ESC'", "toast-info");
document.addEventListener("keydown", exitFullScreen);
};
if (size == "400|267"){
setTinyScreenSize();
}else if (size == "800|533"){
setSmallScreenSize();
}else if (size == "1200|800"){
setStandardScreenSize();
}else if (size == "1400|900"){
setLargeScreenSize();
}else if (size == "TD"){
setMaximizedScreenSize();
}
clearCanvas();
drawGrid('rgba(128, 128, 128, 0.5)', 3);
};
/**
* This function works in two sections.
* The first section is the immediate change of the UI depending on the theme the user changed.
* The second section is there to save these changes in the UI to the database if the user is registered.
* If the user is anonymous, a message will let him know that he needs an account to save his preferences.
*
* @function changeScreenLightMode
* @memberof module:UI
* @returns {void}
* @param {string} mode Which of the two modes to set (light / dark).
* @example
* changeScreenLightMode("light");
* changeScreenLightMode("dark");
*/
function changeScreenLightMode(mode){
if (mode == "light"){
CANVAS.classList.remove("canvas-dark");
CANVAS.classList.add("canvas-light");
document.querySelectorAll(".canvas-scrollbars-dark").forEach(scrollbar => {
scrollbar.classList.remove("canvas-scrollbars-dark");
scrollbar.classList.add("canvas-scrollbars-light");
});
}else{
CANVAS.classList.remove("canvas-light");
CANVAS.classList.add("canvas-dark");
document.querySelectorAll(".canvas-scrollbars-light").forEach(scrollbar => {
scrollbar.classList.remove("canvas-scrollbars-light");
scrollbar.classList.add("canvas-scrollbars-dark");
});
};
Object.keys(channelData).forEach(key => {
if (mode == "light"){
document.getElementById(key).classList.remove(channelData[key].colorDark);
document.getElementById(key).classList.add(channelData[key].colorLight);
document.getElementById("scroller-"+key).style.backgroundColor = channelData[key].colorLight;
}else{
document.getElementById(key).classList.remove(channelData[key].colorLight);
document.getElementById(key).classList.add(channelData[key].colorDark);
document.getElementById("scroller-"+key).style.backgroundColor = channelData[key].colorDark;
}
});
config.theme = mode;
//Now we save the new theme to the db for later on.
const UID = userId;
const Http = new XMLHttpRequest();
const url = `/oscillo/setThemePreference/${UID}/`;
const csrfToken = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
Http.open("POST", url, true);
Http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
Http.setRequestHeader("X-CSRFToken", csrfToken);
const data = JSON.stringify({
theme: mode,
});
Http.onreadystatechange = function() {
if (Http.readyState === 4) {
response = JSON.parse(Http.responseText);
if (Http.status === 200) {
console.log(response.message);
showToast(response.message, "toast-success");
} else {
console.log("Error saving theme: ", response.message);
showToast(response.message, "toast-error");
return;
}
}
};
Http.send(data);
};
/**
* This function is used to setup the interactions between the user and each of the vertical offset scrollers (left of the screen).
* It needs to be called for each scroller.
*
* @function setScrollersEvents
* @memberof module:UI
* @returns {void}
* @param {number} Channel_ID Which channel are we setting an offset cursor for.
* @example
* setScrollersEvents(4);
* @listens MouseMove - Whenever the scroller is moved, the new position of the scroller will be saved and its relative position is then mapped to an offset on the corresponding signal.
*/
function setScrollersEvents(Channel_ID){
let isDragging = false;
const scrollBar = document.getElementById("scroll-bar");
const scroller = document.getElementById("scroller-CH"+Channel_ID);
let startY;
scroller.style.display = "block";
scroller.style.backgroundColor = channelData["CH" + Channel_ID].colorDark;
scroller.addEventListener('mousedown', function(event) {
isDragging = true;
startY = event.clientY - scroller.getBoundingClientRect().top + scrollBar.getBoundingClientRect().top;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
function onMouseMove(event) {
if (!isDragging) return;
//this part handles the actual movement of the element on the screen
let newY = event.clientY - startY;
newY = Math.max(newY, 0);
newY = Math.min(newY, scrollBar.clientHeight - scroller.clientHeight);
scroller.style.top = newY + 'px';
//this part maps the relative position of the scroller to the offset of the signal
let percent = newY / (scrollBar.clientHeight - scroller.clientHeight);
let verticalOffset = (percent - 0.5) * 1000;
verticalOffset = Math.round(verticalOffset);
//and now we actually update the vertical offset of the focused channel
channelData["CH" + Channel_ID].verticalOffset = verticalOffset;
};
function onMouseUp(event) {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
//Here below we save the cursor position for that channel to restore it when the user clicks on the channel again
let newY = event.clientY - startY;
newY = Math.max(newY, 0);
newY = Math.min(newY, scrollBar.clientHeight - scroller.clientHeight);
channelData["CH" + Channel_ID].verticalOffsetRelativeCursorPosition = newY;
};
};
/**
* This function is used to setup the interactions for the trigger cursor.
* This cursor shows the user the current threshold set for the trigger and allows them to move it and therefore change the trigger threshold.
*
* @function setupTriggerCursor
* @memberof module:UI
* @returns {void}
* @listens MouseMove - Whenever the scroller is moved, the new position of the scroller will be saved and its relative position is then mapped to an offset on the corresponding signal.
*/
function setupTriggerCursor(){
let startY;
let isDragging = false;
const scrollBar = document.getElementById("scroll-bar-horizontal-cursors");
const TriggerCursor = document.getElementById("trigger-cursor");
TriggerCursor.addEventListener('mousedown', function(event) {
isDragging = true;
startY = event.clientY - TriggerCursor.getBoundingClientRect().top + scrollBar.getBoundingClientRect().top;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
function onMouseMove(event){
if (!isDragging) return;
let newY = event.clientY - startY;
newY = Math.max(newY, 0);
newY = Math.min(newY, scrollBar.clientHeight - TriggerCursor.clientHeight);
TriggerCursor.style.top = newY + 'px';
let cursorPosToMilliVolts = parseFloat(getMilliVoltsRelativeToTriggerCursor(newY).value);
triggerOptions.triggerLevel = cursorPosToMilliVolts;
}
function onMouseUp(event){
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
};