Source: satteldruck_test.js

/*
Copyright (C) 2021 Velometrik GmbH
<http://www.velometrik.de/>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


/* 
    Created on : 04.06.2021, 21:08:29
    Author     : Peter Bauer
*/
// const host = "http://velobox-peter.local:8080";

const host = `http://${location.host}`;
// const ws = "ws://velobox-peter.local:8080"
const ws = `ws://${location.host}`;

const apps= "satteldruckanalyse";

var onsqlresult = getLog;

const canvas_live = document.getElementById('pressureCanvas01');
const canvas_before = document.getElementById('canvas_1');
const canvas_before_result = document.getElementById('canvas_1_1')
let multiply = 7;
let contrastLevel = 4;; // Beispielwert: 2.5 für hohen Kontrast, 0.8 für niedrigen Kontrast
measure01(canvas_before_result);
// const canvasHocker = new fabric.Canvas("canvas_hocker");
// createHockerCanvas(canvasHocker)

var jsn_result1 = new Object();
var jsn_result2 = new Object();

var cable = false
var showText = true;

let sda_live = `${host}/sattelbild`;
let sda_frame1 = `${host}/sattelbild?image=blank`;
let sda_frame2 = `${host}/sattelbild?image=blank`;

let hocker_frame = `${host}/sattelbild?image=blank`;
let setting = new Object();
let galerie_image_info;
let gal=[]
var data;

let note = getFromLocalStorage('session_note')

var load_num;
var querys;

var bread=0

var local_sess;
var reconectStart = false

var sda_int1_3d;
var sda_int2_3d;

clearFromLocalStorage(['sessionID'])

if(getFromLocalStorage('session')){
  local_sess = getFromLocalStorage('session');
  if(local_sess.split(" ")[0]=='restart'){
    saveToLocalStorage('sessionID',local_sess.split(" ")[1])
  } else {
    reconectStart = true
  }
} else {
  LinkTo('clients.tcls')
}


document.getElementById('headliner').innerHTML = `${getFromLocalStorage('client_forenames')} ${getFromLocalStorage('client_surename')}`;




// document.getElementById('product1').setAttribute('placeholder',gettrans('sda_marke'))

function SessReload() {
  saveToLocalStorage('session',local_sess);
  location.reload(true);
}

/**
 * The function sets the contrast value based on the user's input and saves it in local storage.
 */
