JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

const tau = 2 * Math.PI

const { random } = _

const { abs, max, sin, cos } = Math

// a collection of Vector methods

class Vector {

constructor (x = 0, y = 0) {

this.x = x

this.y = y

}

static fromPolar (r, a) {

let x = r * cos(a),

y = r * sin(a)

return new Vector(x, y)

}

clone () {

return new Vector(this.x, this.y)

}

add (v) {

this.x += v.x

this.y += v.y

return this

}

mul (x) {

this.x *= x

this.y *= x

return this

}

dist (v) {

let dx, dy

return Math.sqrt(

(dx = this.x - v.x) * dx,

(dy = this.y - v.y) * dy)

}

get r () {

return Math.sqrt(

this.x * this.x +

this.y * this.y)

}

set r (r) {

let n = this.norm()

this.x = r * n.x

this.y = r * n.y

return r

}

get a () {

return Math.atan2(this.y, this.x)

}

set a (a) {

let r = this.r

this.x = r * cos(a)

this.y = r * sin(a)

return a

}

norm () {

let r = this.r

return new Vector(

this.x / r, this.y / r)

}

}

// canvas' built-in drawing methods have a lot of

// overhead. this buffer class is for optimized

// drawing of pixels with alpha. it works by directly

// manipulating pixel data and flushing to the canvas

// by calling putImageData

class CanvasBuffer {

constructor (canvas) {

this.ctx = canvas.getContext("2d")

this.width = canvas.width

this.height = canvas.height

this.center = new Vector(this.width / 2, this.height / 2)

this.ncenter = this.center.clone().mul(-1)

this.clear()

}

clear () {

this.ctx.fillStyle = "#000"

this.ctx.fillRect(0, 0, this.width, this.height)

this.buf = this.ctx.getImageData(0, 0, this.width, this.height)

}

// draws floating point coordinate pixel

// with bilinear interpolation

drawPixel (x, y, c) {

let fx = ~~x,

fy = ~~y,

dx = x - fx,

dy = y - fy

this.drawCell(fx, fy, c, (1 - dx) * (1 - dy))

this.drawCell(fx + 1, fy, c, dx * (1 - dy))

this.drawCell(fx, fy + 1, c, (1 - dx) * dy)

this.drawCell(fx + 1, fy + 1, c, dx * dy)

}

// set color of cell with alpha, for drawPixel

drawCell (x, y, c, a) {

if (x < 0 || x >= this.width) return

if (y < 0 || y >= this.height) return

let data = this.buf.data,

i = 4 * (x + y * this.width),

r = data[i + 0],

g = data[i + 1],

b = data[i + 2]

a *= c[3]

r += c[0] * a

g += c[1] * a

b += c[2] * a

// overflow color math so red + red = white

let ro = max(0, r - 255),

go = max(0, g - 255),

bo = max(0, b - 255),

to = (ro + bo + go) / 6

data[i + 0] = r + to

data[i + 1] = g + to

data[i + 2] = b + to

}

flush () {

this.ctx.putImageData(this.buf, 0, 0)

}

}

// a class for generating composite noise textures

// and reading values of the texture at a position

