Xhy*_*ynk 6 javascript animation canvas html5-canvas
作为参考,我正在谈论Discord登录页面左上方的深灰色空间。对于无法访问该链接的任何人,以下是屏幕截图:
它具有许多非常酷的效果,点和(较暗的阴影)随鼠标移动,但是我对“摆动边缘”效果更感兴趣,而对“快速摆动/缩放”则更感兴趣。页面加载时(加载时在画布上缩放会产生类似的效果,即使不是“更便宜”)。
不幸的是,我无法以MCVE的方式进行大量开发,因为我不确定自己从哪里开始。我尝试挖掘Discord的资产,但是我对Webpack不够熟悉,无法确定正在发生的事情。
我能够在“动画波/摆动”上挖掘的一切都是CSS驱动的SVG或剪切路径边框,我想产生一些更自然的东西。
Zev*_*van 16
很有趣的问题。我已将 blob 缩小,以便在下面的预览中可见。
const SCALE = 0.25;
const TWO_PI = Math.PI * 2;
const HALF_PI = Math.PI / 2;
const canvas = document.createElement("canvas");
const c = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
class Blob {
constructor() {
this.wobbleIncrement = 0;
// use this to change the size of the blob
this.radius = 500;
// think of this as detail level
// number of conections in the `bezierSkin`
this.segments = 12;
this.step = HALF_PI / this.segments;
this.anchors = [];
this.radii = [];
this.thetaOff = [];
const bumpRadius = 100;
const halfBumpRadius = bumpRadius / 2;
for (let i = 0; i < this.segments + 2; i++) {
this.anchors.push(0, 0);
this.radii.push(Math.random() * bumpRadius - halfBumpRadius);
this.thetaOff.push(Math.random() * TWO_PI);
}
this.theta = 0;
this.thetaRamp = 0;
this.thetaRampDest = 12;
this.rampDamp = 25;
}
update() {
this.thetaRamp += (this.thetaRampDest - this.thetaRamp) / this.rampDamp;
this.theta += 0.03;
this.anchors = [0, this.radius];
for (let i = 0; i <= this.segments + 2; i++) {
const sine = Math.sin(this.thetaOff[i] + this.theta + this.thetaRamp);
const rad = this.radius + this.radii[i] * sine;
const theta = this.step * i;
const x = rad * Math.sin(theta);
const y = rad * Math.cos(theta);
this.anchors.push(x, y);
}
c.save();
c.translate(-10, -10);
c.scale(SCALE, SCALE);
c.fillStyle = "blue";
c.beginPath();
c.moveTo(0, 0);
bezierSkin(this.anchors, false);
c.lineTo(0, 0);
c.fill();
c.restore();
}
}
const blob = new Blob();
function loop() {
c.clearRect(0, 0, canvas.width, canvas.height);
blob.update();
window.requestAnimationFrame(loop);
}
loop();
// array of xy coords, closed boolean
function bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
if (closed) {
c.moveTo(avg[0], avg[1]);
for (let i = 2; i < leng; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]);
} else {
c.moveTo(bez[0], bez[1]);
c.lineTo(avg[0], avg[1]);
for (let i = 2; i < leng - 2; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.lineTo(bez[leng - 2], bez[leng - 1]);
}
}
// create anchor points by averaging the control points
function calcAvgs(p) {
const avg = [];
const leng = p.length;
let prev;
for (let i = 2; i < leng; i++) {
prev = i - 2;
avg.push((p[prev] + p[i]) / 2);
}
// close
avg.push((p[0] + p[leng - 2]) / 2, (p[1] + p[leng - 1]) / 2);
return avg;
}Run Code Online (Sandbox Code Playgroud)
这里发生了很多事情。为了创建这种效果,您需要很好地了解如何定义二次贝塞尔曲线。一旦你有了它,有一个古老的技巧,多年来我已经使用了很多次。要生成平滑的链接二次贝塞尔曲线,请定义一个点列表并计算它们的平均值。然后将这些点用作控制点,将新的平均点用作锚点。请参阅bezierSkin和calcAvgs功能。
有了绘制平滑贝塞尔曲线的能力,剩下的就是将点定位在弧形中,然后对它们进行动画处理。为此,我们使用一点数学:
x = radius * sin(theta)
y = radius * cos(theta)
Run Code Online (Sandbox Code Playgroud)
这将极坐标转换为笛卡尔坐标。theta圆的圆周上的角在哪里[0 - 2pi]。
至于动画,这里还有很多事情要做——我会看看这个周末我是否有更多时间用更多细节和信息更新答案,但希望这会有所帮助。
该动画在画布上运行,它是一个简单的贝塞尔曲线动画。
为了获得自然的感觉,您应该看看Perlin噪声,这是在开发原始Tron视频FX 时引入的。
您可以在这里找到了解Perlin噪音的好指南。
在示例中,我使用了https://github.com/josephg/noisejs
var c = $('canvas').get(0).getContext('2d');
var simplex = new SimplexNoise();
var t = 0;
function init() {
window.requestAnimationFrame(draw);
}
function draw() {
c.clearRect(0, 0, 600, 300);
c.strokeStyle="blue";
c.moveTo(100,100);
c.lineTo(300,100);
c.stroke();
// Draw a Bézier curve by using the same line cooridinates.
c.beginPath();
c.lineWidth="3";
c.strokeStyle="black";
c.moveTo(100,100);
c.bezierCurveTo((simplex.noise2D(t,t)+1)*200,(simplex.noise2D(t,t)+1)*200,(simplex.noise2D(t,t)+1)*200,0,300,100);
c.stroke();
// draw reference points
c.fillRect(100-5,100-5,10,10);
c.fillRect(200-5,200-5,10,10);
c.fillRect(200-5,0-5,10,10);
c.fillRect(300-5,100-5,10,10);
t+=0.001;
window.requestAnimationFrame(draw);
}
init();Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.js"></script>
<canvas width="600" height="300"></canvas>Run Code Online (Sandbox Code Playgroud)
注意:对Discord源代码的进一步研究,我指出这是使用https://www.npm.red/~epistemex库。Epistemex NPM软件包仍然在线,而GitHub存储库和配置文件不再存在。
注意2:另一种方法可能依赖于此演示之类的物理库,但是如果您只需要一个效果,那可能就太过分了。