function setContrast () {
  setting.vertical = $('#vertical').val();
  console.log(setting.vertical);
  saveToLocalStorage("setting",JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
}

/**
 * It sets the pelvis size.
 */
function setPelSize() {
  setting.pelv = $('#pelv').val();
  saveToLocalStorage("setting",JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)

}
/**
 * It takes the value of the input field with the id "time_before" and saves it in the variable
 * "setting.verZeit" in the local storage
 */
function bZeit (){
setting.verZeit = $('#verZeit').val();
saveToLocalStorage("setting",JSON.stringify(setting));
sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
}
/**
 * It takes the value of the input field with the id "aufzeichnung" and saves it in the variable
 * "setting.aufZeit" and then saves the variable "setting" in the local storage
 */
function aZeit (){
setting.aufZeit = $('#aufZeit').val();
saveToLocalStorage("setting",JSON.stringify(setting));
sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
}
/**
 * `setting.center_color = $('#center_color').val();`
 *
 * The above line of code is the only line of code that is needed to change the center color
 */
function CenterColor() {
  setting.center_color = $('#center_color').val();
  saveToLocalStorage('setting', JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}
/**
 * It takes the value of the input field with the id "bg_color" and sets it as the background color of
 * the JPEG image
 */
function BgColor() {
  setting.bgColor = $('#bgColor').val();
  console.log('set bgColor',setting.bgColor);
  sattelanalyse.send(`set jpeg bgcolor ${setting.bgColor}`);
  saveToLocalStorage('setting', JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
}
/**
 * `function PRColor() { setting.pr_color = $('#pr_color').val(); saveToLocalStorage('setting',
 * JSON.stringify(setting)); BgColor() }`
 *
 * The function is called when the user changes the value of the `#pr_color` input element. The value
 * of the input element is stored in the `setting.pr_color` variable. The `setting` variable is then
 * stored in the browser's local storage. The `BgColor()` function is then called to update the
 * background color of the page
 */
function PRColor() {
  setting.pr_color = $('#pr_color').val();
  saveToLocalStorage('setting', JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}
/**
 * `function ITColor(){setting.text_color = $('#it_color').val();saveToLocalStorage('setting',
 * JSON.stringify(setting));BgColor()}`
 */
function ITColor(){
  setting.text_color = $('#text_color').val();
  saveToLocalStorage('setting', JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}
/**
 * `LineColor()` is a function that sets the line color to the value of the `#line_color` input element
 */
function LineColor() {
  setting.line_color = $('#line_color').val();
  saveToLocalStorage('setting',JSON.stringify(setting))
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}
/**
 * If the checkbox is checked, the variable "teil_line" is set to true, otherwise it is set to false
 */
function Einteilung() {
  if ($('#einteilung').is(':checked')) {
    setting.teil_line = true
  } else{
    setting.teil_line = false
  }
  saveToLocalStorage("setting",JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}
/**
 * If the checkbox is checked, then the setting.showText is set to true, otherwise it is set to false
 */
function imageText(){
  if ($('#imgTextcheck').is(':checked')) {
    setting.showText = true
  } else{
    setting.showText = false
  }
  saveToLocalStorage("setting",JSON.stringify(setting));
  sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
  BgColor()
}

let maxValue = 0;
//center of pressure
let cop1={x:0,y:0};
let cop2={x:0,y:0};
let num;

var ch;
var cw;
var sitzknochen;
var matrixLive;

/* The above code is getting the height and width of the Frame-3 class. */
ch = document.getElementsByClassName("Frame-3")[0].offsetHeight;
cw = document.getElementsByClassName("Frame-3")[0].offsetWidth;


let sattelanalyse = new WebSocket(`${ws}/apps/${apps}`, ["soap", "wamp"]);



//if(location.pathname === "/production/saddle_pressure_analysis.tcls"){
//run_Sattelanalyse();

document.getElementById('note_session').value = note;

var sess;
/* The above code is listening for a change in the note_session textarea. When a change is detected,
the code sends a SQL query to the database to update the notes column in the sessions table with the
new value of the textarea. */
document.getElementById('note_session').onchange = function() {
  //console.log("note_session change");
  if(local_sess.split(' ')[0] == "restart"){
    sess = local_sess.split(' ')[1]
  } else{
    onsqlresult = getSession
    sattelanalyse.send(`sql SELECT next_id from nextids n WHERE table_name = 'sessions'`)
  }
  sattelanalyse.send(`sql UPDATE sessions SET notes='${document.getElementById('note_session').value}' WHERE session_id=${sess}`)
  saveToLocalStorage('session_note',document.getElementById('note_session').value)
}
// console.log($(window).height()>$(window).width,$(window).height(),'>',)
if($(window).height()>$(window).width()){
  let append = document.getElementById('tableth')
  let btn = document.createElement('button')
  btn.setAttribute('onclick','abso()')
  btn.innerHTML='#full'
  append.append(btn)
}

/* Checking if the cable is connected or not. If it is not connected, it will show a modal. */
var conBT = setInterval(function () {
  if(cable==false && setting.demo == 'false'){
  connectBt()
  //UIkit.modal($("#modal-connect-with-bluetooth")).show();
  let append = document.getElementsByClassName('navbar-right')[0];
  let li = newElement({element:'li',cls:['nav-item']},append);
  let btn = newElement({element:'button',cls:['uk-button','uk-button-small','uk-button-default','ico-16', 'mdi', 'mdi-connection'],attr:[['onclick','connectBt()'],['key-title','sda_bluetooth_con']]},li)
  } else {
    if(setting.demo == 'true'){
      DemoMode()
    }
    let append = document.getElementsByClassName('navbar-right')[0];
  let li = newElement({element:'li',cls:['nav-item']},append);
  let btn = newElement({element:'button',cls:['uk-button','uk-button-small','uk-button-default','ico-16', 'mdi', 'mdi-movie-star'],attr:[['onclick','DemoMode()']]},li)
  }
  clearInterval(conBT);
}, 1000);
translatejs();
//}

function connectBt() {
  OpenModDialog({type:'success',title:["sda_blue_con_question"],msg:["sda_blue_con_text"],master_btn:['sda_blue_verbinden','con_bluetooth()'],slave_btn:['button_cancel']})
}
/**
 * "When the user clicks the save button, show the save mask modal."
 *
 * The `save_mask()` function is called by the `onclick` attribute of the save button
 */
function save_mask() {
  UIkit.modal($("#modal-save-mask")).show();
}
/**
 * The function `getHockerNr(num)` creates a new WebSocket connection to the SmartCube with the number
 * `num` and runs the function `run_Sitzknochen(num)` to handle the connection.
 * @param num - The number of the cube you want to connect to.
 */
function getHockerNr(num){
  try {
  sitzknochen = new WebSocket(`ws://smartcube${num}.local/messages`,["soap","wamp"]);
  run_Sitzknochen(num);
  } catch (error) {
    getError(error)
  }
}

/**
 * `set_mask` sets the mask to one of the following: `nomask`, `standard`, `large`, `custom` or `<name>`
 * @param param - The name of the mask to use.
 */
function set_mask(param,mask=[0]){
  //console.log(mask, custommask);
    console.log("name",param);
    
    if(mask.length > 2){
      document.querySelectorAll('.line').forEach(div => div.remove());
      custommask = toggleArray(mask.reverse())
      frame3Mask()
      hide_mask();
      let checkbox = document.getElementById('maskedit')
      checkbox.checked = false
    }
    sattelanalyse.send(`set mask ${param}`);
}

function toggleArray(array) {
  return array.map(value => value === 0 ? 1 : 0);
}

/**
 * It deletes a mask from the database
 * @param param - the name of the mask
 */
function del_mask(param){
  sattelanalyse.send(`sql delete from masks where name='${param}'`)
  document.getElementById(`${param}`).classList.add('hide')

}

/**
 * It sends a message to the server to set the compare parameter
 * @param param - the parameter to set
 */
function set_comp(param) {
  console.log(`%c websocet: set compare ${param}`,'background: #222;color: white;padding:1em');
  sattelanalyse.send(`set compare ${param}`);
}

/**
 * It sends a message to the server to start a session and then it displays the client's name and email
 * address
 *
 * @param val - localStorage value of session
 */
function session(val){
  sattelanalyse.send(`session finish`)
  console.log(`%c websocet: session ${val}`,'background: #222;color: white;padding:1em');
    sattelanalyse.send(`session ${val}`)
    onsqlresult = Maskmenue;
    sattelanalyse.send(`sql select * from masks where mask_id > 4`);
}

/**
 * It takes the number of the image, gets the values of the three input fields, and sends them to the
 * server
 * @param num - the number of the image to be saved
 */
function save_rec(num) {
  let info = new Object();
  info.product = $(`#product${num}`)[0].value;
  info.product_label = $(`#product_label${num}`)[0].value;
  info.notes = $(`#notes${num}`)[0].value;
  console.log(`recording store ${num} ${JSON.stringify(info)}`);
  sattelanalyse.send(`recording store ${num} ${JSON.stringify(info)}`);
  
  //TODO: Dialog nach aktuellem CI erstellen und übersetzen!
  UIkit.notification({message: `${aLangKeys[lang]['save_data']}`})

  let inter = setInterval(()=> {
      UIkit.notification.closeAll()
      clearInterval(inter);
    }, 500);

}

/**
 * It sends a SQL query to the server, and when the server responds, it calls the function RowImg
 * @param num - the number of the recording to load
 */
function load_rec(num) {
  load_num = num
  let btn = document.getElementById('img_select_btn');
  btn.setAttribute('disabled','')
  sattelanalyse.send('switch create_norm on')
  console.log('load ',num);
  if(local_sess.split(' ')[0]=='restart'){
  onsqlresult = RowImg
  sattelanalyse.send(`sql select * from recordings WHERE analysis=2 AND session_id=${local_sess.split(' ')[1]}`)
  }
  if(local_sess.split(' ')[0]=='start'){
   onsqlresult = getSession
   sattelanalyse.send(`sql SELECT next_id from nextids n WHERE table_name = 'sessions'`)
   let getrow = setInterval(function () {
    onsqlresult = RowImg
    sattelanalyse.send(`sql select * from recordings WHERE analysis=2 AND session_id=${getFromLocalStorage('new_session')}`)
    clearInterval(getrow);
  }, 1000);
  }

  }


/**
 * The `getSession` function logs the input parameters, calculates a new session value based on the
 * input elements, and saves this new session value to local storage.
 * @param params - It seems like you haven't provided the actual parameters for the `getSession`
 * function. Could you please provide the values for the `params` variable so that I can assist you
 * further with the function?
 */
function getSession(params) {
  onsqlresult = getLog;
  console.log(params);
  params.forEach(element => {
    // console.log(element.next_id-1);
    sess= element.next_id-1;
    //console.log(sess);
    saveToLocalStorage('new_session',element.next_id-1)
  });
}

/**
 * It sends a message to the server that the session is finished
 */
function end_session(){
  console.log('end session');
  
  sattelanalyse.send('session finish')
}
/**
 * It sends a message to the server to cancel the recording of the specified number
 * @param {number}num - The number of the recording to cancel.
 */
function rec_cancel(num) {
  sattelanalyse.send(`recording cancel ${num}`);
}
/**
 * It creates a websocket connection to the smartcube and listens for messages. If the message is of
 * type "sitzknochenabstand" it will draw the sitzknochenabstand on the canvas
 * @param num - the number of the cube you want to connect to.
 */
function run_Sitzknochen(num) {
  //  createHockerCanvas(canvasHocker);
  let hocker_frame = `http://smartcube${num}.local/hockerbild?rnd=${(new Date).getTime()}`;
  //  drawHockerIMG(canvasHocker,hocker_frame)

    sitzknochen.onmessage = (e)=> {
      if(log)
      console.log(e);

      var sitz_data = new Object();

      try {
        sitz_data = JSON.parse(e.data);
      } catch (error) {
        getError(error)
      }

      if(sitz_data.wsevent === "plugged"){
        hocker_frame = `http://smartcube${num}.local/hockerbild?rnd=${(new Date).getTime()}`;
        drawHockerIMG(canvasHocker,hocker_frame);
      }

      if(sitz_data.wsevent === "hockerbild"){
        hocker_frame = `http://smartcube${num}.local/hockerbild?rnd=${(new Date).getTime()}`;
        drawHockerIMG(canvasHocker,hocker_frame);
      }

      if(sitz_data.wsevent === "sitzknochenabstand"){
        var v_sum = sitz_data.v_sum || 0.0;
        hocker_frame = `http://smartcube${num}.local/hockerbild?rnd=${(new Date).getTime()}`;
        setHockerImage(canvasHocker,hocker_frame,{x1:sitz_data.schwerpunkt1_x,y1: sitz_data.schwerpunkt1_y, x2:sitz_data.schwerpunkt2_x, y2:sitz_data.schwerpunkt2_y},sitz_data.sitzknochenabstand,v_sum)
      }

    }
    sitzknochen.onerror= (e)=>{
      getError(e)
    }
}


//!"beforeunload"
/* Adding an event listener to the window object. The event listener is listening for the beforeunload
event. When the event is triggered, the onConfirmRefresh function is called. */
//window.addEventListener("beforeunload", onConfirmRefresh, { capture: true });

/* The above code is a JavaScript code that is binding two events to the window object. */
$( window ).bind( 'beforeunload' , ( event ) => {
  //event.preventDefault();
  return '';
} ).bind( 'unload', ( event ) => {
  sattelanalyse.send('btdisconnect')
} );
/**
 * It sets up the websocket connection and defines what happens when the server sends a message
 */
//function run_Sattelanalyse() {

  console.log('run_Sattelanalyse',sattelanalyse);

    sattelanalyse.onopen = (e) =>{
      console.log(sattelanalyse.OPEN);
      
      sattelanalyse.send('switch create_norm on')
      rec_cancel(1);
      rec_cancel(2);
      sattelanalyse.send('get clientsettings')
      grid_socet('no')
      StopDemo()
      if(local_sess.split(' ')[0]=='restart'){
        sess = local_sess.split(' ')[1]
      }
      if(local_sess.split(' ')[0]=='start'){
         onsqlresult = getSession
         sattelanalyse.send(`sql SELECT next_id from nextids n WHERE table_name = 'sessions'`)
      }
    }

    sattelanalyse.onmessage = (e) => {
      //console.log(e);
      data = new Object();

        try {
           data = JSON.parse(e.data);
        } catch (error) {
          getError(error)
        }
        if(data.wsevent ==="clientsettings"){
          setting = script_setting
          if(setting.initial){
            for (const key in setting) {
              const element = setting[key];
              if($(`#${key}`)[0]){
              $(`#${key}`)[0].value = element
              // console.log($(`#${key}`)[0].value);
              }
            }
            } else {
              setting = script_setting;
              setting.initial = true;
              setting.bgColor = "#000000";
              setting.mask = "nomask";
              setting.aufZeit = 3;
              setting.verZeit = 3;
              setting.center_color="#ff0000";
              setting.teil_color = "#ffffff";
              setting.teil_line = true;
              setting.text_color ="#ffffff";
              setting.pr_color="#000000";
              setting.line_color ="#ffff00";
              setting.showText = true;
              setting.pelv = 1
              setting.demo = "false"
              sattelanalyse.send(`set clientsettings ${JSON.stringify(setting)}`)
              for (const key in setting) {
                const element = setting[key];
                if($(`#${key}`)[0]){
                $(`#${key}`)[0].value = element
                // console.log($(`#${key}`)[0].value);
              }
            }
            }
          }



        /* Checking if the data.wsevent is equal to "error" and if it is, it will call the error_msg
        function and pass the data to it. */
        if(data.wsevent === "error"){
          error_msg(data);
        }

        if(data.wsevent === "demostreams"){
          console.log(data);
          let demo = document.getElementById('listDemo');
          demo.innerHTML = "";
          for (const key in data) {
            if(key != "wsevent"){
              console.log(key,data[key]);
              let ul    = newElement({element:"ul",cls:['uk-list']},demo)
              let li    = newElement({element:"li"},ul)
              let label = newElement({element:"label",attr:[['for',key]]},li)
              let x     = newElement({element:"input",cls:['uk-radio'],id:key,attr:[['type','radio'],['name','demo'],['value',key]]},label)
              label.innerHTML += data[key]
            }
            UIkit.modal($('#modal-demo-mode')).show();
            
            //document.getElementsByClassName('nav_menu')[0].style.backgroundColor = "orange"
            //$("input[type='radio'][name='demo']:checked").val();
          }

        }

        /* The above code is checking if the data.wsevent is equal to "btevent" and if it is, it will check if
        the data.btevent is equal to "error" and if it is, it will hide the modal and display the error
        message. If the data.btevent is equal to "status", it will display the name and address of the
        connected device. */
        if(data.wsevent === "btevent"){
          /* Checking if the data.btevent is equal to "error" and if it is, it will hide the modal and
          display the error message. */
          if (data.btevent === "error") {
          //UIkit.modal($("#modal-connect-bluetooth")).hide();
          error_msg(data);
          }
          // data.btevent = "ambiguity"
          // data.devices = ['eins','zwei','drei']

          if(data.btevent === "ambiguity"){
            let append = document.getElementById('multi_device');
            data.devices.forEach(element => {
              //console.log(element);
              let tr = newElement({element:'tr'},append);
              let td1= newElement({element:'td'},tr);
              td1.innerHTML = element
              let td2= newElement({element:'td'},tr);
              let btn= newElement({element:'button',cls:['uk-button', 'uk-button-default', 'uk-button-small','ico-16','mdi','mdi-connection'],attr:[['onclick',`sattelanalyse.send('btconnect ${element}')`]]},td2)
            });

          UIkit.modal($("#modal-mod_multi")).show();
          }
          /* A JavaScript code that is executed when the event "status" is received. */
          if(data.btevent === "status"){
            if(data.devices[0]){
            //let e1 = document.getElementById('link_bolt');
            //e1.removeAttribute('onclick');
            //let e2 = document.getElementById("bolt");
            //e2.classList.remove('mdi-link-variant-off');
            //e2.classList.add('mdi-link-variant');
            //e2.style.color="green";
            OpenModDialog({type:'neutral',title:["sda_blue_verbunden"],msg:`Gerätename: ${data.devices[0].name}<br>Macadresse: ${data.devices[0].address}`,master_btn:['button_ok']})

            //$('#bt_verbindung_hergestellt')[0].innerHTML = 'Verbunden';
            //$('#bt_verbindung_text')[0].innerHTML = `Gerätename: ${data.devices[0].name}<br>Macadresse: ${data.devices[0].address}`;
            //let btn = newElement({element:'button',cls:['uk-button' ,'uk-button-primary' ,'uk-modal-close']},document.getElementById('btn-bt-conn'))
            //  btn.innerHTML = aLangKeys[lang]['button_ok']
          }
          }
        }

        /* The above code is checking if the state is active. If it is active, then it will run the
        code. */
        if(data.state ==='active'){
          //console.log('active');
          //console.log(setting);
          sattelanalyse.send(`set jpeg colorcontrast ${$('#vertical').val()}`)
          $('#aufZeit')[0].value = setting.aufZeit
          $('#verZeit')[0].value = setting.verZeit
          document.getElementById('center_color').value = setting.center_color
          document.getElementById('bgColor').value = setting.bgColor
          document.getElementById('pr_color').value = setting.pr_color
          document.getElementById('text_color').value = setting.text_color
          document.getElementById('line_color').value = setting.line_color
          $('#pelv')[0].value = setting.pelv
          /* Checking if the setting.teil_line is true or false. If it is true, it will check the
          checkbox. If it is false, it will uncheck the checkbox. */
          if(setting.teil_line===true){
            $('#einteilung')[0].setAttribute('checked','')
          } else{
            $('#einteilung')[0].removeAttribute('checked')
          }
          /* The above code is checking if the showText is true or false. If it is true, then it will
          check the box. If it is false, then it will uncheck the box. */
          if (setting.showText === true) {
            $('#imgTextcheck')[0].setAttribute('checked','')
          } else{
            $('#imgTextcheck')[0].removeAttribute('checked')
          }
        }

        /* Setting the background image of the element with the id "live_img" to the image at the url
        img3. */
        if (data.wsevent === "sattelbild") {
            img3 = `${host}/sattelbild?rnd=${(new Date).getTime()}`;
            document.getElementById('live_img').style.backgroundImage(img3);
        }
        /* Setting the image source to the sda_live image. */
        if (data.wsevent === "sda_live") {
            //sda_live = `${host}/sattelbild?image=sda_live&rnd=${(new Date).getTime()}`;
            //var d = document.getElementById('div_live_img');
            //d.setAttribute("src",`${host}/sattelbild?image=sda_live&rnd=${(new Date).getTime()}`);
            //d.setAttribute("width",cw);
            //d.setAttribute("height",ch);
        }
        /* Setting the image of the canvas to the image from the server. */
        if (data.wsevent === "sda_int1") {
            //sda_frame1 = `${host}/sattelbild?image=sda_int1&rnd=${(new Date).getTime()}`;
            // setImage(canvas1, sda_frame1, false);
             if(jsn_result1.wsevent){
              let inter = setInterval(function () {
                result_1(jsn_result1)
                clearInterval(inter);
              }, 100);
             }
        }
        /* Setting the image to the canvas. */
        if (data.wsevent === "sda_int2") {
            sda_frame2 = `${host}/sattelbild?image=sda_int2&rnd=${(new Date).getTime()}`;
             setImage(canvas2, sda_frame2, false);
             if(jsn_result2.wsevent){
              let inter = setInterval(function () {
                result_2(jsn_result2)
                clearInterval(inter);
              }, 100);
             }

        }
        /* The above code is a JavaScript function that is executed when the sattelanalyse object sends
        a message to the web page. */
        if (data.wsevent === "sda_int3") {
          // console.log('sda_int3');
          let img = document.getElementsByClassName('imgGal1')[fi-1];
          let a = document.getElementsByClassName('imgGal2')[fi-1];
          sda_frame3 = `${host}/sattelbild?image=sda_int3&rnd=${(new Date).getTime()}`;
          img.src=sda_frame3
          a.setAttribute('onclick',`getImgData(${fi-1},this)`)
          gal[fi-1]=JSON.stringify(galerie_image_info)
          //a.setAttribute('onclick',`sattelanalyse.send('recording retrieve ${recID[fi-1]} ${load_num}')`)
          if(galerie_image_info.pelvisrotation)
            pel = `${galerie_image_info.pelvisrotation.width||""}:${galerie_image_info.pelvisrotation.height||""}`
          else
            pel ="-"
          document.getElementsByClassName('info_img')[fi-1].innerHTML =`
          <ul class="uk-list uk-list-collapse">
          <li key="pro_satteldruck_veloscore">Veloscore</li>
          <li key="pro_satteldruck_becken">Rotation</li>
          <li key="pro_satteldruck_leftright">Lins/Rechts</li>
          <li key="pro_satteldruck_frontback">Vorn/Hinten</li>
          </ul>
          <ul class="uk-list uk-list-collapse">
          <li>${galerie_image_info.veloscore}</li>
          <li>${pel}</li>
          <li>${galerie_image_info.left_right}</li>
          <li>${galerie_image_info.front_rear}</li>
          </ul>
          <textarea readonly class="uk-textarea" style="width:150px;height: 60px;margin-left:30px ">${galerie_image_info.notes}</textarea>`
         document.getElementsByClassName('name_img')[fi-1].innerHTML=`
         <h2 class="uk-text-center">${galerie_image_info.product_label||aLangKeys[lang]['sda_marke']}</h2>
         <p class="uk-text-center"><small>${galerie_image_info.product||aLangKeys[lang]['sda_typ']}</small></p>`
          /* Sending a message to the sattelanalyse object. */
          if(recID[fi]){
              // console.log('sda_init3 send');
              sattelanalyse.send(`recording retrieve ${recID[fi]} 3`)
              fi++
          }
      }
        /* Setting the max value of the progress bar to the value of the data.value. */
        if (data.wsevent === "max_value") {
            maxValue = data.value;
            var bar = document.getElementById('js-progressbar_max');
            bar.value = maxValue;
        }
        if (data.wsevent === "result1") {
            console.log("result1",data);
            
            result_1(data);
            jsn_result1 = data;
            if(data.pelvisrotation){
            cop1.x = data.pelvisrotation.center.x;
            cop1.y = data.pelvisrotation.center.y;
            }
            save_rec(1)
            let redraw  = setInterval(() => {
              BgColor();
              clearInterval(redraw);
            }, 1000);

        }
        if (data.wsevent === "result3"){
          console.log("result3",data);
          galerie_image_info = data;
        }
        if (data.wsevent === "result2") {
            console.log("result2",data);
            result_2(data);
            jsn_result2 = data;
            if(data.pelvisrotation){
            cop2.x = data.pelvisrotation.center.x;
            cop2.y = data.pelvisrotation.center.y;
            }
            save_rec(2)
            let redraw  = setInterval(() => {
              BgColor();
              clearInterval(redraw);
            }, 1000);
            if(bread === 0){
              let append = document.getElementById('menu_bread')
              let li = newElement({element:'li'},append)
              let a = newElement({element:'a',cls:['font-12'],attr:[['onclick','toProtokol()'],['key','pro_protokoll']]},li)
              a.innerHTML = '<!--Protokoll-->'
              let li2 = newElement({element:'li'},append)
              let a2 = newElement({element:'a',cls:['font-12'],attr:[['onclick','toGalerie()'],['key','pro_galerie']]},li2)
              a2.innerHTML = '<!--Galerie-->'
              translatejs();
              bread++
             }
        }
       /* Checking the state of the tty. */
        if (data.wsevent === "ttystate"){
            ttystate_check(data)  
        }
       /* Reloading the page when the tty changes. */
        if(data.wsevent === "ttychange"){
            location.reload();
        }
        if(data.wsevent === "appquestions"){
          querys = data.appquestions
        }
        if(data.wsevent === "sattelnorm"){
          if(data.imagetype === 'sda_int1'){
            //DATA3D(data,myChartX1,1)
            const gradient = getReducedGradient(contrastLevel);

            const upscaledMatrix = upscaleMatrixWithOffset(data.values, data.n_rows, data.n_cols, data.n_rows * multiply, data.n_cols * multiply, multiply);
            //const upscaledMatrix = upscaleMatrix(data.values, data.n_rows, data.n_cols, data.n_rows*multiply, data.n_cols*multiply); // Beispiel für höhere Auflösung
            drawHeatmap(upscaledMatrix, data.n_rows*multiply, data.n_cols*multiply, canvas_before, parentDiv_cop,gradient);

            let result = calculateCenterOfPressure(data.values, data.n_rows, data.n_cols);
            drawCoP(result, data.n_rows, data.n_cols,canvas_before_result,parentDiv_cop,true);

          }
          if(data.imagetype === 'sda_int2'){
            //DATA3D(data,myChartX2,2)
          }
          if (data.imagetype === 'sda_live') {
            const gradient = getReducedGradient(contrastLevel);

            // Matrix hochskalieren
            //const upscaledMatrix = upscaleMatrix(data.values, data.n_rows, data.n_cols, data.n_rows * multiply, data.n_cols * multiply);
            const upscaledMatrix = upscaleMatrixWithOffset(data.values, data.n_rows, data.n_cols, data.n_rows * multiply, data.n_cols * multiply, multiply);

            // Heatmap zeichnen mit reduziertem Gradient
            drawHeatmap(upscaledMatrix, data.n_rows * multiply, data.n_cols * multiply, canvas_live, parentDiv_cop, gradient);
        
            // CoPs zeichnen
            let result = calculateCenterOfPressure(data.values, data.n_rows, data.n_cols);
            drawCoP(result, data.n_rows, data.n_cols,canvas_cop,parentDiv_cop);
        }
      }

        //}
        /* A JavaScript function that is called when the server sends a message with the event name
        "sqlresult". */
        if (data.wsevent === "sqlresult"){
          try {
          onsqlresult (data.rows);
          } catch (error) {
            getError(error)
          }
        }
    }
    sattelanalyse.onerror = (e) => {
      getError(e)
    };
//}


/**
 * It takes an array of objects, and for each object, it calls a function called add_mask, passing the
 * name property of the object as a parameter
 * @param params - an array of objects, each object has a name property
 */
function Maskmenue (params){
  console.log("mask",params);
  
  onsqlresult = getLog;
  params.forEach(element => {
    let mask = element.mask.split(' ')
     add_mask(element.name,mask)
  });
}

/**
 * It creates a list item with a div inside, and two links inside the div. The first link is for
 * setting the mask, and the second link is for deleting the mask
 * @param name - the name of the mask
 */
function add_mask(name,mask){
  let append = $('#mask_list')
  let e = newElement({element:'li'},append)
  let div = newElement({element:'div',cls:['mask_link'],id:`${name}`},e)
  let a = newElement({element:'a',attr:[['onclick',`set_mask("${name}",[${mask}])`]]},div)
  let a2 = newElement({element:'a',attr:[['onclick',`del_mask("${name}")`]]},div)
  let span = newElement({element:'span',cls:['ico-16','mdi','mdi-trash-can-outline']},a2)
  a.innerHTML = name
}


/**
 * It takes an array and removes all the elements in that array that are in arguments[1], arguments[2],
 * etc
 * @param arr - The array you want to remove items from.
 * @returns The array with the value removed.
 */
function removeArr(arr) {
  var what, a = arguments, L = a.length, ax;
  while (L > 1 && arr.length) {
      what = a[--L];
      while ((ax= arr.indexOf(what)) !== -1) {
          arr.splice(ax, 1);
      }
  }
  return arr;
}


///**
// * If the state is active and the driver is ttyACM0, then show the modal-tty_smartCover_ok modal.
// * Otherwise, show the modal-tty_smartCover_off modal and hide the card_A card
// * @param jsn - the JSON object returned from the server
// */
function ttystate_check(jsn) {
//  // state, driver
//  let ele = document.getElementById("bolt");
//  let ele2= document.getElementById('link_bolt')

 if (jsn.state === "active" && jsn.driver === "ttyACM0") {
//    ele.classList.remove('mdi-circle-outline')
//    ele.classList.add('mdi-link-variant')
//    ele.style.color="var(--primary-light)";
      cable = true;
  } else {
//    ele.classList.remove('mdi-circle-outline')
//    ele.classList.add('mdi-link-variant-off')
//    ele2.setAttribute('onclick','UIkit.modal($("#modal-connect-with-bluetooth")).show()')
//    ele.style.color="red";
  }
}

/**
 * It opens a modal window and sends a command to the server.
 */
function con_bluetooth() {
  let con = setInterval(function () {
    //UIkit.modal($("#modal-connect-bluetooth")).show();
    connectingBt()
    sattelanalyse.send(`btconnect`);
    //console.log('btconnect');
    clearInterval(con);
  }, 100);
}

function connectingBt() {
  OpenModDialog({type:'neutral',title:["sda_blue_con_gedult"],msg:["bt_verbindung_text"]})
}

/**
 * It takes a JSON object and displays it in a modal
 * @param jsn - The JSON object that is returned from the server.
 */
function error_msg (jsn){
  //console.log("Error Message: ",jsn);  
  let txt = "";
  let txt_num = "";

  if(jsn.class == 'fail'){
    txt_num = 'err_bt_fail';
  }

  if(jsn.wsevent){
    txt += `<p>WSEVENT: ${jsn.wsevent}</p>`
  }
  if(jsn.class == 'disconnected'){
    txt_num = 'err_bt_discon';
  }

  if(jsn.class){
    txt += `<p>CLASS: ${jsn.class}</p>`
  }

  if (jsn.msg) {
    txt += `<p>MESSAGE: ${jsn.msg}</p>`;
  }
  
  if(jsn.source){
    txt += `<p>SOURCE: ${jsn.source}</p>`
  }
  if(jsn.nr){
    txt += `<p>ERROR-CODE: ${jsn.nr}</p>`
  }
  if(jsn.nr == 3){
    txt_num = 'err_num_3';
    OpenModDialog({type:'warn',title:[txt_num],msg:txt,master_btn:['button_ok']})
  }
  if(jsn.nr == 1){
    txt_num ='err_num_1';
    OpenModDialog({type:'warn',title:[txt_num],msg:txt,master_btn:['button_ok']})
  }
  if(jsn.nr == 5){
    txt_num = 'err_num_5';
    OpenModDialog({type:'warn',title:[txt_num],msg:txt,master_btn:['button_ok']})
  }
  if(jsn.nr != 1 && jsn.nr != 3 && jsn.nr != 5){
    if(txt.includes("doesn't exist")){
      OpenModDialog({type:'error',title:"doesn't exist",msg:txt,master_btn:['button_ok','LinkTo("clients.tcls")']})
    } else{
      OpenModDialog({type:'error',title:[txt_num],msg:txt,master_btn:['button_ok']})
    }
  }
}
/**
 * It opens a modal window
 */
function sattel_einstellungen() {
  UIkit.modal($("#modal-einstellungen")).show();
}
var img_a1=0;
var img_a2=0;
/**
 * It takes a number as an argument, and then it uses that number to find the progress bar with the
 * same number in its id. Then it uses the value of the progress bar to determine how long it should
 * take to fill the progress bar
 * @param num - The number of the progress bar.
 */
//function ProgressTimeHandler(num) {
//  const bar = document.getElementById(`js-progressbar_${num}`);
//  const aufnahme = setting.aufZeit;// document.getElementById(`aufzeichnung`).value;
//  const before = setting.verZeit; // document.getElementById(`time_before`).value;
//  let lauf = true;
//  if(num===1){
//  jsn_result1= new Object();
//  if(img_a1>0)
//    save_rec(1)
//  img_a1++
//  }
//  if(num===2){
//  jsn_result2= new Object();
//  if(img_a2>0)
//    save_rec(2)
//  img_a2++
//  }
//  /* A progress bar that is used to show the user how much time is left until the next recording. */
//  var ani = setInterval(()=>{
//    if (lauf) {
//      const v = 100 / before;
//      bar.value += v;
//    } else {
//      const v = 100 / aufnahme;
//      bar.value -= v;
//    }

//    if (bar.value >= bar.max && lauf) {
//      lauf = false;
      
//      sattelanalyse.send(`record ${aufnahme} ${num}`);
//      //createAnimation(5)
//    }

//    if (bar.value <= 0 && !lauf) clearInterval(ani);
//  }, 1000);
//}

let sessReload = true;

function ProgressTimeHandler(num) {
  const bar = document.getElementById(`js-progressbar_${num}`);
  const { aufZeit: aufnahme, verZeit: before } = setting; // Verkürzte Zuweisung
  let lauf = true;

  // Initialisieren der Ergebnisobjekte und Aufzeichnungen basierend auf num
  const jsn_result = num === 1 ? (jsn_result1 = {}) : (jsn_result2 = {});
  const img_a = num === 1 ? img_a1++ : img_a2++;

  if (img_a > 0) save_rec(num);
  //sattelanalyse = new WebSocket(`${ws}/apps/${apps}`, ["soap", "wamp"]);
  if(sessReload === true && reconectStart === false){
    session(local_sess)
    //sattelanalyse.send(`session ${local_sess}`)
    sessReload = false
  }

  if(reconectStart === true){
    sattelanalyse = new WebSocket(`${ws}/apps/${apps}`, ["soap", "wamp"]);
  }
  // Fortschrittsbalken-Animation
  const ani = setInterval(() => {
    const progressStep = lauf ? 100 / before : 100 / aufnahme;
    bar.value += lauf ? progressStep : -progressStep;

    if (bar.value >= bar.max && lauf) {
      if(reconectStart === true){
        sattelanalyse.send(`session ${local_sess}`)
        reconectStart = false
        sessReload = false
      }
      lauf = false;
      console.log('record', sattelanalyse);
      if(sattelanalyse.readyState === 1)
      sattelanalyse.send(`record ${aufnahme} ${num}`);
    }

    if (bar.value <= 0 && !lauf) {
      
      clearInterval(ani);
    }
  }, 1000);
}


//const canvas1 = new fabric.Canvas("canvas_1");
const canvas2 = new fabric.Canvas("canvas_2");
const canvas3 = new fabric.Canvas("live_img");


//createCanvas(canvas1);
createCanvas(canvas2);
createCanvas(canvas3);

img3 = `/sattelbild?rnd=${new Date().getTime()}`;

//measure(canvas1);
measure(canvas2);

addEventListener("resize", (event) => {
  ch = document.getElementsByClassName("Frame-3")[0].offsetHeight;
  cw = document.getElementsByClassName("Frame-3")[0].offsetWidth;
  //createCanvas(canvas1);
  createCanvas(canvas2);
  createCanvas(canvas3);
  canvas_cop.width = parentDiv_cop.clientWidth;
  canvas_cop.height = parentDiv_cop.clientHeight;
  resetTrail()
});

/**
 * It sends a command to the server to set the background color of the JPEG image
 * @param color - The color to set the background to.
 */
function setBgColor(color) {
  $('#bg_color_txt').val(color);
  // sattelanalyse.send(`set jpeg bgcolor ${color}`);
}

/**
 * It sets the value of the text input field with the id `center_color_txt` to the value of the
 * parameter `color`
 * @param color - The color to set the center of the image to.
 */
function setCenterColor(color) {
  $('#center_color_txt').val(color);
  // sattelanalyse.send(`set jpeg bgcolor ${color}`);
}

/**
 * Create a canvas object with the given parameters, and set the height and width to the values of the
 * global variables cw and ch.
 * @param params - The object that contains the parameters for the canvas.
 */
function createCanvas(params) {
  params.selection = false; // disable group selection
  params.hasControls = false;
  params.lockMovement= false;
  params.setHeight(ch);
  params.setWidth(cw);
}

/**
 * It creates a canvas object and sets the height and width of the canvas to the height and width of
 * the browser window
 * @param params - The object that is passed to the function.
 */
function createHockerCanvas(params) {
  params.selection = false; // disable group selection
  params.hasControls = false;
  params.lockMovement= false;
  params.setHeight(cw);
  params.setWidth(ch);
}

/**
 * It takes a canvas, an image, and a boolean, and then it adds the image to the canvas, and then it
 * draws the text and the grid if the boolean is true
 * @param params - the canvas object
 * @param img - the image to be loaded
 * @param grid - boolean, whether to draw the grid or not
 */
function setImage(params, img, grid) {
  fabric.Image.fromURL(img, function (oImg) {
    oImg.scaleToWidth(cw);
    oImg.hasControls = true;
    oImg.set("selectable", false);
    params.add(oImg);
  });
}

/**
 * It takes in a fabric.js canvas object, an image, a coordinate, a number of centimeters, and a sum of
 * the number of centimeters of all the hockers in the room. If the sum is not zero, it adds the image
 * to the canvas, and then calls three other functions to add text, and two lines to the canvas
 * @param params - the canvas
 * @param img - the image to be drawn
 * @param coord - the coordinates of the hocker
 * @param cm - the number of the hocker
 * @param v_sum - the value of the hocker
 */
function setHockerImage(params,img,coord,cm,v_sum) {
if(v_sum !== 0){
  //  console.log(cm);
   $('#sitzknochenabstand').val(`${cm} cm`)
  fabric.Image.fromURL(img, function (oImg) {
    oImg.scaleToWidth(ch);
    oImg.hasControls = false;
    oImg.set("selectable", false);
    params.add(oImg);
    drawHockertext(params,cm);
    drawHockercop1(params, coord);
    drawHockercop2(params, coord);
  });
}
}


function drawHockerIMG(params,img){
  // console.log(params,img);
  fabric.Image.fromURL(img, function (oImg) {
    oImg.scaleToWidth(ch);
    oImg.hasControls = false;
    oImg.set("selectable", false);
    params.add(oImg);
  })
}

/**
 * It draws a text on the canvas
 * @param c - the canvas object
 */
function drawtext(c,left,top,stext) {
    var text = new fabric.Text(stext, {
      left: left,
      top: top,
      fontSize: 14,
      fontFamily:"Ruda, Helvetica Neue,Helvetica, Arial, sans-serif",
      fill: setting.text_color,
      selectable: false,
      selection: false
    });
    c.add(text);
}

/**
 * It draws a line on the canvas
 * @param c - the canvas object
 * @param left1 - the x coordinate of the first point
 * @param left2 - the x coordinate of the end of the line
 * @param top1 - the top position of the first point
 * @param top2 - the y-coordinate of the end of the line
 */
function drawLine(c,left1,left2,top1,top2) {
  let line = new fabric.Line([left1,top1,left2,top2],{
    stroke:setting.text_color,
    selectable: false,
    selection: false
  })
  c.add(line);
}

/**
 * It takes two arguments, a canvas object and a number, and draws a text on the canvas object
 * @param c - the canvas object
 * @param cm - The height of the hocker in cm.
 */
function drawHockertext(c,cm) {
    var text = new fabric.Text(`${cm} cm`, {
      left: ch/2.3,
      top: cw/1.2,
      fontSize: 40,
      stroke: "rgba(55, 255, 50, 0.9)"
    });
    c.add(text);
}

function drawHockercop1(c,xy) {
  var x1 = xy.x1 * (ch / 28);
  var x2 = cw - xy.y1 * (cw / 16);
  var kreis = new fabric.Circle({
    left: x1 - 10,
    top: x2 - 10,
    radius: 10,
    fill: "rgba(255,255,255,0.7)",
    selectable: false,
    selection: false,
    border: 0
  });
  c.add(kreis);
}

function drawHockercop2(c,xy) {
  var x1 = xy.x2 * (ch / 28);
  var x2 = cw - xy.y2 * (cw / 16);
  var kreis = new fabric.Circle({
    left: x1 - 10,
    top: x2 - 10,
    radius: 10,
    fill: "rgba(255,255,255,0.7)",
    selectable: false,
    selection: false,
    border: 0
  });
  c.add(kreis);
}

/**
 * It draws a line between two points and calculates the length of the line
 * @param canvas - the canvas object
 * @returns A function that takes a canvas as an argument.
 */
function measure(canvas) {
  var line, isDown,text;
  var startx = [];
  var endx = [];
  var starty = [];
  var endy = [];
  var temp = 0;
  // var graphtype;
  var trigger = 1;
  // var text;
  var count = 0;
  var color_a = "red";

//BgColor()
  canvas.on("mouse:dblclick",function(o){
    //console.log(canvas);
    BgColor();

  });

  canvas.on("mouse:down", function (o) {
    if (trigger===1) {
      isDown = true;
      var pointer = canvas.getPointer(o.e);

      var points = [pointer.x, pointer.y, pointer.x, pointer.y];
      startx[temp] = pointer.x;
      starty[temp] = pointer.y;
      line = new fabric.Line(points, {
        strokeWidth: 2,
        stroke: color_a,
        originX: "center",
        originY: "center"
      });
      canvas.add(line);
      count++;
    } else {
      canvas.forEachObject(function (o) {
        o.setCoords();
      });
    }
  });

  canvas.on("mouse:move", function (o) {
    canvas.remove(text);
    canvas.renderAll();
    if (!isDown) return;
    var pointer = canvas.getPointer(o.e);
    line.set({
      x2: pointer.x,
      y2: pointer.y
    });

    endx[temp] = pointer.x;
    endy[temp] = pointer.y;

    if (trigger === 1) {
      var px = Calculate.lineLength(
        startx[temp],
        starty[temp],
        endx[temp],
        endy[temp]
      );
      text = new fabric.Text("x" + count + ": " + px + " cm", {
        left: startx[temp],
        top: starty[temp],
        stroke: setting.text_color,
        fontSize: 12,
        fontFamily:"Ruda, Helvetica Neue,Helvetica, Arial, sans-serif"
      });
      // text = new fabric.Text('Length ' + px/5, { left: endx[temp], top: endy[temp], fontSize: 12 });
      canvas.add(text);
    }

    canvas.renderAll();
  });

  canvas.on("mouse:up", function (o) {
    if (trigger===1) {
      var px = Calculate.lineLength(
        startx[temp],
        starty[temp],
        endx[temp],
        endy[temp]
      );
      text = new fabric.Text(`x${count}: ${px} cm`, {
        left: startx[temp],
        top: starty[temp],
        stroke: setting.text_color,
        fontSize: 12,
        fontFamily:"Ruda, Helvetica Neue,Helvetica, Arial, sans-serif"
      });
      // text1 = new fabric.Text('Length ' + px/5, { left: endx[temp], top: endy[temp], fontSize: 12 });
      canvas.add(text);
    }

    canvas.renderAll();
    var pointer = canvas.getPointer(o.e);
    isDown = false;
  });

  canvas.on("mouse:out",function (e) {
    // e.target.setStroke(color_b);
    if (text) text.setStroke(color_a);
    trigger = 1;

    canvas.renderAll();
  });

  // canvas.on("mouse:wheel", function (opt) {
  //   opt.e.preventDefault();
  //   opt.e.stopPropagation();
  //   if (opt.e.ctrlKey) {
  //     // console.log("pinch");
  //     var delta = opt.e.deltaY;
  //     var zoom = canvas.getZoom();
  //     zoom *= 0.999 ** delta;
  //     canvas.setZoom(zoom);
  //   } else {
  //     var e = opt.e;
  //     // var vpt = this.viewportTransform;
  //     // vpt[4] += e.deltaX;
  //     // vpt[5] += e.deltaY;
  //     this.requestRenderAll();
  //   }
  // });

  var Calculate = {
    lineLength: function (x1, y1, x2, y2) {
      var linePixelsX = x1 - x2;
      var linePixelsY = y1 - y2;
      var gregVar = linePixelsX - linePixelsY;
      // horizontal/vertical components of line in pixels
      var horizontalMPP = ch / 28 / (cw / 16);
      var verticalMPP = ch / 28 / (cw / 16);
      // horizontal/vertical meters per pixel, p being according canvas measurement in pixels and m being the measurement (in meters) of the area it should represent
      var lineMetersX = linePixelsX * horizontalMPP;
      var lineMetersY = linePixelsY * verticalMPP;
      //                      // calculate horizontal/vertical line components in meters
      var lineMetersTotal =
        lineMetersX * lineMetersX + lineMetersY * lineMetersY;
      lineMetersTotal = Math.sqrt(lineMetersTotal).toFixed(2);
      return (lineMetersTotal / (cw / 16)).toPrecision(4);
    },
  };
}

var imageSaver1 = document.getElementById("lnkDownload1");
imageSaver1.addEventListener("click", saveImage_n1, false);
var imageSaver2 = document.getElementById("lnkDownload2");
imageSaver2.addEventListener("click", saveImage_n2, false);


/**
 * `saveImage_n1()` is a function that saves the current canvas as a png file
 */
function saveImage_n1() {
  var timestamp = new Date()
  this.href = canvas1.toDataURL({
    format: "png",
    quality: 100,
    width: cw,
    height: ch,
    crossOriginIsolated: false,
  });
    this.download = `${localStorage.client_name}_${timestamp.toLocaleString()}.png`;
}


/**
 * The function `saveImage_n2()` is called when the user clicks on the download button. It saves the
 * current canvas as a PNG image with the name `Messung_Frame_B.png` in the download folder of the user
 */
function saveImage_n2() {
  var timestamp = new Date()
  this.href = canvas2.toDataURL({
    format: "png",
    quality: 100,
    width: cw,
    height: ch,
    crossorigin: "anonymous",
  });
    this.download = `${localStorage.client_name}_${timestamp.toLocaleString()}.png`;

}


/**
 * It sends a command to the sattelanalyse server to set the grid type for all three JPEG streams
 * @param type - line, dotted, no
 */
function grid_socet(type){
  sattelanalyse.send(`set jpeg 0 grid ${type}`);
  sattelanalyse.send(`set jpeg 1 grid ${type}`);
  sattelanalyse.send(`set jpeg 2 grid ${type}`);
  if(jsn_result1.wsevent){
    let inter = setInterval(() => {
      result_1(jsn_result1)
      clearInterval(inter);
    }, 100);
   }
   if(jsn_result2.wsevent){
    let inter = setInterval(() => {
      result_2(jsn_result2)
      clearInterval(inter);
    }, 100);
   }
}

/**
 * It sends a command to the server to set the color contrast of the JPEG image
 * @param num - 0-7
 */
function set_contrast(num){
  setContrast();
  // console.log(`set jpeg colorcontrast ${num}`);
  sattelanalyse.send(`set jpeg colorcontrast ${num}`);
}

/**
 * "When the user clicks on the button, toggle the class 'hide' on the element with the class 'line'."
 *
 * The first line of the function is a variable declaration. The variable is called 'elm' and it's
 * assigned the value of the jQuery selector $(".line"). This means that the variable 'elm' is now a
 * jQuery object that represents the element with the class 'line'
 */
function hide_mask() {
  let elm = $(".line");
  elm.toggleClass("hide");
  canvas_cop.classList.toggle('hide')
}

function result1(x, y,z,canvas) {
  // console.log(x,y,z,canvas);
  var x1 = x * (cw / 16);
  var x2 = ch - y * (ch / 28);
  var mult = ch/28
  var points = [z.center_left.x * mult,ch - z.center_left.y * mult , z.center_right.x * mult, ch - z.center_right.y * mult];
  //line
  line = new fabric.Line(points, {
    strokeWidth: 2,
    stroke: setting.line_color,
    originX: "center",
    originY: "center",
    selectable: false,
    selection: false
  });
  if(z.pelvisrotation)
  var c = [
    //{
		//x: z.pelvisrotation.c1.x*mult, y: ch - z.pelvisrotation.c1.y * mult
	  //},
     {
     x:z.pelvisrotation.front.x*mult,y:ch - z.pelvisrotation.front.y*mult
     },
    //{
		//x: z.pelvisrotation.c2.x*mult, y: ch - z.pelvisrotation.c2.y * mult
	  //},
     {
     x:z.pelvisrotation.right.x*mult,y:ch-z.pelvisrotation.right.y*mult
     },
    //{
    //x: z.pelvisrotation.c3.x*mult, y: ch - z.pelvisrotation.c3.y * mult
	  //},
     {
     x:z.pelvisrotation.rear.x*mult,y:ch-z.pelvisrotation.rear.y*mult
     },
    //{
    //x: z.pelvisrotation.c4.x*mult, y: ch - z.pelvisrotation.c4.y * mult
	  //},
     {
     x:z.pelvisrotation.left.x*mult,y:ch-z.pelvisrotation.left.y*mult
     },
    //{
    //  x: z.pelvisrotation.c1.x*mult, y: ch - z.pelvisrotation.c1.y * mult
    //  },
]

//var Pelv_size = {width:(z.pelvisrotation.width*mult),height:(z.pelvisrotation.height*mult)}
//console.log(c,z.pelvisrotation);

if(z.pelvisrotation)
var polygon = new fabric.Rect({
  left: x1 - ((z.pelvisrotation.width)*setting.pelv)/2,
  top: x2 - ((z.pelvisrotation.height)*setting.pelv)/2,
  fill: 'rgba(255,255,255,0.3)',
  selectable: false,
  selection: false,
  stroke:setting.pr_color,
  width: (z.pelvisrotation.width)*setting.pelv,
  height: (z.pelvisrotation.height)*setting.pelv
});

	//var polygon = new fabric.Polygon(c, {
	//	strokeWidth: 1,
  //  stroke: setting.pr_color,
  //  fill:'rgba(0,0,0,0)',
	//	//scaleX: setting.pelv,
	//	//scaleY: setting.pelv,
  //  left:x1,
  //  top:x2,
  //  selectable: false,
  //  selection: false
	//});

  //center of Presure
  var kreis = new fabric.Circle({
    left: x1 - 10,
    top: x2 - 10,
    radius: 10,
    // fill: setting.center_color,
      fill: 'rgba(255,255,255,0.3)',
      stroke: setting.center_color,
    selectable: false,
    selection: false,
    border: 0
  });
  if(setting.showText){
  let abstand = 0;
  drawtext(canvas,10,10,`${aLangKeys[lang]['sda_leftright']}:`);
  abstand=aLangKeys[lang]['sda_leftright'].length;
  drawtext(canvas,10,30,`${aLangKeys[lang]['sda_frontrear']}:`);
  if(aLangKeys[lang]['sda_frontrear'].length>abstand)
  abstand=aLangKeys[lang]['sda_frontrear'].length;
  abstand=abstand+270;
  drawtext(canvas,abstand,10,`${z.left_right}`);
  drawtext(canvas,abstand,30,`${z.front_rear}`);
    if(z.pelvisrotation){
    drawtext(canvas,10,50,`${aLangKeys[lang]['sda_rotation']}:`);
    drawtext(canvas,abstand,50,`${z.pelvisrotation.width}:${z.pelvisrotation.height}`);
    }
  }
  canvas.add(kreis);
  canvas.add(line);
  if(z.pelvisrotation)
	canvas.add(polygon);
  if(setting.teil_line){
  drawLine(canvas,cw/2,cw/2,ch/2,ch);
  drawLine(canvas,0,cw,ch/2,ch/2);
  }
  canvas.renderAll();
}

$('#product1')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product1')){
    let pro1 = JSON.parse(getFromLocalStorage('product1'))
    pro1.product = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.product = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  }
});
$('#product_label1')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product1')){
    let pro1 = JSON.parse(getFromLocalStorage('product1'))
    pro1.label = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.label = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  }
});
$('#notes1')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product1')){
    let pro1 = JSON.parse(getFromLocalStorage('product1'))
    pro1.note = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.note = this.value
    saveToLocalStorage('product1',JSON.stringify(pro1))
  }
});
$('#product2')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product2')){
    let pro1 = JSON.parse(getFromLocalStorage('product2'))
    pro1.product = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.product = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  }
});
$('#product_label2')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product2')){
    let pro1 = JSON.parse(getFromLocalStorage('product2'))
    pro1.label = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.label = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  }
});
$('#notes2')[0].addEventListener('input', function (evt) {
  //console.log(this.value);
  if(getFromLocalStorage('product2')){
    let pro1 = JSON.parse(getFromLocalStorage('product2'))
    pro1.note = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  } else {
    let pro1 = {}
    pro1.note = this.value
    saveToLocalStorage('product2',JSON.stringify(pro1))
  }
});

