html5 canvas 图片变形,HTML5/Canvas 流动的变形圆形

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

/**

* inspired by:

* Rectangle World

* http://rectangleworld.com/blog/archives/462

*/

// http://stackoverflow.com/a/5624139/5930258

const hexToRgb = (hex) => {

let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;

hex = hex.replace(shorthandRegex, (m, r, g, b) => {

return r + r + g + g + b + b;

});

let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);

return result ? [

parseInt(result[1], 16),

parseInt(result[2], 16),

parseInt(result[3], 16)

] : null;

}

const canvas = document.querySelector('.mycanvas');

const ctx = canvas.getContext('2d');

let winWidth;

let winHeight;

let midX;

let midY;

let tick;

let rafId;

class Circle {

constructor(options) {

this.assign(options);

return this;

}

create() {

this.points = [];

this.radius = (this.grow) ? 0 : this.radius;

let angle = 0;

let step = (Math.PI * 2) / this.segments;

for (let i = 0; i < this.segments; i++) {

let x = this.x + (Math.cos(angle) * this.radius);

let y = this.y + (Math.sin(angle) * this.radius);

this.points.push({

x, y, angle

});

angle += step;

}

return this;

}

update(x, y, endX) {

this.x = x;

this.y = y;

if (this.grow) {

this.radius = Math.max(0, this.maxRadius * (x / endX));

}

}

updatePoint(p, tick, baseX, baseY) {

p.x = Math.cos(p.angle);

p.y = Math.sin(p.angle);

let smoothness = 1;

let nx = p.x * smoothness;

let ny = p.x * smoothness; // x intentionally

let radius = this.radius + this.getNoise(tick + nx, tick + ny);

p.x *= radius;

p.y *= radius;

p.x += baseX;

p.y += baseY;

}

getNoise(a, b) {

const max = this.radius * 1.5;

const n = noise.perlin2(a, b);

// map between -1, 1

return (n + 1) * (max + max) / 2 - max;

}

assign(options) {

Object.assign(this, options);

this.maxRadius = this.radius;

this.reset();

}

reset() {

this.create();

}

// when setting a rgb value ([r, g, b]) directly in dat.ui, it sometimes returns a hex

// so, input a hex by default and convert it manually to rgb

set color1(c1) {

let rgb = hexToRgb(c1).join(', ');

this._color1 = c1;

this.rgb1 = `rgba(${rgb}, ${this.alpha})`;

}

set color2(c2) {

let rgb = hexToRgb(c2).join(', ');

this._color2 = c2;

this.rgb2 = `rgba(${rgb}, ${this.alpha})`;

}

get color1() {

return this._color1;

}

get color2() {

return this._color2;

}

get rgba1() {

return this.rgb1;

}

get rgba2() {

return this.rgb2;

}

}

const assignColors = () => {

circle.color1 = options.color1;

circle.color2 = options.color2;

circle.alpha = options.alpha;

}

const setupStage = () => {

winWidth = window.innerWidth;

winHeight = window.innerHeight;

midX = winWidth >> 1;

midY = winHeight >> 1;

tick = performance.now();

ctx.clearRect(0, 0, winWidth, winHeight);

ctx.canvas.width = winWidth;

ctx.canvas.height = winHeight;

}

const redraw = () => {

setupStage();

circle.assign(options);

}

const loop = () => {

tick += options.randomness;

circle.update(circle.x + 1.5, midY + ((midY / 2) * noise.perlin2(tick * 0.75, tick)), winWidth);

let currX = circle.x;

let currY = circle.y;

let grad = ctx.createLinearGradient(-circle.radius, currY, circle.radius, currY);

grad.addColorStop(0, circle.rgba1);

grad.addColorStop(1, circle.rgba2);

ctx.strokeStyle = grad;

ctx.lineWidth = options.lineWidth;

ctx.save();

ctx.translate(currX, currY);

circle.points.forEach((point, index) => {

ctx.beginPath();

ctx.moveTo(point.x - currX, point.y - currY);

circle.updatePoint(point, tick, currX, currY);

ctx.lineTo(point.x - currX, point.y - currY);

ctx.stroke();

ctx.closePath();

});

ctx.restore();

rafId = requestAnimationFrame(loop);

}

window.addEventListener('resize', redraw);

setupStage();

let options = {

segments: 1000,

radius: 150,

x: -100,

y: midY,

grow: false,

radius: 130,

color1: '#d2205e',

color2: '#29cafc',

alpha: 0.1,

randomness: 0.005,

lineWidth: 1.01

};

let circle = new Circle(options);

noise.seed(Math.random());

redraw();

loop();

let gui = new dat.GUI();

let folderColor = gui.addFolder('Appearance');

let folderSettings = gui.addFolder('Circle settings');

folderColor.addColor(options, 'color1').onChange(assignColors);

folderColor.addColor(options, 'color2').onChange(assignColors);

folderColor.add(options, 'alpha').step(0.001).min(0.01).max(1).onChange(assignColors);

folderColor.add(options, 'lineWidth').step(0.01).min(1.01).max(5);

folderSettings.add(options, 'segments', 100, 1500).step(1).onFinishChange(redraw);

folderSettings.add(options, 'grow').onFinishChange(redraw);

gui.add({

redraw

}, 'redraw');

folderColor.open();

gui.close();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值