如何调整draggableElement以获得正确的x和y位置

问题描述 投票:0回答:1

我已经实现了图表js来绘制由红线和蓝线指示的两条曲线。我想添加一个滑块(黑色垂直线),以便它始终保持在两条曲线内,并且用户可以将其向左和向右移动。当用户向左或向右滑动它时,它会自行调整高度。因此,获取下图的 x 和 y 值,并通过减去第一个图的 y1 和第二个图的 y2 来设置高度,它的行为符合预期。 这是我的代码,

    // 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>
它运行并实现其目标,但由于此行导致错误 'draggableElement.style.height =
${newHeight}px
;' ,这是可以理解的,因为它没有在代码中的任何地方定义,所以当我删除该线时,黑线滑块就会出现在两个图之外的图的顶部。但只有保留它,绘图才会按预期运行,并且当拖动黑线时会出现在两个绘图中。因此,虽然我按照我想要的方式得到结果,但我无法理解为什么删除上面的行,我的图表无法按预期工作。

javascript jquery css jquery-ui chart.js
1个回答
0
投票

首先,您可以将导致错误的行替换为更有意义的内容,例如

throw 'myError'
。无论如何,此时会发生错误 阻止
jquery-ui
'drag'
事件处理程序的正常完成。

将代码调试到

jquery-ui
显示用户处理程序(您的
drag
函数) 在这一行被调用:

if ( this._trigger( "drag", event, ui ) === false ) {.....

如果那里发生错误,则不会执行这一行

this.helper[ 0 ].style.left = this.position.left + "px";
this.helper[ 0 ].style.top = this.position.top + "px";

第二行是将可拖动元素重新定位在顶部的行。

这提供了干净的解决方案 - 将产生错误的行替换为:

ui.position.top = yPixelPos;

您实际上可以将涉及

const blackLine = document.getElementById('draggable')
的所有四行替换为:

ui.position.top = yPixelPos;
ui.position.left = xPixelPos;
ui.helper[0].style.height = `${height}px`;
© www.soinside.com 2019 - 2024. All rights reserved.