var product1 = new Object();
var product2 = new Object();

product1 = getFromLocalStorage('product1') ? JSON.parse(getFromLocalStorage('product1')) : {"product":"","label":"","note":""};
product2 = getFromLocalStorage('product2') ? JSON.parse(getFromLocalStorage('product1')) : {"product":"","label":"","note":""};

function clearProduct(num){
  clearFromLocalStorage([`product${num}`])
  $(`#product${num}`)[0].value = '';
  $(`#product_label${num}`)[0].value = '';
  $(`#notes${num}`)[0].value = '';
}
/**
 * The function takes the JSON object returned from the API and displays the results on the page
 * @param jsn - the JSON object returned from the API
 */
function result_1(jsn) {
  //console.log('result1',jsn);

  if(jsn.product === ""){
    setProduct1({pro:`(${aLangKeys[lang].sda_marke})`})
  } else {
    setProduct1({pro:jsn.product})
  }

  if(jsn.product_label === ""){
    setProduct1({label:`(${aLangKeys[lang].sda_typ})`})
  } else {
    setProduct1({label:jsn.product_label})
  }

  if(jsn.notes === "") {
    setProduct1({note:" "})
  } else {
    setProduct1({note:jsn.notes})
  }


  $("#res1_veloscore")[0].innerHTML = jsn.veloscore||'';
  $("#res1_front_rear")[0].innerHTML = jsn.front_rear||'';
  $("#res1_left_right")[0].innerHTML = jsn.left_right||'';
  //$('#product1')[0].value = pro.product;
  //$('#product_label1')[0].value =pro.label;
  //$('#notes1')[0].value = pro.note;
  if(jsn.pelvisrotation){
  $("#res1_rotation")[0].innerHTML =
  jsn.pelvisrotation.width + ":" + jsn.pelvisrotation.height||'';
  var res1 = setInterval(function () {
    var x = jsn.pelvisrotation.width/jsn.pelvisrotation.height;
    //result1(jsn.pelvisrotation.center.x, jsn.pelvisrotation.center.y,jsn,canvas1);
    clearInterval(res1);
  }, 1000);
} else{
  $("#res1_rotation")[0].innerHTML = 'no Data'
  var res1 = setInterval(function () {
    result1(jsn.center.x, jsn.center.y,jsn,canvas1);
    clearInterval(res1);
  }, 1000);
}
}

