Chart.js 在 Y 上没有零值的情况下交集不起作用

Chart.js intersection not working without zero value on Y

这是我从另一个主题中提取的代码:

var ORDER_STATS = {
  "2016": [0, 400010, 400110, 400110, 401000, 401000, 400100, 401000, 400001],
  "Source": [330865, 332865, 318865, 332865, 320865, 334865, 322865, 320865, 340865],
  "Moving average LONG": [304493, 315040, 325809, 329532, 332643, 330421, 329754, 327309, 326865]
};
var colors = ['206,191,26', '119,206,26', '26,200,206', '236,124,98', '206,26,140', '26,77,206', '236,124,98', '206,26,140', '26,77,206'];

// Definning X
var ordersChartData = {
  labels: ['2022-02-10', '2022-02-11', '2022-02-12', '2022-02-13', '2022-02-14', '2022-02-15', '2022-02-16', '2022-02-17', '2022-02-18'],
  datasets: []
}

Object.keys(ORDER_STATS).forEach(function(key) {
  color = colors.shift();
  ordersChartData.datasets.push({
    label: key,
    lineTension: 0,
    type: 'line',
    backgroundColor: "rgba(" + color + ",0.1)",
    borderColor: "rgba(" + color + ",1)",
    borderWidth: 2,
    pointBackgroundColor: "rgba(" + color + ",1)",
    pointBorderColor: "#fff",
    pointBorderWidth: 1,
    pointRadius: 4,
    pointHoverBackgroundColor: "#fff",
    pointHoverBorderColor: "rgba(" + color + ",1)",
    pointHoverBorderWidth: 1,
    data: ORDER_STATS[key]
  });
});

var ctx = document.getElementById("myChart").getContext("2d");

Chart.defaults.global.defaultFontColor = 'grey';
Chart.defaults.global.defaultFontFamily = "Tahoma";
Chart.defaults.global.defaultFontSize = 11;
Chart.defaults.global.defaultFontStyle = 'normal';

var myChart = new Chart(ctx, {
  type: 'line',
  data: ordersChartData,
  defaultFontSize: 11,
  options: {
    responsive: true,

    title: {
      display: true,
      text: 'Intersection realization',
      fontColor: "#444",
      fontFamily: 'Tahoma',
      padding: 0
    },

    legend: {
      display: true,
      labels: {
        fontColor: 'grey',
        usePointStyle: true
      }
    },
    tooltips: {
      mode: "index",
      intersect: true,
      position: 'nearest',
      bodySpacing: 4

    }
  }
});

Chart.plugins.register({
  afterDatasetsDraw: function(chartInstance, easing) {

    var Y = chartInstance.scales['y-axis-0'];
    var X = chartInstance.scales['x-axis-0'];

    zeroPointY = Y.top + ((Y.bottom - Y.top) / (Y.ticks.length - 1) * Y.zeroLineIndex);
    zeroPointX = Y.right;

    yScale = (Y.bottom - Y.top) / (Y.end - Y.start);
    xScale = (X.right - X.left) / (X.ticks.length - 1);

    console.log("aaa1", Y.top, Y.bottom, Y.ticks.length, Y.zeroLineIndex, zeroPointY);
    console.log("aaa2", Y.bottom, Y.top, Y.end, Y.start, yScale);


    var intersects = findIntersects(ORDER_STATS['Source'], ORDER_STATS['Moving average LONG']);
    var context = chartInstance.chart.ctx;

    intersects.forEach(function(result, idx) {
      context.fillStyle = 'red';
      context.beginPath();
      context.arc((result.x * xScale) + zeroPointX, (Y.end - Y.start) - (result.y * yScale) - ((Y.end - Y.start) - zeroPointY), 3, 0, 2 * Math.PI, true);
      context.fill();
    });
  }
});


function findIntersects(line1, line2) {
  var intersects = [];

  line1.forEach(function(val, idx) {
    var line1StartX = idx;
    var line1StartY = line1[idx];
    var line1EndX = idx + 1;
    var line1EndY = line1[idx + 1];
    var line2StartX = idx;
    var line2StartY = line2[idx];
    var line2EndX = idx + 1;
    var line2EndY = line2[idx + 1];

    result = checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY);

    if (result.onLine1 && result.onLine2) {
      intersects.push(result);
    }
  });

  return intersects;
}

function checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
  // if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
  var denominator, a, b, numerator1, numerator2, result = {
    x: null,
    y: null,
    onLine1: false,
    onLine2: false
  };
  denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
  if (denominator == 0) {
    return result;
  }
  a = line1StartY - line2StartY;
  b = line1StartX - line2StartX;
  numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
  numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
  a = numerator1 / denominator;
  b = numerator2 / denominator;

  // if we cast these lines infinitely in both directions, they intersect here:
  result.x = line1StartX + (a * (line1EndX - line1StartX));
  result.y = line1StartY + (a * (line1EndY - line1StartY));

  // it is worth noting that this should be the same as:
  x = line2StartX + (b * (line2EndX - line2StartX));
  y = line2StartX + (b * (line2EndY - line2StartY));

  // if line1 is a segment and line2 is infinite, they intersect if:
  if (a > 0 && a < 1) {
    result.onLine1 = true;
  }
  // if line2 is a segment and line1 is infinite, they intersect if:
  if (b > 0 && b < 1) {
    result.onLine2 = true;
  }
  // if line1 and line2 are segments, they intersect if both of the above are true
  return result;
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
<canvas id="myChart" width="650" height="241" style="display: block; width: 650px; height: 241px;"></canvas>

它运行良好,但如果在这里:

"2016" : [0, 400010, 400110, 400110, 401000, 401000, 400100, 401000, 400001]

我在 300000 上更改了第一个值 0,代码无法再显示交集。

我认为问题出在 Y.zeroLineIndex。 我尝试了很多变体,记录了几乎所有的值并注意到当第一个值为零时(如示例),Y.zeroLineIndex 为 9。但是如果你将第一个值更改为 300000,它将变为 - 1. 在尝试检测问题并修复它数小时后,我不确定如何修复它。没有任何帮助。

我在 JS 方面不太好,所以请求帮助

编辑: [演示][1] [1]: https://i.stack.imgur.com/0t3Gu.png

我对你的问题进行了一些讨论,发现你在根据 Y-axis 设置高度时遇到了问题。使用此代码,您会发现它在任何情况下都有效。我对 context.arc 函数的 zeroPointY、yScale 和 Y 值进行了更改。

Chart.plugins.register({
            afterDatasetsDraw: function (chartInstance, easing) {

                var Y = chartInstance.scales['y-axis-0'];
                var X = chartInstance.scales['x-axis-0'];

                zeroPointY = (Y.bottom - Y.top)/(Y.ticks.length-1);
                zeroPointX = Y.right;

                yScale = (Y.end - Y.start)/ (Y.ticks.length - 1);
                xScale = (X.right - X.left) / (X.ticks.length - 1);

                console.log("aaa1", Y.top, Y.bottom, Y.ticks.length, Y.zeroLineIndex, zeroPointY);
                console.log("aaa2", Y.bottom, Y.top, Y.end, Y.start, yScale);

                var intersects = findIntersects(ORDER_STATS['Source'], ORDER_STATS['Moving average LONG']);
                var context = chartInstance.chart.ctx;

                intersects.forEach(function (result1, idx) {
                    context.fillStyle = 'red';
                    context.beginPath();
                    context.arc((result1.x * xScale) + zeroPointX, Y.top + (Y.end - result1.y)/yScale*zeroPointY, 3, 0, Math.PI * 2, true);
                    context.fill();
                });
            }
        });