在 HTML5 Canvas 上绘制倒数函数的问题

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

我目前正在使用 HTML Canvas 和 JavaScript 开发一个函数绘图应用程序。该应用程序旨在绘制用户输入的各种数学函数。它完美地处理线性函数(如 y=x 和 y=x+2),并在画布上正确渲染它们。

但是,我遇到了倒数函数的特定问题,特别是像 y=2/x 这样的函数。当我尝试绘制此类函数时,画布保持空白,并且不会在控制台中显示任何错误消息或日志。

这是我处理绘图的代码片段:

var canvas = document.getElementById('plotCanvas');
var ctx = canvas.getContext('2d');

var startX = -20;
var endX = 20;
var scaleFactor = 25;
var epsilon = 0.0001; // A small number close to zero


ctx.beginPath();
for (var x = startX + 0.01; x <= endX; x += 0.01) {
  xP = (x - startX) * (canvas.width / (endX - startX));
  let y = 2/x
  yP = canvas.height / 2 - y * scaleFactor

  if (xP > -canvas.width && yP > -canvas.height && xP < canvas.width && yP < canvas.height) {
    ctx.lineTo(xP, yP);
  } else {
    ctx.moveTo(xP, yP)
  }
}




ctx.strokeStyle = 'blue';
ctx.stroke();
canvas {
  border: 1px solid black;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="plotCanvas" width="400" height="300"></canvas>
</body>
</html>

我认为问题是因为当 x = 0 时,它将趋于无穷大,而这是不可能绘制的。

我该如何解决这个问题?

javascript html canvas html5-canvas
1个回答
0
投票

您可以对所有 y 值进行排序,并找到将包含特定百分位数值的

min
max

请注意,如果您选择较大的范围或非常小的 delta x,这会产生一些开销。

这是一个例子,我:

  • 首先计算(x,y)点,
  • 然后计算包含 98% 的点的最小和最大 y 值,
  • 然后通过将每个点从 (x,y) 空间缩放到画布尺寸来渲染每个点

const cvs = document.getElementById('plotCanvas');
const ctx = cvs.getContext('2d');

const minX = -20;
const maxX = 20;
const dx = 0.1;

const points = graph(
  x => 2 / x,
  minX,
  maxX,
  dx
);

const yRange = range(0.01, 0.99, points.map(p => p.y));

ctx.beginPath();
for (const { x, y, i } of points) {
  
  const px = scale(x, minX, maxX, 0, cvs.width);
  const py = scale(y, yRange.max, yRange.min, 0, cvs.height);

  const prev = points[i - 1];
  
  // Do not draw lines to/from (-)Infinity
  if (
    !prev ||
    y === Infinity ||
    y === -Infinity ||
    prev.y === Infinity ||
    prev.y === -Infinity) {
    ctx.moveTo(px, py);
  } else {
    ctx.lineTo(px, py);
  }

}


ctx.strokeStyle = 'blue';
ctx.stroke();

function scale(from, minFrom, maxFrom, minTo, maxTo) {
  const pFrom = (from - minFrom) / (maxFrom - minFrom);
  return minTo + (maxTo - minTo) * pFrom;
}

function graph(
  f,
  startX = -20,
  endX = 20,
  dx = 0.1,
) {
  const points = [];
  
  for (let i = 0; i < (endX - startX) / dx; i += 1) {
    const x = startX + i * dx;
    const y = f(x)
    points.push({ x, y, i });
  }
  
  return points;
}

function range(fromP, toP, values) {
  const p0 = Math.round(values.length * fromP);
  const p1 = Math.round(values.length * toP);
  
  const s = Array.from(values).sort((a,b) => b - a);
  
  return { min: s[p0], max: s[p1] };
}
<canvas id="plotCanvas" width="400" height="300" style="border: 1px solid black"></canvas>

© www.soinside.com 2019 - 2024. All rights reserved.