/**
 * It takes the JSON object returned from the server and displays the results on the page
 * @param jsn - the JSON object returned from the API
 */
function result_2(jsn) {
  //console.log('result2',jsn);

  if(jsn.product === ""){
    setProduct2({pro:`(${aLangKeys[lang].sda_marke})`})
  } else {
    setProduct2({pro:jsn.product})
  }

  if(jsn.product_label === ""){
    setProduct2({label:`(${aLangKeys[lang].sda_typ})`})
  } else {
    setProduct2({label:jsn.product_label})
  }

  if(jsn.notes === "") {
    setProduct2({note:" "})
  } else {
    setProduct2({note:jsn.notes})
  }


  $("#res2_veloscore")[0].innerHTML = jsn.veloscore;
  $("#res2_front_rear")[0].innerHTML = jsn.front_rear;
  $("#res2_left_right")[0].innerHTML = jsn.left_right;
  //$('#product2')[0].value = pro.product;
  //$('#product_label2')[0].value = pro.label;
  //$('#notes2')[0].value = pro.note;
  if(jsn.pelvisrotation){
  $("#res2_rotation")[0].innerHTML =
  jsn.pelvisrotation.width + ":" + jsn.pelvisrotation.height;
  var res2 = setInterval(function () {
    result1(jsn.pelvisrotation.center.x, jsn.pelvisrotation.center.y,jsn,canvas2);
    clearInterval(res2);
  }, 1000);
} else{
  $("#res2_rotation")[0].innerHTML = 'no Data'
  var res2 = setInterval(function () {
    try {
      result1(jsn.center.x, jsn.center.y,jsn,canvas2);
    } catch (error) {
      console.log(error);
      
    }
    clearInterval(res2);
  }, 1000);
}
}