class Noise {

constructor (settings) {

this.width = settings.width

this.height = settings.height

this.type = settings.type

this.strength = settings.strength

this.canvas = Noise.compositeNoise(

this.width, this.height, settings.startOctave, settings.endOctave)

let ctx = this.canvas.getContext('2d')

this.data = ctx.getImageData(0, 0, this.width, this.height).data

}

// create w by h noise

static noise (w, h) {

let cv = document.createElement('canvas'),

ctx = cv.getContext('2d')

cv.width = w

cv.height = h

let img = ctx.getImageData(0, 0, w, h),

data = img.data

for (let i = 0, l = data.length; i < l; i += 4) {

data[i + 0] = random(0, 255)

data[i + 1] = random(0, 255)

data[i + 2] = random(0, 255)

data[i + 3] = 255

}

ctx.putImageData(img, 0, 0)

return cv;

}

// create composite noise with multiple octaves

static compositeNoise (w, h, soct, eoct) {

let cv = document.createElement('canvas'),

ctx = cv.getContext('2d')

cv.width = w

cv.height = h

ctx.fillStyle = '#000'

ctx.fillRect(0, 0, w, h)

ctx.globalCompositeOperation = 'lighter'

ctx.globalAlpha = 1 / (eoct - soct)

for (let i = soct; i < eoct; i++) {

let noise = Noise.noise(w >> i, h >> i)

ctx.drawImage(noise, 0, 0, w, h)

}

return cv

}

// returns noise value from -1.0 to 1.0

getNoise (x, y, ch = 0) {

// bitwise ~~ to floor

let i = (~~x + ~~y * this.width) * 4

return this.data[i + ch] / 127.5 - 1

}

}

class Particle {

constructor (system, x = 0, y = 0) {

this.system = system

this.pos = new Vector(x, y)

this.vel = new Vector()

this.col = [255, 255, 255, 0.1]

}

update () {

let { x, y } = this.pos,

noise = this.system.noise,

dx = noise.getNoise(x, y, 0),

dy = noise.getNoise(x, y, noise.type == 2 ? 0 : 1),

d = new Vector(dx, dy).mul(noise.strength)

this.col[3] *= 0.99

this.vel.mul(1 - this.system.friction)

this.vel.add(d)

if ((noise.type == 0 && this.vel.r > this.system.speed)

|| noise.type == 1)

this.vel.r = this.system.speed

}

}

