October 22, 2024
Chicago 12, Melborne City, USA
jQuery

how to adjust draggableElement to have correct x and y position


I have implemented chart js to plot a two curve indicated by red and blue line. I want to add a slider (black vertical line) so that it remains always within two curves and user can move it left and right of the plot. when users slides it left or right, it would adjust the height itself. So taking the x and y value of lower plot and setting height by subtracting y1 of first plot and y2 of second plot, it behaves as expected. Here is my code,

    // Initialize the draggable line
    $(function() {
      $("#draggable").draggable({
        axis: "x",
        containment: "#myChart",
        drag: function(event, ui) {
          const canvas = document.getElementById('myChart');
          const ctx = canvas.getContext('2d');
          const rect = canvas.getBoundingClientRect();
          const chartLeft = rect.left;
          
          const xPos = ui.position.left; // Position of the draggable line
          const xValue = myChart.scales.x.getValueForPixel(xPos); // X value on the chart

          // Find the nearest points on the datasets
          const pYValue = getYValueAtX(xValue, myChart.data.datasets[0].data);
          const sYValue = getYValueAtX(xValue, myChart.data.datasets[1].data);

          const difference = pYValue && sYValue ? (pYValue - sYValue) : null;

          // Update the tooltip with the current x, p, and s values
          const tooltip = document.getElementById('tooltip');
          tooltip.innerHTML = `X: ${xValue.toFixed(2)}<br>P: ${pYValue ? pYValue.toFixed(2) : 'N/A'}<br>S: ${sYValue ? sYValue.toFixed(2) : 'N/A'}<br>Difference: ${difference ? difference.toFixed(2) : 'N/A'}`;
          tooltip.style.display = 'block';
          tooltip.style.left = `${xPos + chartLeft + 10}px`;
          tooltip.style.top = `${rect.top + 10}px`;


    const xPixelPos = myChart.scales.x.getPixelForValue(xValue); // Get pixel for xValue
    const yPixelPos = myChart.scales.y.getPixelForValue(pYValue); // Get pixel for sYValue

    const y1PixelPos = myChart.scales.y.getPixelForValue(sYValue); // Get pixel for sYValue


    const height = Math.abs(yPixelPos - y1PixelPos);

    const blackLine = document.getElementById('draggable');
    blackLine.style.left = `${xPixelPos}px`; // Set the x position of the div
    blackLine.style.top = `${yPixelPos}px`;
    blackLine.style.height = `${height}px`; 

    console.log("xpixel:", xPixelPos, "ypixel:", yPixelPos, "y1pixel:", y1PixelPos, "height:", height);


draggableElement.style.height = `${newHeight}px`; // Set height



        }
      });
    });

    // Helper function to find Y value for a given X in the dataset
    function getYValueAtX(x, data) {
      // Find the nearest point in the data for the given x
      const point = data.find(p => p.x >= x);
      return point ? point.y : null;
    }


function interpolateData(data) {
  // Create arrays to store the new interpolated p and s values
  let interpolatedData = [];
  
  for (let i = 0; i < data.length; i++) {
    const currentPoint = data[i];
    const nextPoint = data[i + 1];

    // Check if "p" or "s" is missing and interpolate if necessary
    if (currentPoint.p === "" && nextPoint) {
      // Linear interpolation for 'p'
      const prevPoint = data[i - 1];
      if (prevPoint && nextPoint.p !== "") {
        currentPoint.p = prevPoint.p + ((nextPoint.x - prevPoint.x) * (nextPoint.p - prevPoint.p)) / (nextPoint.x - prevPoint.x);
      }
    }

    if (currentPoint.s === "" && nextPoint) {
      // Linear interpolation for 's'
      const prevPoint = data[i - 1];
      if (prevPoint && nextPoint.s !== "") {
        currentPoint.s = prevPoint.s + ((nextPoint.x - prevPoint.x) * (nextPoint.s - prevPoint.s)) / (nextPoint.x - prevPoint.x);
      }
    }

    // Push the currentPoint to the interpolatedData
    interpolatedData.push(currentPoint);
  }

  return interpolatedData;
}


    // AJAX function to fetch JSON data
    function fetchJSONFile(filePath, callback) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', filePath, true);
      xhr.responseType="json";
      xhr.onload = function() {
        if (xhr.status === 200) {
      const interpolatedData = interpolateData(xhr.response);
      callback(interpolatedData);
        } else {
          console.error('Failed to load JSON file.');
        }
      };
      xhr.send();
    }

    // Callback to process the data and plot the chart
    function plotChart(jsonData) {
      const pData = jsonData
        .filter(item => item.p !== "")
        .map(item => ({
          x: item.x,
          y: item.p
        }));
      const sData = jsonData
        .filter(item => item.s !== "")
        .map(item => ({
          x: item.x,
          y: item.s
        }));

      // Chart.js configuration
      const ctx = document.getElementById('myChart').getContext('2d');
      myChart = new Chart(ctx, {
        type: 'line',
        data: {
          datasets: [
            {
              label: 'p Values',
              data: pData,
              borderColor: 'blue',
              fill: false,
              tension: 0.1,
              pointRadius: 0,
              showLine: true
            },
            {
              label: 's Values',
              data: sData,
              borderColor: 'red',
              fill: false,
              tension: 0.1,
              pointRadius: 0,
              showLine: true
            }
          ]
        },
        options: {
          scales: {
            x: {
              type: 'linear',
              position: 'bottom',
              title: {
                display: true,
                text: 'X Axis'
              }
            },
            y: {
              title: {
                display: true,
                text: 'Y Axis'
              }
            }
          }
        }
      });
    }

    // Fetch and plot the chart using AJAX
    fetchJSONFile('https://www.sagarrawal.com.np/csvjson.json', plotChart);
    #chart-container {
      width: 50%;
      height: 90%;
      position: relative;
    }

    canvas {
      background-color: white;
    }

    /* Draggable vertical line */
    #draggable {
      position: absolute;
      width: 2px;
      height: 100%;
      background-color: black;
      z-index: 10;
      cursor: pointer;
    }

    /* Tooltip to show values */
    #tooltip {
      position: absolute;
      background-color: rgba(0, 0, 0, 0.75);
      color: white;
      padding: 5px;
      border-radius: 3px;
      font-size: 12px;
      display: none;
      z-index: 20;
    }
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<div id="chart-container">
    <div id="draggable"></div>
    <canvas id="myChart"></canvas>
    <div id="tooltip"></div> <!-- Tooltip to display values -->
  </div>

It runs and achives its goals but with error cause by this line
‘draggableElement.style.height = ${newHeight}px;’ , which is understandable as it has not been defined anywhere in the code, so when i remove the line, the black line slider then appears on top of the plot outside the two plots. But Only keeping it , the plot behaves as expected and when dragged black line appears within the two plot. so though i get results the way i want but i’m not able to understand why removing the above line , my chart don’t work as expected.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video