/**
 * It reads the values of the three input fields and sends them to the server
 */
function toProtokol() {
  if(local_sess.split(' ')[0]=='restart'){
    sess = local_sess.split(' ')[1]
  }
  if(local_sess.split(' ')[0]=='start'){
     onsqlresult = getSession
     sattelanalyse.send(`sql SELECT next_id from nextids n WHERE table_name = 'sessions'`)
  }
  let info = new Object();
  info.product = $(`#product1`)[0].value;
  info.product_label = $(`#product_label1`)[0].value;
  info.notes = $(`#notes1`)[0].value;
  // console.log(`recording store 1 ${JSON.stringify(info)}`);
  sattelanalyse.send(`recording store 1 ${JSON.stringify(info)}`);
  info.product = $(`#product2`)[0].value;
  info.product_label = $(`#product_label2`)[0].value;
  info.notes = $(`#notes2`)[0].value;
  // console.log(`recording store 2 ${JSON.stringify(info)}`);
  sattelanalyse.send(`recording store 2 ${JSON.stringify(info)}`);
  sattelanalyse.send(`sql UPDATE sessions SET notes='${document.getElementById('note_session').value||""}' WHERE session_id=${sess}`)
  location.pathname = '/production/protokoll.tcls';
}

function toGalerie() {
  if(local_sess.split(' ')[0]=='restart'){
    sess = local_sess.split(' ')[1]
  }
  if(local_sess.split(' ')[0]=='start'){
     onsqlresult = getSession
     sattelanalyse.send(`sql SELECT next_id from nextids n WHERE table_name = 'sessions'`)
  }
  let info = new Object();
  info.product = $(`#product1`)[0].value;
  info.product_label = $(`#product_label1`)[0].value;
  info.notes = $(`#notes1`)[0].value;
  // console.log(`recording store 1 ${JSON.stringify(info)}`);
  sattelanalyse.send(`recording store 1 ${JSON.stringify(info)}`);
  info.product = $(`#product2`)[0].value;
  info.product_label = $(`#product_label2`)[0].value;
  info.notes = $(`#notes2`)[0].value;
  // console.log(`recording store 2 ${JSON.stringify(info)}`);
  sattelanalyse.send(`recording store 2 ${JSON.stringify(info)}`);
  sattelanalyse.send(`sql UPDATE sessions SET notes='${document.getElementById('note_session').value||""}' WHERE session_id=${sess}`)
  location.pathname = '/production/galerie.tcls';
}

/**
 * It opens the modal window with the ID "modal-einstellungen" when the button with the ID "config" is
 * clicked
 */
//function config() {
//  UIkit.modal('#modal-einstellungen').show();
//}

/**
 * It takes a parameter, and logs it to the console
 * @param params - {
 */
function getLog(params){
  console.log(params);
}