class ParticleSystem {

constructor (settings, noise, buffer) {

this.noise = noise

this.buffer = buffer

this.particles = []

this.num = settings.numParticles

this.subFrames = settings.subFrames

this.speed = settings.speed

this.friction = settings.friction

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

this.particles.push(new Particle(this))

let r = (this.buffer.height / 2) * settings.radius

switch (settings.shape) {

case 'circle': this.circle(r); break;

case 'triangle': this.polygon(r, 3); break;

case 'triangle2': this.polygon(r, 3, tau / 2); break;

case 'square': this.polygon(r, 4, tau / 8); break;

case 'square2': this.polygon(r, 4); break;

case 'hexagon': this.polygon(r, 6); break;

case 'hexagon2': this.polygon(r, 6, tau / 12); break;

case 'star': this.star(r); break;

case 'random': this.random(r); break;

}

this.setVels(settings.velocity, this.speed)

if (settings.colorType == 'solid')

this.colorify(settings.color.concat(settings.alpha))

if (settings.colorType == 'rainbow')

this.rainbowify(settings.alpha)

}

circle (radius, thickness = 0) {

for (let p of this.particles) {

// get random radius and angle

let r1 = radius + thickness * random(-0.5, 0.5),

a1 = random(0, tau),

r2 = random(0, 1, true),

a2 = random(0, tau)

let pos = Vector.fromPolar(r1, a1),

vel = Vector.fromPolar(-3, a1)

pos.add(this.buffer.center)

p.pos = pos

p.vel = vel

}

}

polygon (radius, sides, angle = 0) {

// calculate lines of polygon

let lines = []

for (let i = 0; i < sides; i++) {

let a = i * tau / sides - tau / 4 + angle,

x1 = radius * cos(a),

y1 = radius * sin(a),

x2 = radius * cos(a + tau / sides),

y2 = radius * sin(a + tau / sides)

lines.push({ x1, y1, x2, y2 })

}

let yd = (abs(lines[0].y1) - abs(lines[sides >> 1].y1)) / 2

if (lines[0].y1 > lines[sides >> 1].y1) yd *= -1

for (let p of this.particles) {

// choose random line

let { x1, x2, y1, y2 } = lines[random(0, sides - 1)]

// lerp between points

let t = random(0, 1, true),

x = x1 + t * (x2 - x1),

y = y1 + t * (y2 - y1)

let pos = new Vector(x, y)

// center on canvas

pos.add(this.buffer.center)

pos.y += yd

p.pos = pos

}

}

star (radius) {

// calculate lines of star

let lines = []

for (let i = 0; i < 5; i++) {

let a = i * tau / 5 - tau / 4,

x1 = radius * cos(a),

y1 = radius * sin(a),

x2 = radius * cos(a + tau * 2 / 5),

y2 = radius * sin(a + tau * 2 / 5)

lines.push({ x1, y1, x2, y2 })

}

// centering factor

let yd = (abs(lines[0].y1) - abs(lines[2].y1)) / 2

for (let p of this.particles) {

// choose random line

let { x1, x2, y1, y2 } = lines[random(0, 4)]

// magic number is tip to valley on star

let t = random(0, 0.381966011250105)

if (random(0, 1)) t = 1 - t

// lerp between points

let x = x1 + t * (x2 - x1),

y = y1 + t * (y2 - y1)

let pos = new Vector(x, y)

// center on canvas

pos.add(this.buffer.center)

pos.y += yd

p.pos = pos

}

}

fn (fn, domain) {

for (let p of this.particles) {

let x = random(...domain, 1),

y = fn(x),

t = (x + domain[0]) / (domain[1] - domain[0]),

rgb = hsl2rgb(t, 1, 0.5)

let pos = new Vector(x, y)

pos.add(this.buffer.center)

rgb.push(p.col[3])

p.col = rgb

p.pos = pos

}

}

random () {

for (let p of this.particles) {

let x = random(0, this.buffer.width, true),

y = random(0, this.buffer.height, true)

p.pos = new Vector(x, y)

}

}

// 0 = frozen, 1 = outward, 2 = inward

setVels (dir, speed) {

for (let p of this.particles) {

if (dir == 0) {

p.vel.mul(0)

} else {

let vel = p.pos.clone().add(this.buffer.ncenter)

vel.r = (dir == 2 ? -1 : 1) * speed

p.vel = vel

}

}

}

update () {

let n = this.subFrames

// break up into n steps to make smooth lines

for (let p of this.particles) {

p.update(this.noise)

let step = p.vel.clone().mul(1 / n)

for (let i = 0; i < n; i++) {

this.buffer.drawPixel(p.pos.x, p.pos.y, p.col)

p.pos.add(step)

}

}

this.buffer.flush()

}

rainbowify (alpha) {

for (let p of this.particles) {

let c = p.pos.clone().add(this.buffer.ncenter),

a = (c.a + tau / 4) / tau,

rgb = hsl2rgb(a, 1, 0.5)

rgb.push(alpha)

p.col = rgb

}

}

colorify (col) {

for (let p of this.particles)

p.col = col.slice()

}

}

class ParticleNoise {

constructor (canvas) {

this.canvas = canvas

this.renderID = 0

}

generate (settings) {

let {

width, height, shape,

startOctave, endOctave,

numParticles, numFrames

} = settings

this.frame = 0

this.numFrames = numFrames

this.shape = shape

this.canvas.width = width

this.canvas.height = height

this.buffer = new CanvasBuffer(this.canvas)

this.noise = new Noise(settings)

this.particles = new ParticleSystem(settings, this.noise, this.buffer)

this.stop()

this.render()

}

render () {

this.frame++

this.particles.update()

// update progress bar at 30fps

if (this.frame == this.numFrames || this.frame % 2 == 0)

settings.progress = 100 * this.frame / this.numFrames

if (this.frame < this.numFrames)

this.renderID = window.requestAnimationFrame(this.render.bind(this))

else {

this.renderID = 0

if (settings.autogenerate)

this.generate(settings)

}

}

save () {

let rnd = new Array(5).fill(0).map(() => Math.floor(36 * Math.random()).toString(36)).join('')

let name = `noise-${this.shape}-${rnd}.png`

this.canvas.toBlob(blob => {

saveAs(blob, name)

})

}

stop () {

if (this.renderID) {

window.cancelAnimationFrame(this.renderID)

this.renderID = 0

settings.progress = 0

}

}

invert () {

this.stop()

let ctx = this.canvas.getContext('2d')

let img = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height)

for (let i = 0; i < img.data.length; i += 4) {

img.data[i + 0] = 255 - img.data[i + 0]

img.data[i + 1] = 255 - img.data[i + 1]

img.data[i + 2] = 255 - img.data[i + 2]

}

ctx.putImageData(img, 0, 0)

}

}

