Source: seatbone.js

var aLangKeys = new Object();
var devLangKeys = new Object();
var lang = getFromLocalStorage('lang');
var ska = false;

var data2D;

const httpsend = new XMLHttpRequest();
const setting = new Object();
setting.text_color = '#ffffff';
const cw = document.getElementsByClassName("ska")[0].offsetWidth;
var url_smartcube = getFromLocalStorage('smartcube') || location.host;

const script_host = location.origin;
const script_ws = script_host.replace('http','ws');

const apps= "sitzknochenabstand";
const script_apps= "satteldruckanalyse";
const script_websocket = new WebSocket(`${script_ws}/apps/${script_apps}`, ["soap", "wamp"]);

try {
  var sitzknochen = new WebSocket(`${script_ws}/apps/${apps}`, ["soap", "wamp"]);
} catch (error) {
    console.error('ws_ska',error);
}

const ska_new = document.getElementById('ska_new')
const canvas_cop = document.getElementById('ska_new_cop')
const parentDiv = document.querySelector('.parent');
let multiply = 7;
let contrastLevel = 4;; // Beispielwert: 2.5 für hohen Kontrast, 0.8 für niedrigen Kontrast

canvas_cop.width = parentDiv.clientWidth;
canvas_cop.height = parentDiv.clientHeight;
const ctx_cop = canvas_cop.getContext('2d');
 

var script_Data= new Object();
var script_setting = new Object();

var back = document.getElementsByClassName('main')[0];

var dom = document.getElementById('chart-container2');
var myChartX = echarts.init(dom, 'dark', {
  renderer: 'canvas',
  useDirtyRect: false
});

if(getFromLocalStorage("url_logo")){
  let img = document.getElementById('logo')
  img.src = getFromLocalStorage("url_logo")
}

script_websocket.onopen = (e)=>{
  console.log('websocket open');
  script_websocket.send('get clientsettings')
}

script_websocket.onmessage = (e)=> {
  try {
    script_Data = JSON.parse(e.data);
  } catch (error) {
    getError(error)
  }

  if(script_Data.wsevent ==="clientsettings"){
    script_setting = script_Data.clientsettings
    //console.log(script_setting);
    if(script_setting.text_color){
      setting.text_color = script_setting.text_color
    }
    if(script_setting.LoginMail != '' && script_setting.LoginPass != ''){
      let portal = document.getElementById('haendlerportal')
      portal.classList.remove('hidden')
    }
  }
}

const canvas_ska = new fabric.Canvas("ska_img");
createCanvas(canvas_ska);
setImage(canvas_ska,`/production/images/ska.png`);

let cm;
let inch;
var vsum = 0;

translatejs()

OpenMod('disconected')

/**
 * The function `saveToLocalStorage` saves a key-value pair to the browser's local storage.
 * @param key - The `key` parameter is a string that represents the name under which the `value` will
 * be stored in the browser's local storage.
 * @param value - The `value` parameter in the `saveToLocalStorage` function is the data that you want
 * to save to the local storage. It could be a string, number, object, array, or any other type of data
 * that you want to store locally in the browser.
 */
function saveToLocalStorage(key, value) {
  localStorage.setItem(key, value);
}

/**
 * The function `getFromLocalStorage` retrieves a value from the browser's local storage based on a
 * specified key.
 * @param key - The `key` parameter is a string that represents the key of the item you want to
 * retrieve from the localStorage.
 * @returns The value stored in the localStorage with the specified key is being returned.
 */
function getFromLocalStorage(key) {
  return localStorage.getItem(key);
}

function clearFromLocalStorage(array) {
  if (!Array.isArray(array)) {
    console.error('Das übergebene Argument ist kein Array.');
    return;
  }
  
  array.forEach(key => {
    if (getFromLocalStorage(key) !== null) {
      localStorage.removeItem(key);
      console.log(`'${key}' wurde aus dem localStorage entfernt.`);
    } else {
      console.warn(`'${key}' ist nicht im localStorage vorhanden.`);
    }
  });
}