// function session_img(num) {
//   load_num = num
//   onsqlresult = RowImg
//   session.send(`sql select * from recordings where session_id=${session_id}`)
// }

/**
 * It takes an array of objects, each object has a recording_id property, and it creates a list of
 * images, each image is a thumbnail of the recording_id
 * @param params - an array of objects, each object has a recording_id property
 */
function RowImg(params) {
  if(params.length == 0){
    document.getElementById('ZeroImage').classList.remove('hidden')
  }
  fi = 0;
  recID = [];
  onsqlresult = getLog;
  var append1 = document.getElementById('img_list')//('img_gal')
  append1.innerHTML ="";
  params.forEach(element => {
      // console.log(element);
          if(fi===0){
              sattelanalyse.send(`recording retrieve ${element.recording_id} 3`)
              fi++
          }
          recID.push(element.recording_id)

          const master      = newElement({element:'div',id:`img_${element.recording_id}`,cls:['imgGal2']},append1);
          const div         = newElement({element:'div',id:`sel_${element.recording_id}`,cls:['flex-column-center']},master);
          const date        = newElement({element:'p',cls:['uk-text-center']},master).innerHTML = element.finished;
          const div_name    = newElement({element:'div',cls:['name_img']},div);
          const img         = newElement({element:'img',cls:['imgGal1'],attr:[['width','100'],['height','100']]},div);
          const div2        = newElement({element:'div',attr:[['style','width: 150px']]},div);
          const div_info    = newElement({element:'div',cls:['uk-grid','uk-child-width-1-2','info_img','detail','hidden'],attr:[['style','margin: 0 -30px;']]},div2);
          const chk = document.getElementById('check_img_detail');
          if(chk.checked){
            div_info.classList.remove('hidden')
          }
  });
  UIkit.modal($("#modal-mod_imgList")).show();

}

function getImgData(num,ele) {
  galerie_image_info = JSON.parse(gal[num])

  let noselect1 = document.getElementsByClassName('imgGal2')
  for (const iterator of noselect1) {
    iterator.removeAttribute('style')
  }
  let noselect2 = document.getElementsByClassName('flex-column-center')
  for (const iterator of noselect2) {
    iterator.removeAttribute('style')
  }
  ele.setAttribute('style','scale:1.2;transition: all 0.3s linear;')
  ele.firstChild.setAttribute('style','box-shadow:0 0 1em var(--primary);border-radius:0.5em;transition: all 0.3s linear;')

  //let noselect = document.getElementsByClassName('flex-column-center')
  //for (const iterator of noselect) {
  //  iterator.removeAttribute('style')
  //}
  //ele.firstChild.setAttribute('style','border: 1px solid var(--primary);padding: 0.5em')

   let btn = document.getElementById('img_select_btn');
   btn.setAttribute('onclick',`sattelanalyse.send('switch create_norm on');sattelanalyse.send('recording retrieve ${recID[num]} ${load_num}')`)
   btn.removeAttribute("disabled")
  translatejs()
}

check_img_detail.addEventListener('change', function() {
  let detail = document.getElementsByClassName('detail')
  if (this.checked) {
    for (const iterator of detail) {
      iterator.classList.remove('hidden')
    }
  } else {
    for (const iterator of detail) {
      iterator.classList.add('hidden')
    }
  }
});

/**
 * The function is called when the user clicks on the "Exit" button. The function removes the "hidden"
 * class from the "live" div and adds the "hidden" class to the "img_list" div
 */
function exitImgList() {
  // var live = document.getElementById('live');
  // live.classList.remove('hidden')
  var append1 = document.getElementById('img_list')//('img_gal')
  append1.setAttribute('style','width: 0')
  append1.classList.remove('uk-padding')
  // append1.classList.add('hidden_imglist')
  // append1.classList.remove('imglist')
}

/**
 * It sends a command to the Sattelanalyse server to show the mask of the JPEG image with the given
 * number
 * @param num - the number of the camera
 */
function showMask (num){
  sattelanalyse.send(`set jpeg ${num} mask show`)
}
/**
 * It sends a command to the Sattelanalyse server to hide the mask of the JPEG image with the given
 * number
 * @param num - the number of the jpeg you want to hide the mask on
 */
function hideMask (num){
  sattelanalyse.send(`set jpeg ${num} mask hide`)
}

$('document').ready(()=>{
    let comp = document.getElementsByClassName('switchery')
      comp[0].setAttribute('style','background-color: var(--primary);border-color: var(--primary);box-shadow: var(--primary) 0px 0px 0px 11px inset;transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;')
});

/**
 * `ClientInfo` is a function that takes a single parameter, `params`, and stores it in local storage
 * @param params - {
 */
function ClientInfo(params) {
  onsqlresult = getLog;
  saveToLocalStorage('client_info',JSON.stringify(params));
}
/**
 * It takes three arguments, sends a query to the database, and then creates a table with the results
 * of the query
 * @param {number}client_id - The client's ID
 * @param {string}name - The name of the client
 * @param {string}mail - The email address of the user.
 */
function info(client_id,name,fname,lname,mail,fc) {
  onsqlresult = ClientInfo
  sattelanalyse.send(`sql select * from sessions where client_id=${client_id}`);
  let inter = setInterval(()=> {
      saveToLocalStorage('client_fc',fc)
      saveToLocalStorage('client_name',name)
      saveToLocalStorage('client_mail',mail)
      saveToLocalStorage('client_id',client_id)
      saveToLocalStorage('client_forenames',fname)
      saveToLocalStorage('client_surename',lname)
      location.href = "/production/client.tcls"

      clearInterval(inter);
    }, 500);

}

/**
 * The function updates and stores product and label values in local storage based on user input.
 * @param {number}params - A parameter that determines which product field to update (either 1 or 2).
 * @param {HTMLBaseElement}x - The "x" parameter is a reference to the HTML element that triggered the function.
 * @param {number}field - The field parameter is used to determine whether the value being passed should be
 * assigned to the "product" or "label" field in the local storage object. If field is equal to 1, the
 * value is assigned to the "product" field, otherwise it is assigned to the "label" field
 */
function TextTo(params,x,field) {
  let pro1;
  if(params==1){
    if(field==1){
      document.getElementById('product1').value = x.nextElementSibling.value
      pro1 = getFromLocalStorage('product1') ? JSON.parse(getFromLocalStorage('product1')) : {};
      pro1.product = x.nextElementSibling.value
    } else{
      document.getElementById('product_label1').value = x.nextElementSibling.value
      pro1 = getFromLocalStorage('product1') ? JSON.parse(getFromLocalStorage('product1')) : {};
      pro1.label = x.nextElementSibling.value
    }
    saveToLocalStorage('product1',JSON.stringify(pro1))
  } else {
    if(field==1){
      document.getElementById('product2').value = x.nextElementSibling.value
      pro1 = getFromLocalStorage('product2') ? JSON.parse(getFromLocalStorage('product2')) : {};
      pro1.product = x.nextElementSibling.value
    } else{
      document.getElementById('product_label2').value = x.nextElementSibling.value
      pro1 = getFromLocalStorage('product2') ? JSON.parse(getFromLocalStorage('product2')) : {};
      pro1.label = x.nextElementSibling.value
    }
    saveToLocalStorage('product2',JSON.stringify(pro1))
  }
}

function setProduct1(params) {
  let pro = document.getElementById('product1')
  let label = document.getElementById('product_label1')
  let note = document.getElementById('notes1')
  let local = getFromLocalStorage('product1') ? JSON.parse(getFromLocalStorage('product1')) : {product:"",label:"",note:""}

  if(params.pro){
    pro.value = params.pro
    local.product = params.pro
  }

  if(params.label){
    label.value = params.label
    local.label = params.label
  }

  if(params.note){
    note.value = params.note
    local.note = params.note
  }
  saveToLocalStorage('product1',JSON.stringify(local))
}

/**
 * The function sets the values of product, label, and notes for a specific element with the ID
 * "product2".
 * @param params - The `params` parameter is an object that contains the following properties:
 */
function setProduct2(params) {
  let pro = document.getElementById('product2')
  let label = document.getElementById('product_label2')
  let note = document.getElementById('notes2')
  let local = getFromLocalStorage('product2') ? JSON.parse(getFromLocalStorage('product2')) : {product:"",label:"",note:""}
  
  if(params.pro){
    pro.value = params.pro
    local.product = params.pro
  }

  if(params.label){
    label.value = params.label
    local.label = params.label
  }

  if(params.note){
    note.value = params.note
    local.note = params.note
  }
  saveToLocalStorage('product2',JSON.stringify(local))
}

function DemoMode() {
  sattelanalyse.send(`demostreams`)
}

function StartDemo() {
  sattelanalyse.send(`democonnect ${$("input[type='radio'][name='demo']:checked").val()}`)
  //document.getElementsByClassName('nav_menu')[0].style.backgroundColor = "orange"
}

function StopDemo(){
  sattelanalyse.send(`demodisconnect`)
  //document.getElementsByClassName('nav_menu')[0].style.backgroundColor = "var(--secondary-text)"
}

function actitvate3DLive(){
  localStorage.setItem('get3d',1)
  sattelanalyse.send(`switch create_norm on`)
  sattelanalyse.send(`switch create_jpeg off`)
  UIkit.modal('#chart_modal_live').show();
}

function deaktivateNorm(){
  sattelanalyse.send(`switch create_norm off`)
  sattelanalyse.send(`switch create_jpeg on`)
}

function close3d_2 (){
  localStorage.removeItem('get3d')
  sattelanalyse.send(`switch create_norm on`)
  sattelanalyse.send(`switch create_jpeg on`)
}

function close3D() {
  close3d_2()
  UIkit.modal('#chart_modal_live').hide()
}

var chartDom = document.getElementById('chart-container');
//var chartDom1 = document.getElementById('chart-container1');
//var chartDom2 = document.getElementById('chart-container2');
var myChartX = echarts.init(chartDom);
//var myChartX1 = echarts.init(chartDom1);
//var myChartX2 = echarts.init(chartDom2);
var option;
var ColorRange = ['#00000000','#0000ff','#00ff00','#ffff00','#ff0000'];
var max = 254
var type = 'bar3D'
var alpha = 45
var beta = 0
//setView(alpha,beta,300)

function setView(x, y,distance) {
  alpah = x
  beta = y
  if(distance){
    myChartX.setOption({
      grid3D: {
        viewControl: {
          //autoRotate:true,
          distance:distance,
          alpha:alpha,
          beta:beta, //270
          center:{
            0:0,
            1:-50,
            2:0
          }
      }
      }
    });
  } else {
  myChartX.setOption({
    grid3D: {
      viewControl: {
        //autoRotate:true,
        alpha:alpha,
        beta:beta, //270
        center:{
          0:0,
          1:-50,
          2:0
        }
    }
    }
  });
}
}


function setChartType(params) {
  type = params
}