let PN = new ParticleNoise(document.getElementById('noise'))

let dpr = 2//window.devicePixelRatio

let settings = {

width: window.innerWidth * dpr,

height: window.innerHeight * dpr,

type: 0,

strength: 1,

startOctave: 5,

endOctave: 8,

numParticles: 10000,

numFrames: 300,

subFrames: 4,

progress: 0,

shape: 'triangle',

radius: 0.7,

colorType: 'rainbow',

color: [127, 0, 255],

alpha: 0.1,

velocity: 0,

speed: 3,

friction: 0.05,

autogenerate: true,

save: () => PN.save(),

stop: () => PN.stop(),

invert: () => PN.invert(),

generate: () => PN.generate(settings)

}

settings.generate()

let gui = new dat.GUI()

let rndr = gui.addFolder('rendering')

rndr.add(settings, 'width')

rndr.add(settings, 'height')

rndr.add(settings, 'numParticles', 10, 3e4, 1)

rndr.add(settings, 'numFrames', 1, 600, 1)

rndr.add(settings, 'subFrames', 1, 10, 1)

rndr.open()

let col = gui.addFolder('particles')

col.add(settings, 'shape', ['circle', 'triangle', 'triangle2', 'square', 'square2', 'hexagon', 'hexagon2', 'star', 'random'])

col.add(settings, 'radius', 0.1, 1)

col.add(settings, 'velocity', {'none': 0, 'outward': 1, 'inward': 2}).name('initial velocity')

col.add(settings, 'speed', 0.1, 10)

col.add(settings, 'friction', 0, 1)

col.add(settings, 'colorType', ['solid', 'rainbow'])

col.addColor(settings, 'color')

col.add(settings, 'alpha', 0, 1)

col.open()

let nz = gui.addFolder('noise')

nz.add(settings, 'type', {'ink': 0, 'loop': 1, 'streak': 2})

nz.add(settings, 'strength', 0.1, 10, 0.1)

nz.add(settings, 'startOctave', 0, 10, 1).onChange(update)

nz.add(settings, 'endOctave', 0, 11, 1).onChange(update)

nz.open()

gui.add(settings, 'invert')

gui.add(settings, 'save')

gui.add(settings, 'stop')

gui.add(settings, 'autogenerate')

gui.add(settings, 'progress', 0, 100, 1).listen()

gui.add(settings, 'generate')

function update() {

for (let c of nz.__controllers) {

switch (c.property) {

case "endOctave":

let min = settings.startOctave + 1;

if (c.getValue() < min)

c.setValue(min)

break;

}

}

}

