根据mouseX和mouseY在圆上应用噪声

时间:2017-05-22 11:02:26

标签: javascript canvas

我创建了一个小点的blob。我希望我的blob根据mouseX和mouseY在其表面显示噪音。我希望它在鼠标所在的象限中显示高噪声。我希望它是波浪状的。以下是我的代码。

var ctx = document.querySelector("canvas").getContext("2d");
var cx = 200;
var cy = 200;
var radius = 50;
var amp = 2;
var mouseX = 0;
var mouseY = 0;

document.querySelector("canvas").addEventListener("mousemove", function (e) {
	mouseX = e.clientX;
	mouseY = e.clientY;
});

function drawTheBlob() {
	ctx.fillStyle = "#000";
	ctx.fillRect(0, 0, 400, 400);

	ctx.beginPath();
	ctx.strokeStyle = "#fff";
  for (var a = 0; a < 360; a ++) {
    var angle = a * Math.PI/180;
    var x = cx + radius * Math.cos(angle) + Math.random() * amp;
    var y = cy + radius * Math.sin(angle) + Math.random() * amp;
    ctx.lineTo(x, y);
  }
  ctx.stroke();
  ctx.closePath();
  
  requestAnimationFrame(drawTheBlob);
}

drawTheBlob();
<canvas width="400" height="400"></canvas>

1 个答案:

答案 0 :(得分:1)

在圆上添加sin波。使用ctx.arc绘制圆的平坦部分以获得速度,因为绘制许多带线条的圆圈会很慢。请参阅代码以了解已完成的操作。

var ctx = document.querySelector("canvas").getContext("2d");
ctx.lineWidth = 3;
ctx.lineJoin = "round";
var cx = 100;
var cy = 100;
var radius = 50;

var mouseX = 0;
var mouseY = 0;
const quadWidth = Math.PI / 2;     // area of effect PI/2 is 90 degree
const steps = radius / quadWidth; // number steps around the circle matches 1 pixel per step, 
const noiseAmpMax = 5;         // in pixels
const noiseWaveMoveSpeed = 2;  // speed of waves on circle in radians per second
const noiseWaveFreq = 16;      // how many waves per 360 deg
document.querySelector("canvas").addEventListener("mousemove", function(e) {
  mouseX = e.clientX;
  mouseY = e.clientY;
});

function drawTheBlob(time) { // time is passed from the requestAnimationFrame call
  var amp = 0; // amplitude of noise 
  var wavePos = ((time / 1000) * Math.PI) * noiseWaveMoveSpeed;
  var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);
  ctx.fillStyle = "#000";
  ctx.fillRect(0, 0, 400, 400);

  ctx.beginPath();
  ctx.strokeStyle = "#fff";
  ctx.fillStyle = "red";
  // draw arc for parts that have no noise as it is a log quicker
  ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);
  for (var a = 0; a < 1; a += 1 / steps) {
    var angle = (mouseDir - quadWidth / 2) + a * quadWidth;
    var angDist = Math.abs(angle - mouseDir); // find angular distance from mouse
                                              // as a positive value, it does not mater 
                                              // what the sign is
    if (angDist < quadWidth / 2) { // is angle distance within the range of effect
                                   // normalise the distance (make it 0 to 1)
      amp = 1 - angDist / (quadWidth / 2);
    } else {
      amp = 0; // no noise
    }
    // amp will be zero if away from mouse direction and 0 to 1 the closer to 
    // mouse angle it gets.
    // add a sin wave to the radius and scale it by amp
    var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp;
    var x = cx + dist * Math.cos(angle);
    var y = cy + dist * Math.sin(angle);
    ctx.lineTo(x, y);
  }
  ctx.closePath(); // use close path to close the gap (only needed if you need to draw a line from the end to the start. It is not needed to match beginPath
  ctx.fill();
  ctx.stroke();

  requestAnimationFrame(drawTheBlob);
}

requestAnimationFrame(drawTheBlob); // start this way so that you get the time argument
<canvas width="200" height="200"></canvas>

工作原理。

鼠标方向

首先我们需要从圆圈到鼠标的方向。要做到这一点,我们使用函数Math.atan2它从圆到鼠标的向量,并以弧度返回方向。该函数有点奇怪,因为它首先需要y,然后是x。

var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);

绘制弧以节省CPU时间

现在我们有了鼠标的方向,我们可以使用arc绘制没有噪音的圆圈部分。

ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);

变量quadWidth是噪声位的角度大小,因此从mouseDir我们加上角度宽度的一半,并将弧线绘制到mouseDir加上360度,占{{1}的一半}}

关于Radians的快速词汇

几乎所有编程语言都使用弧度来定义角度,360度等于2 * PI或2 * 3.1415,这可能很难让你理解,但是有充分的理由使用弧度。现在请记住,弧度的整圆是quadWidth2 * Math.PI = 360degMath.PI = 180degMath.PI / 2 = 90degMath.PI / 4 = 45Deg。你不必记住Math.PI / 180 = 1deg只是半圈的数字。

上面的

Math.PI是一个定义为quadWidth的常量,为90deg。

for循环

for循环仅在const quadWidth = Math.PI / 2;周围绘制(Math.PI / 2)90deg部分,从45度左侧到45度右侧。或者你设置的任何内容mouseDir

quadWidth

我从0到1循环给出合理平滑曲线的步数。我们可以通过乘以值for (var a = 0; a < 1; a += 1 / steps) { 并将其添加到a * quadWidth来找到我们绘制的嘈杂弧的哪个部分。这意味着我们从mouseDir - quadWidth / 2开始,然后将时钟移至mouseDir - 45deg

mouseDir + 45deg

接下来我发现var angle = (mouseDir - quadWidth / 2) + a * quadWidth; angle有多远(可以在这里稍微优化一下,但如果你想在另一部分吸取更多噪音,这种方式会更灵活一点())

mouseDir

如果该数字小于var angDist = Math.abs(angle - mouseDir); ,则将该值转换为0到1的范围,其中0表示距离鼠标方向最远的角度和最近的1。

quadWidth / 2

罪恶之波

现在我们计算当前角度的圆的半径并为其添加正弦波。首先是if (angDist < quadWidth / 2) { amp = 1 - angDist / (quadWidth / 2); } else { amp = 0; } 然后是sin波乘以最后一步计算的radius。在amp为零的情况下,不添加任何正弦波,其中amp为1(在鼠标方向上),将添加完整的正弦波。

amp

var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp wavePosnoiseWaveFreq控制着正弦波的动画。使用这些值来了解它们的作用,noiseAmpMax是根据函数开始时的时间计算的。

使用wavePos,我们可以计算圆的下一行的x,y位置

dist

实验

我添加了一些常量

var x = cx + dist * Math.cos(angle);
var y = cy + dist * Math.sin(angle);
ctx.lineTo(x, y);

要了解他们的实验,并更改数字,看看会发生什么。