function DATA3D(data,myChart,num){


  var myChartX = myChart
  var initChart0 = false;
  var initChart1 = false;
  var initChart2 = false;

  var numRows = data.n_rows;
          var numCols = data.n_cols;
          var max = 0
              // Create an empty 2D array with the specified dimensions
          data2D = new Array(numRows);
          for (var i = 0; i < numRows; i++) {
              data2D[i] = new Array(numCols);
            }
            // Fill the 2D array with your data
            for (var i = 0; i < data.values.length; i++) {
              var row = Math.floor(i / numCols);
              var col = i % numCols;
                if(Number(data.values[i]) > max){
                  max = data.values[i]
                }
                data2D[row][col] = [col, row, data.values[i]];
            }
          //  console.log(data2D);
          var option;
      
          if(initChart0===false||initChart1===false||initChart2===false){
      
          //var ColorRange = ['#000000','#0000ff','#00ff00','#ffff00','#ff0000']
          var ColorRange = ['#9f9f9f', '#666666', '#333333', '#0000ff', '#0066cc', '#00cccc', '#00ffcc', '#00ff66', '#00ff00', '#66ff00', '#ccff00', '#ffff00', '#ffcc00', '#ff9933', '#ff6600', '#ff3300', '#ff0000', '#cc0000', '#990000', '#660000'];
      
          
          //$.getScript(
          //  '/production/js/chart/simplex-noise.js'
          //).done(() => {

          //});
          myChartX.setOption(
            (option = {
            backgroundColor: '#00000000',
            visualMap: {
                show: false, //true
                calculable: true,
                min: 0,
                max: 255,
                inRange: {
                    color: ColorRange,
                },
              },
              xAxis3D: {
                type: 'category', //category
                show:false,
                max:numCols,
                min:0
              },
              yAxis3D: {
                type: 'category', //category
                show:true,
                max: numRows,
                min:0
              },
              zAxis3D: {
                type: 'value',
                max: 255*2,
                min: 0
              },
              toolbox: { 
                show: true, 
                orient: 'vertical', 
                itemsize: 16,
                iconStyle: {
                    borderColor: '#5cbc40',
                    borderWidth: 1 ,
                },
                left:10,
                feature: {
                    saveAsImage: { 
                        show: true, 
                        name: `3DImage${getFromLocalStorage('client_name')}`, 
                        type: 'png',
                        pixelRatio:2 
                    }
                } 
              },
              grid3D: {
                boxWidth: numCols*10,
                boxDepth: numRows*10,
                axisLine: {
                  //show:false,
                  lineStyle: { color: '#99999900' }
                },
                splitLine: {
                  show:false
                },
                splitArea: {
                  show:false
                }, 
                axisPointer: {
                  lineStyle: { color: '#99999900' }
                },
                light: {
                    main: {
                      color: '#fff' ,
                      intensity: 1 ,
                      shadow: false ,
                      shadowQuality: 'medium' ,
                      alpha: 30 ,
                      beta: 30 ,
                    },
                    ambient: {                 
                      color: '#fff' ,
                      intensity: 0.2 ,
                    },
                },            
              },
              series: [
                {
                  type: type,//'bar3D',//line3D, bar3D,scatter3D,surface
                  data: data2D.flat(),
                  animation: true,
                  //animationEasingUpdate: "cubicOut" ,
                  shading: 'color',//color,lambert,realistic
                  label: {
                    fontSize: 16,
                    borderWidth: 1,
                    show:false
                  },
                  
                  emphasis: {
                    label: {
                      fontSize: 20,
                      color: '#00000000',
                      show: true,
                    },
                    itemStyle: {
                        color: '#000000'
                    }
                  }
                }
              ]
            })
          );
          
          if (option && typeof option === 'object') {
            myChartX.setOption(option);
          }
          if(num===0)
          initChart0 = true;
          if(num===1)
          initChart1 = true;
          if(num===1)
          initChart1 = true;

          window.addEventListener('resize', myChartX.resize);
      } else {
          myChartX.setOption((option = {
              series: [
                  {
                      data:data2D.flat(),
                  }
                ]
          }))
      }

}

myChartX.on('click',(e) => {
  // The listener will be called after echarts built-in event called,
  // rather than before them. That is, the listener is auto marked as 
  // `zrEventfulCallAtLast`
  console.log(e);
  
});


/**
 * The function calculates the center of pressure for the left side, right side, and globally based on
 * a matrix of intensity values.
 * @param matrix - The `matrix` parameter in the `calculateCenterOfPressure` function represents a 2D
 * matrix that is flattened into a 1D array. The elements of the matrix correspond to the intensity
 * values at different positions.
 * @param rows - The `rows` parameter in the `calculateCenterOfPressure` function represents the number
 * of rows in the matrix. It is used to iterate over the rows of the matrix while calculating the
 * center of pressure for different sections of the matrix.
 * @param cols - The `cols` parameter in the `calculateCenterOfPressure` function represents the number
 * of columns in the matrix. It is used to determine the width of the matrix and iterate over each
 * column while calculating the center of pressure.
 * @returns The function `calculateCenterOfPressure` returns an object containing the center of
 * pressure (CoP) for the left side, right side, and the global CoP. The object has the following
 * properties:
 */
function calculateCenterOfPressure(matrix, rows, cols) {
  let leftSumX = 0, leftSumY = 0, leftWeight = 0;
  let rightSumX = 0, rightSumY = 0, rightWeight = 0;
  let totalSumX = 0, totalSumY = 0, totalWeight = 0;

  for (let y = 0; y < rows; y++) {
      for (let x = 0; x < cols; x++) {
          const value = matrix[y * cols + x]; // Flattened array index
          if (value > 0) { // Check for non-zero intensity
              totalSumX += x * value; // Sum for global CoP
              totalSumY += y * value;
              totalWeight += value;

              if (x < cols / 2) {
                  // Left side
                  leftSumX += x * value;
                  leftSumY += y * value;
                  leftWeight += value;
              } else {
                  // Right side
                  rightSumX += x * value;
                  rightSumY += y * value;
                  rightWeight += value;
              }
          }
      }
  }

  // Calculate CoP for left and right sides
  const leftCoP = leftWeight > 0
      ? { x: leftSumX / leftWeight, y: leftSumY / leftWeight }
      : null;

  const rightCoP = rightWeight > 0
      ? { x: rightSumX / rightWeight, y: rightSumY / rightWeight }
      : null;

  // Calculate global CoP
  const globalCoP = totalWeight > 0
      ? { x: totalSumX / totalWeight, y: totalSumY / totalWeight }
      : null;

  return { leftCoP, rightCoP, globalCoP };
}

// Canvas setup
const canvas_cop = document.getElementById('pressureCanvas');
const parentDiv_cop = document.querySelector('.Frame-3');
canvas_cop.width = parentDiv_cop.clientWidth;
canvas_cop.height = parentDiv_cop.clientHeight;
const ctx_cop = canvas_cop.getContext('2d');


/**
 * The function `scaleCoP` scales a given point's coordinates based on the original and canvas
 * dimensions provided.
 * @param coP - The `coP` parameter represents the coordinates of a point on a canvas. It is an object
 * with `x` and `y` properties indicating the x and y coordinates of the point.
 * @param originalWidth - The `originalWidth` parameter represents the original width of the coordinate
 * point (coP) before scaling.
 * @param originalHeight - The `originalHeight` parameter represents the original height of the content
 * or image that you are scaling. This value is used in the calculation to determine the new position
 * of a point based on the scaling factor applied to the canvas.
 * @param canvasWidth - The `canvasWidth` parameter represents the width of the canvas where you want
 * to scale the coordinates of a point (`coP`). This function takes the original width and height of
 * the coordinate point (`coP`) and the dimensions of the canvas to calculate the scaled coordinates.
 * @param canvasHeight - The `canvasHeight` parameter represents the height of the canvas where you
 * want to scale the coordinates of a point (`coP`). This function takes the original coordinates
 * (`coP`) relative to an original width and height (`originalWidth` and `originalHeight`) and scales
 * them to fit within a new
 * @returns An object with properties `x` and `y` representing the scaled coordinates of the point
 * `coP` based on the original dimensions and the canvas dimensions provided.
 */
function scaleCoP(coP, originalWidth, originalHeight, canvasWidth, canvasHeight) {
  return {
      x: coP.x * (canvasWidth / originalWidth),
      y: coP.y * (canvasHeight / originalHeight)
  };
}

// Display options for CoPs
/* The above code is defining a JavaScript object named `displayOptions` with three properties:
`leftRight`, `global`, and `showTrail`. Each property is a boolean value indicating whether to show
specific elements in a display. The `leftRight` property is set to `false`, indicating not to show
left and right Centers of Pressure (CoPs). The `global` property is set to `true`, indicating to
show the global CoP. The `showTrail` property is set to `false`, indicating not to show point
trails. */
const displayOptions = {
  leftRight: false, // Show left and right CoPs
  global: true,    // Show global CoP
  showTrail: false  // Show point trails
};

// Function to set visibility of CoPs
/**
 * The function setCoPVisibility updates the display options for leftRight and global settings and logs
 * the updated display options.
 * @param leftRight - The `leftRight` parameter determines the visibility of the content on the left
 * and right sides of the screen. It could be a boolean value indicating whether to display content on
 * the left and right sides.
 * @param global - The `global` parameter in the `setCoPVisibility` function likely refers to a setting
 * that affects the visibility of an element or feature across the entire application or system. When
 * `global` is set to `true`, it means that the visibility setting will be applied universally,
 * affecting all instances or
 */
function setCoPVisibility(leftRight, global) {
  displayOptions.leftRight = leftRight;
  displayOptions.global = global;
  console.log("Display Options Updated:", displayOptions);
}

// Function to redraw the CoPs
// Arrays to store the trails
let leftTrail = [];
let rightTrail = [];
let globalTrail = [];

// Maximum length of the trail (optional)
const MAX_TRAIL_LENGTH = 20;

/**
 * The function `drawCoP` in JavaScript clears a canvas, draws trails and lines between left and right
 * Centers of Pressure (CoPs), and scales and draws a global CoP as a transparent circle with a border.
 * @param result - The `result` parameter in the `drawCoP` function likely contains data related to the
 * Center of Pressure (CoP), including the leftCoP, rightCoP, and globalCoP values. These values are
 * used to draw the CoP trails and lines on the canvas.
 * @param rows - The `rows` parameter in the `drawCoP` function represents the number of rows in the
 * grid where the CoP (Center of Pressure) data is being visualized. This parameter is used to help
 * scale and position the CoP data correctly within the canvas based on the grid dimensions.
 * @param cols - The `cols` parameter in the `drawCoP` function represents the number of columns in the
 * grid where the CoP (Center of Pressure) data is being visualized. It is used to help scale and
 * position the CoP data correctly within the canvas based on the grid dimensions.
 */
function drawCoP(result, rows, cols, canvas,parentDiv, show_all = false) {
  //const parentDiv = document.querySelector('.Frame-3'); // Übergeordnetes Div holen
  if (!parentDiv) {
      console.error("Div mit der Klasse 'Frame-3' nicht gefunden!");
      return;
  }

  // Passe die Canvas-Größe an die Größe des parentDiv an
  canvas.width = parentDiv.clientWidth;
  canvas.height = parentDiv.clientHeight;

  const ctx = canvas.getContext('2d'); // Kontext des Canvas holen
  const { leftCoP, rightCoP, globalCoP } = result; // Destructure der CoP-Daten

  ctx.clearRect(0, 0, canvas.width, canvas.height); // Canvas leeren

  // Trails zeichnen, wenn aktiviert oder `show_all` true ist
  if (displayOptions.showTrail || show_all) {
      drawTrail(leftTrail, "blue", ctx, canvas);
      drawTrail(rightTrail, "red", ctx, canvas);
      drawTrail(globalTrail, setting.center_color || "purple", ctx, canvas);
  }

  // Linie zwischen linken und rechten CoP zeichnen, wenn aktiviert oder `show_all` true ist
  if ((displayOptions.leftRight || show_all) && leftCoP && rightCoP) {
      const scaledLeft = scaleCoP(leftCoP, cols, rows, canvas.width, canvas.height);
      const scaledRight = scaleCoP(rightCoP, cols, rows, canvas.width, canvas.height);

      ctx.strokeStyle = setting.line_color || "gray"; // Linienfarbe
      ctx.lineWidth = 2; // Liniendicke
      ctx.beginPath();
      ctx.moveTo(scaledLeft.x, canvas.height - scaledLeft.y); // Y-Achse invertieren
      ctx.lineTo(scaledRight.x, canvas.height - scaledRight.y); // Y-Achse invertieren
      ctx.stroke();

      // Punkte zu den Trails hinzufügen
      leftTrail.push(scaledLeft);
      if (leftTrail.length > MAX_TRAIL_LENGTH) leftTrail.shift();

      rightTrail.push(scaledRight);
      if (rightTrail.length > MAX_TRAIL_LENGTH) rightTrail.shift();
  }

  // Globalen CoP als transparenten Kreis mit Rahmen zeichnen, wenn aktiviert oder `show_all` true ist
  if ((displayOptions.global || show_all) && globalCoP) {
      const scaledGlobal = scaleCoP(globalCoP, cols, rows, canvas.width, canvas.height);
      ctx.strokeStyle = setting.center_color || "purple";
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.arc(scaledGlobal.x, canvas.height - scaledGlobal.y, 10, 0, Math.PI * 2);
      ctx.stroke();

      // Punkt zum globalen Trail hinzufügen
      globalTrail.push(scaledGlobal);
      if (globalTrail.length > MAX_TRAIL_LENGTH) globalTrail.shift();
  }
}




// Function to draw a trail
/**
 * The function `drawTrail` is used to draw a trail using a specified color on a canvas by connecting a
 * series of points.
 * @param trail - The `trail` parameter is an array of points that represent the trail you want to draw
 * on the canvas. Each point should have an `x` and `y` coordinate, like this:
 * @param color - The `color` parameter in the `drawTrail` function is used to specify the color of the
 * trail that will be drawn on the canvas. You can pass a color value as a string to this parameter,
 * such as `"red"`, `"#00FF00"`, or `"rgba(255
 */
function drawTrail(trail, color) {
  ctx_cop.strokeStyle = color;
  ctx_cop.lineWidth = 1;
  ctx_cop.beginPath();
  for (let i = 0; i < trail.length; i++) {
      const point = trail[i];
      if (i === 0) {
          ctx_cop.moveTo(point.x, canvas_cop.height - point.y); // Invert Y-axis
      } else {
          ctx_cop.lineTo(point.x, canvas_cop.height - point.y); // Invert Y-axis
      }
  }
  ctx_cop.stroke();
}