html炫彩粒子的代码,HTML5 Canvas炫彩粒子特效生成器相关推荐

  1. html制作图片动画效果代码,HTML5 Canvas:制作动画特效

    编辑推荐: 本文来自于jquery之家 ,html5制作canvas动画的基本步骤,控制canvas动画和实例代码. 要在 HTML5 canvas 中绘制图像动画效果,你需要绘制出每一帧的图像,然后 ...

  2. 彩色圆圈的html代码,HTML5 Canvas彩色圆点粒子飘动动画特效

    js代码 var c = new Cbg({ container: ".canvas", //随机生成动画,默认无控制 control: "auto", //鼠 ...

  3. html5刮彩效果,HTML5 Canvas炫酷彩虹色波浪线动画特效代码

    效果图 JS源码 var c = document.querySelector('.c') , w , h , ctx = c.getContext('2d') , x0, y0, x, y, t = ...

  4. html 星空效果,html5 canvas炫酷旋转银河系星空背景特效

    这是一款html5 canvas炫酷旋转银河系星空背景特效.该特效通过canvas来绘制银河系星盘,并制作星系旋转的效果,非常炫酷. 使用方法 HTML结构 该旋转银河系星空背景特效的HTML结果只需 ...

  5. html5 canvas时光隧道3D粒子动画js特效

    下载地址 html5 canvas时光隧道3D粒子动画特效是一款非常酷炫的3D粒子时光穿梭视觉冲击动画特效. dd:

  6. HTML粒子碰撞烟花,html5 canvas漂亮的粒子烟花背景动画特效

    特效描述:html5 canvas 漂亮的粒子烟花 背景动画特效.html5 canvas漂亮的粒子烟花背景动画特效 代码结构 1. HTML代码 class Vector2 { constructo ...

  7. html 流动效果,html5 canvas流动的海浪特效

    特效描述:html5canvas 流动的海浪特效.html5 canvas流动的海浪特效 代码结构 1. 引入JS 2. HTML代码 'use strict'; var gui = new dat. ...

  8. html 画动画效果,html5 canvas绘制曲线动画特效

    特效描述:html5 canvas绘制 曲线动画特效. 代码结构 1. HTML代码 Balls Size Speed Delay Go! Presets: Atomic Flower Spiro Y ...

  9. html银河特效编码,html5 canvas银河星系动画特效

    特效描述:html5 canvas 银河星系动画特效.html5 canvas绘制闪闪发光移动的银河星系背景动画特效.(上传服务器正常演示,本地无法直接预览) 代码结构 1. 引入JS 2. HTML ...

  10. html5 运动轨迹绘画,html5 canvas行星运动轨迹动画特效

    特效描述:html5 canvas 行星运动 轨迹动画特效.html5运动轨迹,行星动画特效 代码结构 1. 引入JS 2. HTML代码 Your browser doesn't support c ...

最新文章

  1. latex中的\label标签的作用
  2. android 中测量高度和宽度,android获得屏幕高度和宽度(display中getSize(Point)方法使用)...
  3. swiper 定义放多少张图片_swiper轮播问题之二:默认显示3张图片,中间显示全部两边显示部分...
  4. facebook对话链接_并非里程碑! Facebook的100种语言互译模型夸大宣传遭质疑
  5. 使用application log 分析navigation target解析错误
  6. 我为什么要放弃RESTful,选择拥抱GraphQL?
  7. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第1节 基本概念_02maven依赖管理的概念
  8. C++——模板(超详细的模板解析)
  9. Funcode-贪吃蛇
  10. 变砖的平板怎样重装android,台电平板电脑刷机教程,小编教你台电平板电脑怎么刷机...
  11. 台式计算机时间不能同步,电脑时间同步不了怎么办
  12. win10下Linux双系统
  13. mapbox-gl:创建Marker
  14. 手游虚拟机服务器,手游剑侠情缘虚拟机镜像一键服务端+安卓客户端+远程工具+架设教程...
  15. 迷宫求解(深度优先)
  16. idea设置console控制台显示内容大小-小白实操记录
  17. 【时间序列分析】12.MA(q)模型
  18. 互联网金融:未来发展的囚徒困境
  19. 静态网页制作—制作“当当网首页”
  20. Java中%是什么意思?

热门文章

  1. 澳门上葡京综合度假村冬季献礼迎佳节
  2. Java并发编程系列(4)-线程安全及synchronized
  3. 【编译原理】【实验】THOMPSON 算法的实现
  4. 微调StyleGAN2模型(使用Google Colab)
  5. vue中设置外部链接
  6. Junit5 单元测试框架的使用
  7. [转]谈爬虫反爬虫套路
  8. spring boot 上传视频demo
  9. docker-nividia run 报错
  10. android地图方位角,根据两点经纬度,计算距离、方位角