try {
var ws_ska = new WebSocket(`ws://${url_smartcube}/apps/${apps}`, ["soap", "wamp"]);
} catch (error) {
}

ws_ska.onopen = (e)=>{
  //  sitzknochen.send(`session restart ${sessionID}`)
  //  sitzknochen.send(`analysis ["sitbones","anamnesis","x1"]`)
  ws_ska.send('switch create_norm on')
}

ws_ska.onmessage = (e) =>{
    translatejs()
    let data = JSON.parse(e.data)

    console.log("ws_ska: ",data);

    if(data.v_sum == 0.0){
      vsum = 0;
    }
    
    if(data.state == 'active'){
        OpenMod('connected')
        document.getElementById('glow').classList.add('glow')
    }
    if(data.wsevent === 'hockerbild'){
      console.log("draw image");
      let img = `http://${url_smartcube}/hockerbild?rnd=${(new Date).getTime()}`;
      setImage(canvas_ska, img);

    }
    if(data.wsevent === 'sitzknochenabstand' ){
      //if(vsum == 0){
        vsum = 1
        var inter = setInterval(function () {
          draw_cross(canvas_ska,[(data.schwerpunkt1_x+0.5) * (cw / 28) , (cw/1.75) - (data.schwerpunkt1_y+0.5) * (cw / 28)]);
          draw_cross(canvas_ska,[(data.schwerpunkt2_x+0.5)* (cw / 28) , (cw/1.75) - (data.schwerpunkt2_y+0.5) * (cw / 28)]);
          console.log(lineDistance([data.schwerpunkt1_x * (cw / 28) , (cw/1.75) - data.schwerpunkt1_y * (cw / 28)],[data.schwerpunkt2_x * (cw / 28) , (cw/1.75) - data.schwerpunkt2_y * (cw / 28)])/(cw/28));
          cm_inch(data.sitzknochenabstand)
          document.getElementById('val').innerHTML = `${cm} / ${inch}`
          vsum++
          clearInterval(inter);
        }, 1000);

      //}
    }

    if(data.wsevent === "hockernorm"){
      console.log('hockernorm data: ',data);
      
      if (data.imagetype === 'ska_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, ska_new, parentDiv, 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);
    }


      let d = document.getElementById('button3d')
      d.classList.remove('hidden')
  
      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;
      var initChart = false;
  
      if(initChart===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(function () {
        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: {
                  //magicType: {
                  //    type: ["line3D", "bar3D","scatter3D","surface"]
                  //}, 
                  //dataZoom: { show: true }, 
                  //dataView: { show: true },
                  saveAsImage: { 
                      show: true, 
                      name: `Sitzknochen`, 
                      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' }
              },
              viewControl: {
                  distance:250,
                  alpha:45,
                  beta:0, //270
                  center:{
                    0:0,
                    1:-50,
                    2:0
                  }
              },
              light: {
                  main: {
                    color: '#fff' ,
                    intensity: 1 ,
                    shadow: false ,
                    shadowQuality: 'medium' ,
                    alpha: 30 ,
                    beta: 30 ,
                  },
                  ambient: {                 
                    color: '#fff' ,
                    intensity: 0.2 ,
                  },
              },            
            },
            series: [
              {
                type: getValue(),//line3D, bar3D,scatter3D,surface
                data: data2D.flat(),
                shading: 'lambert',//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);
      }
      initChart = true;
      window.addEventListener('resize', myChartX.resize);
  } else {
      myChartX.setOption((option = {
          series: [
              {
                  data:data2D.flat(),
              }
            ]
      }))
  }
  
  }
}

sitzknochen.onopen = (e)=>{
  //  sitzknochen.send(`session restart ${sessionID}`)
  //  sitzknochen.send(`analysis ["sitbones","anamnesis","x1"]`)
  sendMatte('switch create_norm on')
}
var active = false
//sitzknochen.onmessage = (e) =>{
//  translatejs()
//  let data = JSON.parse(e.data)

//  console.log(data);

//  if(data.v_sum == 0.0){
//    vsum = 0;
//  }
  
//  if(data.wsevent == 'ttystate' && data.state == 'active'){
//      OpenMod('connected')
//      document.getElementById('glow').classList.add('glow')
//      active = true
//  }
//  if(data.wsevent === 'hockerbild'&&active==true){
//    console.log("draw image");
//    //let img = `${script_host}/hockerbild?rnd=${(new Date).getTime()}`;
//    setImage(canvas_ska, `${script_host}/hockerbild?rnd=${(new Date).getTime()}`);
//    //setImage(canvas_ska, img);

//  }
//  if(data.wsevent === 'sitzknochenabstand'){
//    //if(vsum == 0){
//      vsum = 1
//      var inter = setInterval(function () {
//        draw_cross(canvas_ska,[(data.schwerpunkt1_x+0.5) * (cw / 28) , (cw/1.75) - (data.schwerpunkt1_y+0.5) * (cw / 28)]);
//        draw_cross(canvas_ska,[(data.schwerpunkt2_x+0.5)* (cw / 28) , (cw/1.75) - (data.schwerpunkt2_y+0.5) * (cw / 28)]);
//        console.log(lineDistance([data.schwerpunkt1_x * (cw / 28) , (cw/1.75) - data.schwerpunkt1_y * (cw / 28)],[data.schwerpunkt2_x * (cw / 28) , (cw/1.75) - data.schwerpunkt2_y * (cw / 28)])/(cw/28));
//        cm_inch(data.sitzknochenabstand)
//        document.getElementById('val').innerHTML = `${cm} / ${inch}`
//        vsum++
//        clearInterval(inter);
//      }, 1000);

//    //}
//  }

//  if(data.wsevent === "hockernorm"){
//    let d = document.getElementById('button3d')
//    d.classList.remove('hidden')

//    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;
//    var initChart = false;

//    if(initChart===false){

//    //var ColorRange = ['#9f9f9f','#0000ff','#00ff00','#ffff00','#ff0000']
//    //var ColorRange = ['#9f9f9f', '#0000ff', '#0099ff', '#00ccff', '#00ffcc', '#00ff00', '#ccff00', '#ffff00', '#ffcc00', '#ff9900', '#ff6600', '#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(function () {
//      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:false,
//            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: {
//                //magicType: {
//                    //show:true,
//                    //type: ['line3D', 'bar3D','scatter3D','surface'] do not work with 3D elements
//                //}, 
//                //dataZoom: { show: true }, 
//                //dataView: { show: true },
//                saveAsImage: { 
//                    show: true, 
//                    name: `Sitzknochen`, 
//                    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' }
//            },
//            viewControl: {
//                distance:250,
//                alpha:45,
//                beta:0, //270
//                center:{
//                  0:0,
//                  1:-50,
//                  2:0
//                }
//            },
//            light: {
//                main: {
//                  color: '#fff' ,
//                  intensity: 1 ,
//                  shadow: false ,
//                  shadowQuality: 'medium' ,
//                  alpha: 45 ,
//                  beta: 0 ,
//                },
//                ambient: {                 
//                  color: '#fff' ,
//                  intensity: 0.2 ,
//                },
//            },            
//          },
//          series: [
//            {
//              type: getValue(),//line3D, bar3D,scatter3D,surface
//              data: data2D.flat(),
//              shading: 'realistic',//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);
//    }
//    initChart = true;
//    window.addEventListener('resize', myChartX.resize);
//} else {
//    myChartX.setOption((option = {
//        series: [
//            {
//                data:data2D.flat(),
//            }
//          ]
//    }))
//}

//}

//}

// Funktion zum Verarbeiten eingehender Nachrichten
function handleMessage(e) {
  translatejs();
  const data = JSON.parse(e.data);
  console.log(data);

  if (data.v_sum === 0.0) {
    vsum = 0;
  }

  if (data.wsevent === 'ttystate' && data.state === 'active') {
    handleActiveState();
  }

  if (data.wsevent === 'hockerbild' && active) {
    console.log("draw image");
    const imgURL = `${script_host}/hockerbild?rnd=${new Date().getTime()}`;
    setImage(canvas_ska, imgURL);
  }

  if (data.wsevent === 'sitzknochenabstand') {
    handleSitzknochenabstand(data);
  }

  if (data.wsevent === "hockernorm") {
    handleHockernorm(data);
  }
}

// Funktion zur Behandlung des aktiven Zustands
function handleActiveState() {
  OpenMod('connected');
  document.getElementById('glow').classList.add('glow');
  active = true;
}

// Funktion zur Behandlung von sitzknochenabstand-Ereignissen
function handleSitzknochenabstand(data) {
  vsum = 1;
  const inter = setInterval(() => {
    draw_cross(canvas_ska, [(data.schwerpunkt1_x + 0.5) * (cw / 28), (cw / 1.75) - (data.schwerpunkt1_y + 0.5) * (cw / 28)]);
    draw_cross(canvas_ska, [(data.schwerpunkt2_x + 0.5) * (cw / 28), (cw / 1.75) - (data.schwerpunkt2_y + 0.5) * (cw / 28)]);
    console.log(lineDistance([data.schwerpunkt1_x * (cw / 28), (cw / 1.75) - data.schwerpunkt1_y * (cw / 28)], [data.schwerpunkt2_x * (cw / 28), (cw / 1.75) - data.schwerpunkt2_y * (cw / 28)]) / (cw / 28));
    cm_inch(data.sitzknochenabstand);
    document.getElementById('val').innerHTML = `${cm} / ${inch}`;
    vsum++;
    clearInterval(inter);
  }, 1000);
}

// Funktion zur Behandlung von hockernorm-Ereignissen
function handleHockernorm(data) {
  const d = document.getElementById('button3d');
  d.classList.remove('hidden');
  const numRows = data.n_rows;
  const numCols = data.n_cols;
  let max = 0;
  const data2D = [];

  for (let i = 0; i < numRows; i++) {
    data2D[i] = new Array(numCols);
  }

  for (let i = 0; i < data.values.length; i++) {
    const row = Math.floor(i / numCols);
    const col = i % numCols;
    if (Number(data.values[i]) > max) {
      max = data.values[i];
    }
    data2D[row][col] = [col, row, data.values[i]];
  }

  const option = {
    // Optionen für das Diagramm
  };

  if (!initChart) {
    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(function () {
      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:false,
            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: {
                //magicType: {
                    //show:true,
                    //type: ['line3D', 'bar3D','scatter3D','surface'] do not work with 3D elements
                //}, 
                //dataZoom: { show: true }, 
                //dataView: { show: true },
                saveAsImage: { 
                    show: true, 
                    name: `Sitzknochen`, 
                    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' }
            },
            viewControl: {
                distance:250,
                alpha:45,
                beta:0, //270
                center:{
                  0:0,
                  1:-50,
                  2:0
                }
            },
            light: {
                main: {
                  color: '#fff' ,
                  intensity: 1 ,
                  shadow: false ,
                  shadowQuality: 'medium' ,
                  alpha: 45 ,
                  beta: 0 ,
                },
                ambient: {                 
                  color: '#fff' ,
                  intensity: 0.2 ,
                },
            },            
          },
          series: [
            {
              type: getValue(),//line3D, bar3D,scatter3D,surface
              data: data2D.flat(),
              shading: 'realistic',//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);
    }
    window.addEventListener('resize', myChartX.resize);
    initChart = true;
  } else {
    myChartX.setOption((option = {
      series: [
          {
              data:data2D.flat(),
          }
        ]
  }))
  }
}

// Hinzufügen des Event Listeners für eingehende Nachrichten
sitzknochen.onmessage = handleMessage;


/**
 * The function `getValue` retrieves the selected value from a dropdown menu with the id "view3d".
 * @returns The function `getValue()` is returning the value of the selected option in the "view3d"
 * select element.
 */
function getValue() {
  var selectElement = document.getElementById("view3d");
  var selectedOption = selectElement.options[selectElement.selectedIndex];
  var selectedValue = selectedOption.value;
  
  return selectedValue
}

/**
 * The function calculates the distance between two points in a two-dimensional space.
 * @param p1 - The `p1` parameter represents the coordinates of the first point in the form of an array
 * `[x1, y1]`.
 * @param p2 - The `p2` parameter in the `lineDistance` function represents the coordinates of the
 * second point in a two-dimensional space. It is typically an array with two elements, where `p2[0]`
 * is the x-coordinate and `p2[1]` is the y-coordinate of
 * @returns The function `lineDistance` calculates the Euclidean distance between two points `p1` and
 * `p2` in a 2D plane and returns the distance as a numeric value.
 */
function lineDistance(p1, p2) {
  return Math.hypot(p2[0] - p1[0], p2[1] - p1[1])
}

/**
 * The function `draw_cross` draws a cross shape at a specified position on a canvas element.
 * @param ele - The `ele` parameter is the HTML canvas element on which you want to draw the cross. You
 * can pass the canvas element to this function so that it can draw the cross on that canvas.
 * @param pos - The `pos` parameter in the `draw_cross` function represents the position where the
 * cross will be drawn on the canvas. It is an array containing the x and y coordinates of the center
 * point of the cross. The function draws a cross shape centered at this position on the canvas.
 */
function draw_cross(ele,pos) {
  console.log(pos);
  let c = ele.getContext('2d')
  c.lineWidth = 5;
  c.strokeStyle = setting.text_color;

  c.beginPath()
  c.moveTo(pos[0],pos[1])
  c.lineTo(pos[0],pos[1]+10)
  c.stroke();

  c.beginPath()
  c.moveTo(pos[0],pos[1])
  c.lineTo(pos[0],pos[1]-10)
  c.stroke();

  c.beginPath()
  c.moveTo(pos[0],pos[1])
  c.lineTo(pos[0]+10,pos[1])
  c.stroke();
  
  c.beginPath()
  c.moveTo(pos[0],pos[1])
  c.lineTo(pos[0]-10,pos[1])
  c.stroke();
}

/**
 * The function opens a UIkit modal with the ID specified in the parameter.
 * @param params - The parameter `params` is a string that represents the ID of the modal that needs to
 * be opened. The function `OpenMod` takes this parameter and uses it to show the corresponding modal
 * using the UIkit framework.
 */
function OpenMod(params) {
  UIkit.modal(`#modal-${params}`).show();
}


/**
 * This function sends an HTTP GET request to store an image in a database and opens a confirmation
 * modal.
 * @returns There is no return statement in this code snippet, so nothing is being returned explicitly.
 * However, the function may return undefined implicitly if it reaches the end without encountering a
 * return statement.
 */
function SendSkImg() {
  if(ska === true){
  let mail = document.getElementById("UserMail").value;
  let url = `http://${url_smartcube}/storedbld`;

  if (mail == "") {
    if (!confirm("Das Druckbild wird anonym gespeichert.")) return;
  } else {
    url += `?email=${encodeURI(mail)}`;
  }

  httpsend.open("GET", url, true);
  httpsend.send();

  document.getElementById('UserMail').value = ""
  document.getElementById('val').innerHTML = `0 cm / 0 inch`
  setImage(canvas_ska, `/production/images/ska.png`);
  UIkit.modal(`#modal-mail`).hide();
  //OpenMod("confirm");
  ska = false
  }
}

$('#UserMail').on("keyup", (e) => {
  if (e.keyCode == 13 && document.getElementById('UserMail').value) {
    SendSkImg()
  }
});

/**
 * This function attempts to fetch and parse a JSON file located at "/speach/speach.json?v=1" and then
 * passes the resulting data to another function called "_Translate".
 */
function translatejs() {
    try {
      fetch("/production/json/lang.json", {
        mode: "no-cors",
      })
        .then((res) => res.json())
        .then((data) => (_Translate(data)));
    } catch (error) {
      console.log(error);
    }
}


/**
 * The `_Translate` function iterates over HTML elements with specific attributes and sets their
 * content to translated values based on a parameter object, while also storing the translations in
 * local storage.
 * @param params - The `params` parameter is an object that contains translations for different keys in
 * different languages. The keys in the object correspond to the keys used in the HTML document, and
 * the values are objects that contain translations for each language. For example, `params` might look
 * like this:
 */
function _Translate(params) {
  aLangKeys = params;
  /* This code block is iterating over all elements in the HTML document that have a `key-place`
  attribute and setting their `placeholder` attribute to a translated value based on the `params`
  object passed as a parameter to the `_Translate` function. The translated value is determined by
  looking up the corresponding key in the `params` object using the current language (`lang`) as the
  index. The translated value is also stored in the `devLangKeys` object and in the browser's local
  storage. */
  for (const key3 in document.querySelectorAll("[key-place]")) {
    const element3 = document.querySelectorAll("[key-place]")[key3];
    if (element3.tagName) {
      let ele = element3.getAttribute("key-place");
      element3.setAttribute("placeholder", params[lang][ele]);
      devLangKeys[element3.getAttribute("key-place")] =
        element3.getAttribute("placeholder") == "undefined"
          ? element3.getAttribute("key-place")
          : element3.getAttribute("placeholder");
      saveToLocalStorage("devLang", JSON.stringify(devLangKeys));
    }
  }
  /* This code block is iterating over all elements in the HTML document that have a `key-title`
  attribute and setting their `title` attribute to a translated value based on the `params` object
  passed as a parameter to the `_Translate` function. The translated value is determined by looking
  up the corresponding key in the `params` object using the current language (`lang`) as the index.
  The translated value is also stored in the `devLangKeys` object and in the browser's local
  storage. */
  for (const key2 in document.querySelectorAll("[key-title]")) {
    const element2 = document.querySelectorAll("[key-title]")[key2];
    if (element2.tagName) {
      let ele = element2.getAttribute("key-title");
      element2.setAttribute("title", params[lang][ele]);
      devLangKeys[element2.getAttribute("key-title")] =
        element2.getAttribute("title") == "undefined"
          ? element2.getAttribute("key-title")
          : element2.getAttribute("title");
      saveToLocalStorage("devLang", JSON.stringify(devLangKeys));
    }
  }
  /* This code block is iterating over all elements in the HTML document that have a `key` attribute
  and setting their `innerHTML` to a translated value based on the `params` object passed as a
  parameter to the `_Translate` function. The translated value is determined by looking up the
  corresponding key in the `params` object using the current language (`lang`) as the index. The
  translated value is also stored in the `devLangKeys` object and in the browser's local storage. */
  for (const key in document.querySelectorAll("[key]")) {
    const element = document.querySelectorAll("[key]")[key];
    if (element.innerHTML) {
      element.innerHTML = params[lang][element.getAttribute("key")];
      devLangKeys[element.getAttribute("key")] =
        element.innerHTML == "undefined"
          ? element.getAttribute("key")
          : element.innerHTML;
      saveToLocalStorage("devLang", JSON.stringify(devLangKeys));
    }
  }
}

/**
 * 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) {
  fabric.Image.fromURL(img, (oImg) => {
    oImg.scaleToWidth(cw);
    oImg.hasControls = false;
    oImg.set("selectable", false);
    params.add(oImg);
  });
}

/**
 * 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(cw/1.75);
  params.setWidth(cw);
}

/**
 * The function converts a measurement in centimeters to inches.
 * @param params - The parameter "params" in the given function represents the length in centimeters
 * that needs to be converted to inches.
 */
function cm_inch(params) {
  cm = `${params.toFixed(2)} cm`;
  inch = params / 2.54;
  inch = `${inch.toFixed(2)} inch`;
  ska = true;
}

var elem = document.documentElement;
var fullScreen = false

function Vollbild() {
    if (fullScreen) {
        closeFullscreen()
        }
    if (!fullScreen) {
        openFullscreen()
        }
    }

function openFullscreen() {
    if (elem.requestFullscreen) {
        elem.requestFullscreen();
        } 
    else if (elem.mozRequestFullScreen) { /* Firefox */
        elem.mozRequestFullScreen();
        } 
    else if (elem.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
        elem.webkitRequestFullscreen();
        } 
    else if (elem.msRequestFullscreen) { /* IE/Edge */
        elem.msRequestFullscreen();
        }
        fullScreen = true
    }

function closeFullscreen() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
        } 
    else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
        } 
    else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
        } 
    else if (document.msExitFullscreen) {
        document.msExitFullscreen();
        }
        fullScreen=false
}

const main_ele = document.getElementsByClassName('mode')
const logo = document.getElementById('logo')
function ChangeColor() {
for (const i of main_ele) {
  if (i.classList.contains('lightmode')) {
    i.classList.remove('lightmode')
    i.classList.add('darkmode')
    //logo.setAttribute('src','/production/images/Logo-mit-Schriftzug-invertiert.png')
  } else{
    i.classList.remove('darkmode')
    i.classList.add('lightmode')
    //logo.setAttribute('src','/production/images/Logo-mit-Schriftzug.png')
  }
}


}

/**
 * The function takes a parameter, which is the name of the page you want to link to, and then it
 * changes the location of the current page to the page you want to link to
 * @param params - The name of the parameter you want to pass to the function.
 */
function LinkTo(params) {
  location.href = `/production/${params}`
  saveToLocalStorage('force',false)
}

function haendler_Login() {
location.origin = "https://www.dashaendlerportal.de"
window.open(
  `https://www.dashaendlerportal.de/production/login.tcl?email=${script_setting.LoginMail}&passwd=${script_setting.LoginPass}&login=`,
  '_blank' // <- This is what makes it open in a new window.
);
}

function loginNew() {

}

/**
 * The function "sendMatte" sends parameters to the "sitzknochen" object.
 * @param parameters - I'm sorry, but the code snippet you provided doesn't include any information
 * about the parameters that are expected by the `sendMatte` function. Can you please provide more
 * context or code so I can better understand what the function does and what parameters it expects?
 */
function sendMatte(parameters) {
  sitzknochen.send(parameters)
}

function show3d() {
  document.getElementById('chart-container2').classList.toggle('hidden')
  document.getElementById('glow').classList.toggle('hidden')
  document.getElementById('head').classList.toggle('hidden')
}


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 };
}

function scaleCoP(coP, originalWidth, originalHeight, canvasWidth, canvasHeight) {
  return {
      x: coP.x * (canvasWidth / originalWidth),
      y: coP.y * (canvasHeight / originalHeight)
  };
}

const displayOptions = {
  leftRight: true, // Show left and right CoPs
  global: true,    // Show global CoP
  showTrail: false  // Show point trails
};

function setCoPVisibility(leftRight, global) {
  displayOptions.leftRight = leftRight;
  displayOptions.global = global;
  console.log("Display Options Updated:", displayOptions);
}


let leftTrail = [];
let rightTrail = [];
let globalTrail = [];

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

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 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 resetTrail() {
    leftTrail = [];
    rightTrail = [];
    globalTrail = [];
    console.log("Trails reset.");
}


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);
  //}
}

function toggleTrailVisibility() {
  const trailChecked = document.getElementById('trailVisibility').checked;
  displayOptions.showTrail = trailChecked;
  console.log("Trail visibility updated:", displayOptions.showTrail);
}


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 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
          );
      }
  }
}

$(() => {
    translatejs();
});