// Function to reset the trail
/**
 * The function `resetTrail` resets three arrays and logs a message indicating that the trails have
 * been reset.
 */
function resetTrail() {
    leftTrail = [];
    rightTrail = [];
    globalTrail = [];
    console.log("Trails reset.");
}


/**
 * The function `toggleCoPVisibility` updates display options based on checkbox states and optionally
 * redraws the CoP data if needed.
 */
function toggleCoPVisibility() {
  const leftRightChecked = document.getElementById('copLeftRight').checked;
  const globalChecked = document.getElementById('copGlobal').checked;

  // Update display options based on checkbox states
  setCoPVisibility(leftRightChecked, globalChecked);

  // Optionally redraw immediately if needed
  //if (currentCoPResult) { // Ensure there is valid CoP data
  //    drawCoP(currentCoPResult, currentRows, currentCols);
  //}
}

/**
 * The function `toggleTrailVisibility` toggles the visibility of a trail based on the checked status
 * of an element with the id 'trailVisibility'.
 */
function toggleTrailVisibility() {
  const trailChecked = document.getElementById('trailVisibility').checked;
  displayOptions.showTrail = trailChecked;
  console.log("Trail visibility updated:", displayOptions.showTrail);
}

function drawHeatmap(matrix, rows, cols, canvas, parentDiv, gradient) {
  const ctx = canvas.getContext('2d');

  // Passe die Canvas-Größe an die Größe des parentDiv an
  canvas.width = parentDiv.clientWidth;
  canvas.height = parentDiv.clientHeight;

  const cellWidth = canvas.width / cols;
  const cellHeight = canvas.height / rows;

  function getColor(value, gradient) {
      const normalizedValue = value / 255; // Normalisiere Wert zwischen 0 und 1
      for (let i = 0; i < gradient.length - 1; i++) {
          const start = gradient[i];
          const end = gradient[i + 1];
          if (normalizedValue >= start.value && normalizedValue <= end.value) {
              // Interpolation zwischen den Farben
              const t = (normalizedValue - start.value) / (end.value - start.value);
              const startColor = start.color.match(/\d+/g).map(Number);
              const endColor = end.color.match(/\d+/g).map(Number);
              const r = Math.round(startColor[0] + t * (endColor[0] - startColor[0]));
              const g = Math.round(startColor[1] + t * (endColor[1] - startColor[1]));
              const b = Math.round(startColor[2] + t * (endColor[2] - startColor[2]));
              return `rgb(${r},${g},${b})`;
          }
      }
      return gradient[0].color; // Standardfarbe (z. B. Schwarz)
  }
  

  // Canvas leeren
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Heatmap zeichnen
  for (let y = 0; y < rows; y++) {
      for (let x = 0; x < cols; x++) {
          const value = matrix[y * cols + x]; // Matrixindex
          const color = getColor(value, gradient);
          ctx.fillStyle = color;
          // Zeichne die Zellen ohne Gitter:
          ctx.fillRect(
              Math.floor(x * cellWidth),       // Abrunden auf ganze Pixel
              Math.floor((rows - y - 1) * cellHeight), // Y invertieren und abrunden
              Math.ceil(cellWidth),           // Breite der Zelle
              Math.ceil(cellHeight)           // Höhe der Zelle
          );
      }
  }
}

function upscaleMatrix(matrix, rows, cols, newRows, newCols) {
  const scaledMatrix = new Array(newRows * newCols).fill(0); // Initialisiere die hochskalierte Matrix
  const scaleX = cols / newCols;
  const scaleY = rows / newRows;

  for (let y = 0; y < newRows; y++) {
    const origY = y * scaleY;
    const y1 = Math.floor(origY);
    const y2 = Math.min(y1 + 1, rows - 1);
    const ty = origY - y1; // Fraktionaler Anteil

    for (let x = 0; x < newCols; x++) {
      const origX = x * scaleX;
      const x1 = Math.floor(origX);
      const x2 = Math.min(x1 + 1, cols - 1);
      const tx = origX - x1; // Fraktionaler Anteil

      // Bilinear interpolation
      const q11 = matrix[y1 * cols + x1];
      const q21 = matrix[y1 * cols + x2];
      const q12 = matrix[y2 * cols + x1];
      const q22 = matrix[y2 * cols + x2];

      const value =
        (1 - tx) * (1 - ty) * q11 +
        tx * (1 - ty) * q21 +
        (1 - tx) * ty * q12 +
        tx * ty * q22;

      // Korrigiere mögliche Verschiebungen
      scaledMatrix[y * newCols + x] = value;
    }
  }

  return scaledMatrix;
}

function upscaleMatrixWithOffset(matrix, rows, cols, newRows, newCols, multiply) {
  const scaledMatrix = new Array(newRows * newCols).fill(0);
  const scaleX = cols / newCols;
  const scaleY = rows / newRows;
  const offset = Math.floor((multiply - 1) / 2); // Offset-Korrektur

  for (let y = 0; y < newRows; y++) {
    const origY = (y - offset) * scaleY;
    const y1 = Math.floor(origY);
    const y2 = Math.min(y1 + 1, rows - 1);
    const ty = origY - y1;

    for (let x = 0; x < newCols; x++) {
      const origX = (x - offset) * scaleX;
      const x1 = Math.floor(origX);
      const x2 = Math.min(x1 + 1, cols - 1);
      const tx = origX - x1;

      // Bilineare Interpolation
      const q11 = matrix[y1 * cols + x1];
      const q21 = matrix[y1 * cols + x2];
      const q12 = matrix[y2 * cols + x1];
      const q22 = matrix[y2 * cols + x2];

      const value =
        (1 - tx) * (1 - ty) * q11 +
        tx * (1 - ty) * q21 +
        (1 - tx) * ty * q12 +
        tx * ty * q22;

      scaledMatrix[y * newCols + x] = value;
    }
  }

  return scaledMatrix;
}




function getReducedGradient(contrastLevel) {
  // Definiere alle Gradienten
  const gradient1 = [
    { value: 0, color: 'rgb(0, 0, 0)' },   // Schwarz (Hintergrund)
    { value: 0.2, color: 'rgb(0, 255, 0)' }, // Dunkelblau
    { value: 0.3, color: 'rgb(0, 255, 0)' }, // Türkis
    { value: 0.4, color: 'rgb(0, 255, 0)' }, // Türkis/Grün
    { value: 0.5, color: 'rgb(255, 0, 0)' }, // Grün
    { value: 0.7, color: 'rgb(255, 0, 0)' }, // Gelb
    { value: 0.8, color: 'rgb(255, 0, 0)' }, // Orange
    { value: 1, color: 'rgb(255, 0, 0)' }   // Rot
  ];

  const gradient2 = [
    { value: 0, color: 'rgb(0, 0, 0)' },   // Schwarz (Hintergrund)
    { value: 0.2, color: 'rgb(0, 255, 255)' }, // Dunkelblau
    { value: 0.3, color: 'rgb(0, 255, 255)' }, // Türkis
    { value: 0.4, color: 'rgb(0, 255, 0)' }, // Türkis/Grün
    { value: 0.5, color: 'rgb(255, 255, 0)' }, // Grün
    { value: 0.7, color: 'rgb(255, 255, 0)' }, // Gelb
    { value: 0.8, color: 'rgb(255, 0, 0)' }, // Orange
    { value: 1, color: 'rgb(255, 0, 0)' }   // Rot
  ];

  const gradient3 = [
    { value: 0, color: 'rgb(0, 0, 0)' },   // Schwarz (Hintergrund)
    { value: 0.2, color: 'rgb(0, 0, 255)' }, // Dunkelblau
    { value: 0.3, color: 'rgb(0, 255, 255)' }, // Türkis
    { value: 0.4, color: 'rgb(0, 255, 0)' }, // Türkis/Grün
    { value: 0.5, color: 'rgb(255, 255, 0)' }, // Grün
    { value: 0.7, color: 'rgb(255, 255, 0)' }, // Gelb
    { value: 0.8, color: 'rgb(255, 165, 0)' }, // Orange
    { value: 1, color: 'rgb(255, 0, 0)' }   // Rot
  ];

  const fullGradient = [
      { value: 0, color: 'rgb(0, 0, 0)' },   // Schwarz (Hintergrund)
      { value: 0.2, color: 'rgb(0, 0, 255)' }, // Dunkelblau
      { value: 0.3, color: 'rgb(0, 255, 255)' }, // Türkis
      { value: 0.4, color: 'rgb(0, 255, 128)' }, // Türkis/Grün
      { value: 0.5, color: 'rgb(0, 255, 0)' }, // Grün
      { value: 0.7, color: 'rgb(255, 255, 0)' }, // Gelb
      { value: 0.8, color: 'rgb(255, 165, 0)' }, // Orange
      { value: 1, color: 'rgb(255, 0, 0)' }   // Rot
  ];

  // Wähle den passenden Gradient basierend auf dem Kontrastlevel
  switch (contrastLevel) {
      case 1: return gradient1;
      case 2: return gradient2;
      case 3: return gradient3;
      default: return fullGradient; // Standard: volle Palette
  }
}


function measure01(canvas) {
  let isDown = false;
  let startX = 0;
  let startY = 0;
  let endX = 0;
  let endY = 0;
  const ctx = canvas.getContext("2d");
  const lineColor = "red"; // Farbe für die Messlinien
  const textColor = "white"; // Farbe für die Textanzeige

  // Maus-Event: Startpunkt der Messung
  canvas.addEventListener("mousedown", (event) => {
    const rect = canvas.getBoundingClientRect();
    startX = event.clientX - rect.left;
    startY = event.clientY - rect.top;
    isDown = true;

    // Canvas leeren (alles löschen)
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  // Maus-Event: Linie zeichnen und Länge berechnen
  canvas.addEventListener("mousemove", (event) => {
    if (!isDown) return;

    // Mausposition
    const rect = canvas.getBoundingClientRect();
    endX = event.clientX - rect.left;
    endY = event.clientY - rect.top;

    // Canvas leeren und neue Linie zeichnen
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Linie zeichnen
    ctx.beginPath();
    ctx.moveTo(startX, startY);
    ctx.lineTo(endX, endY);
    ctx.strokeStyle = lineColor;
    ctx.lineWidth = 2;
    ctx.stroke();

    // Entfernung berechnen und Text mittig auf der Linie anzeigen
    const distance = calculateLineLength(startX, startY, endX, endY);
    const midX = (startX + endX) / 2;
    const midY = (startY + endY) / 2;

    // Zeichne den Text
    ctx.font = "14px Arial";
    ctx.fillStyle = textColor;
    ctx.fillText(`Distanz: ${distance} cm`, midX, midY);
  });

  // Maus-Event: Messung abschließen
  canvas.addEventListener("mouseup", () => {
    isDown = false;

    // Finale Linie und Text bleiben sichtbar
    const distance = calculateLineLength(startX, startY, endX, endY);
    const midX = (startX + endX) / 2;
    const midY = (startY + endY) / 2;

    // Linie und Text final zeichnen
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(startX, startY);
    ctx.lineTo(endX, endY);
    ctx.strokeStyle = lineColor;
    ctx.lineWidth = 2;
    ctx.stroke();

    ctx.font = "14px Arial";
    ctx.fillStyle = textColor;
    ctx.fillText(`Distanz: ${distance} cm`, midX, midY);
  });

  // Funktion zur Entfernungsmessung
  function calculateLineLength(x1, y1, x2, y2) {
    const linePixelsX = x2 - x1;
    const linePixelsY = y2 - y1;
    const pixelPerCmHorizontal = canvas.width / 16; // 16 Spalten
    const pixelPerCmVertical = canvas.height / 28; // 28 Reihen

    // Berechne die Gesamtdistanz in Pixeln
    const distanceInPixels = Math.sqrt(
      Math.pow(linePixelsX, 2) + Math.pow(linePixelsY, 2)
    );

    // Konvertiere Pixel in Zentimeter
    const distanceInCm = distanceInPixels / ((pixelPerCmHorizontal + pixelPerCmVertical) / 2);
    return distanceInCm.toFixed(2);
  }
}

$( document ).ready(function() {
  document.getElementById("set_comp").nextSibling.classList.add('custom_switch')
  document.getElementById("maskedit").nextSibling.style = "box-shadow: rgb(223, 223, 223) 0px 0px 0px 0px inset; border-color: rgb(223, 223, 223); background-color: rgb(255, 255, 255); transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s;"
  let comp = setInterval(() => {
    session(localStorage.getItem('session'))
    //sattelanalyse.send(`session ${local_sess}`)
    set_comp('on');
    localStorage.removeItem('session');
    clearInterval(comp);
  }, 1500);
  let fsc = document.getElementById('fsc');
  fsc.setAttribute('style','overflow:hidden;')
});
hide_mask();