如果 Y 上没有零值,Chart.js 交集将无法工作

发布于 2025-01-10 21:31:08 字数 6115 浏览 2 评论 0原文

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

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.sstatic.net/0t3Gu.png

Here's code that I took from another topic:

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>

It's working great, but if here:

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

I change first value, 0, on 300000, code can't show intersection anymore.

Problem is, as I think, in Y.zeroLineIndex.
I've tried a lot of variants, logged to console almost all values and noticed that when first value is zero (like in example), Y.zeroLineIndex is 9. But if u change first value to 300000, it becomes to -1.
I am unsure how to fix it after many hours attempting to detect a problem and fix it. Nothing helped.

In JS I'm not good, so requesting for a help

EDIT:
[DEMO][1]
[1]: https://i.sstatic.net/0t3Gu.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄离 2025-01-17 21:31:09

我对你的问题进行了一番思考,发现你在根据 Y 轴设置高度时遇到了问题。使用此代码,您将发现它在任何情况下都有效。我对 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();
                });
            }
        });

I sat down a bit on your problem and found out that you had a problem setting the height according to the Y-axis. Use this code and you will see that it works in any situation. I made changes on zeroPointY, yScale and on Y value of context.arc function.

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();
                });
            }
        });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文