html5 使用 bezierCurveTo 绘制高斯函数

html5 draw gaussian function using bezierCurveTo

我一直在尝试使用 bezierCurveTo

绘制类高斯函数

找到下面的代码

<canvas id="thisCan" width="0px" height="0px" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>
(function() {
var
// Obtain a reference to the canvas element
// using its id.
htmlCanvas = document.getElementById('thisCan'),
   // Obtain a graphics context on the
   // canvas element for drawing.
   ctx = htmlCanvas.getContext('2d');

var width = 0;
var height = 0;

// Start listening to resize events and
// draw canvas.
initialize();

function initialize() 
{
  // Register an event listener to
  // call the resizeCanvas() function each time
  // the window is resized.
  window.addEventListener('resize', resizeCanvas, false);
  // Draw canvas border for the first time.
  resizeCanvas();
}

// Display custom canvas.
// In this case it's a blue, 5 pixel border that
// resizes along with the browser window.
function redraw()
{
  ctx.beginPath();

  ctx.moveTo(width/2, 0);
  ctx.bezierCurveTo(150, 119, 186, 121, 66, 185);

  ctx.moveTo(width/2 + width * 0.08 , 0);
  ctx.bezierCurveTo(344, 119, 344, 121, 504, 185);

  ctx.stroke();
}

// Runs each time the DOM window resize event fires.
// Resets the canvas dimensions to match window,
// then draws the new borders accordingly.
function resizeCanvas()
{
  var contentElement = document.getElementsByClassName("content-box post")[0]
  width = htmlCanvas.width = (contentElement.clientWidth * 0.75)
  height = htmlCanvas.height = (contentElement.offsetWidth*0.75 * 0.5);

  redraw();
}

})();
</script>

我也打算在中间画很多曲线。 但是如何根据 widthheight 变量将其设为参数化

我需要使用宽度和高度参数指定控制点,使其成为window尺寸不变。

有办法吗?

我设法解决了。

具体来说,我正在寻找半高斯曲线。

我发现 guassian function 相对于 bezier curves 有一个非常特殊的 属性。它可能是初级的,但我在 google 上找不到它。所以这可能是有用的发现。

如果三次贝塞尔曲线的每个控制点都位于 "line parallel to X axis and passing through start point/end point" 上,则生成的曲线将是半高斯曲线。

例如

基于这一发现,我编写了以下代码:

<canvas id="thisCan" width="0px" height="0px">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>
(function() {
var
// Obtain a reference to the canvas element
// using its id.
htmlCanvas = document.getElementById('thisCan'),
   // Obtain a graphics context on the
   // canvas element for drawing.
   ctx = htmlCanvas.getContext('2d');

// Start listening to resize events and
// draw canvas.
initialize();

function initialize() 
{
  // Register an event listener to
  // call the resizeCanvas() function each time
  // the window is resized.
  window.addEventListener('resize', resizeCanvas, false);
  // Draw canvas border for the first time.
  resizeCanvas();
}

// Display custom canvas.
// In this case it's a blue, 5 pixel border that
// resizes along with the browser window.
function redraw(width, height)
{
  var start = width/2;
  var margin = width * 0.01;
  var height = (width / 3) - (margin * 4);
  var end_step = width/4

  ctx.beginPath();

  ctx.moveTo(start - margin, 0);
  ctx.bezierCurveTo((start - height/3), 0 , (start - height/3), height , end_step*1, height);

  ctx.moveTo(start + margin, 0);
  ctx.bezierCurveTo((start + height/3), 0 , (start + height/3), height , end_step*3, height);

  ctx.moveTo(start - margin, 0);
  ctx.bezierCurveTo((start - height*0.33), 0 , (start - height*0.16), height , end_step*1.5, height);

  ctx.moveTo(start + margin, 0);
  ctx.bezierCurveTo((start + height*0.33), 0 , (start + height*0.16), height , end_step*2.5, height);

  ctx.moveTo(start, 0);
  ctx.bezierCurveTo((start ), 0 , (start ), height , end_step*2, height);

  ctx.stroke();
}

// Runs each time the DOM window resize event fires.
// Resets the canvas dimensions to match window,
// then draws the new borders accordingly.
function resizeCanvas()
{
  var width = 0;
  var height = 0;

  var contentElement = document.getElementsByClassName("content-box post")[0]
  width = htmlCanvas.width = (contentElement.clientWidth * 0.85)
  height = htmlCanvas.height = (contentElement.offsetWidth*0.85 * 0.33);

  redraw(width, height);
}

})();
</script>

和输出:

如果您想要指数曲线,请不要使用贝塞尔曲线,它们是不同的函数。相反,只需绘制您实际需要的函数,例如 http://jsbin.com/nubutodosu/edit?js,output,您可以在其中定义一个高斯对象:

// Gaussian distribution generator

var Gaussian = function(mean, std) {
  this.mean = mean;
  this.std = std;
  this.a = 1/Math.sqrt(2*Math.PI);
};

Gaussian.prototype = {
  addStd: function(v) {
    this.std += v;
  },

  get: function(x) {
    var f = this.a / this.std;
    var p = -1/2;
    var c = (x-this.mean)/this.std;
    c *= c;
    p *= c;
    return f * Math.pow(Math.E, p);
  },

  generateValues: function(start, end) {
    var LUT = [];
    var step = (Math.abs(start)+Math.abs(end)) / 100;
    for(var i=start; i<end; i+=step) {
      LUT.push(this.get(i));
    }
    return LUT;
  }
};

然后你可以给它一个绘图例程,这样它就可以在你需要的时间间隔内绘制自己:

...
  draw: function(ctx) {
    var points = this.generateValues(-10,10);
    var len = points.length;
    ctx.strokeStyle = "black";
    ctx.beginPath();
    var p0 = points[0];
    ctx.moveTo(0, height - (height*p0));
    points.forEach(function(p,i) {
      if(i===0) {
        return;
      }
      ctx.lineTo(width * i/len, height - (height*p));
      p0 = p;
    });
    ctx.stroke();
  }
...

因此,您在区间内构建值数组,然后通过 "connecting the dots" 在 canvas 上绘制它们。