UNPKG

@tsparticles/path-perlin-noise

Version:

tsParticles perlin noise path

118 lines (117 loc) 4.56 kB
import { Vector, deepExtend, getRandom, } from "@tsparticles/engine"; import { PerlinNoise } from "@tsparticles/perlin-noise"; const double = 2, doublePI = Math.PI * double, defaultOptions = { draw: false, size: 20, increment: 0.004, columns: 0, rows: 0, width: 0, height: 0, factor: { angle: 0.02, length: 0.01, }, offset: { x: 40000, y: 40000, }, }; export class PerlinNoiseGenerator { constructor() { this._calculateField = () => { const { field, noiseGen, options } = this, lengthFactor = options.factor.length, angleFactor = options.factor.angle; for (let x = 0; x < options.columns; x++) { const column = field[x]; for (let y = 0; y < options.rows; y++) { const cell = column[y]; cell.length = noiseGen.noise3d(x * lengthFactor + options.offset.x, y * lengthFactor + options.offset.y, this.noiseZ); cell.angle = noiseGen.noise3d(x * angleFactor, y * angleFactor, this.noiseZ) * doublePI; } } }; this._drawField = ctx => { const { field, options } = this; for (let x = 0; x < options.columns; x++) { const column = field[x]; for (let y = 0; y < options.rows; y++) { const cell = column[y], { angle, length } = cell; ctx.setTransform(1, 0, 0, 1, x * this.options.size, y * this.options.size); ctx.rotate(angle); ctx.strokeStyle = "white"; ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(0, this.options.size * length); ctx.stroke(); ctx.setTransform(1, 0, 0, 1, 0, 0); } } }; this._initField = () => { const { columns, rows } = this.options; this.field = new Array(columns); for (let x = 0; x < columns; x++) { this.field[x] = new Array(rows); for (let y = 0; y < rows; y++) { this.field[x][y] = Vector.origin; } } }; this.noiseGen = new PerlinNoise(); this.field = []; this.noiseZ = 0; this.options = deepExtend({}, defaultOptions); } generate(particle) { const pos = particle.getPosition(), { size } = this.options, point = { x: Math.max(Math.floor(pos.x / size), 0), y: Math.max(Math.floor(pos.y / size), 0), }, { field } = this; return !field?.[point.x]?.[point.y] ? Vector.origin : field[point.x][point.y].copy(); } init(container) { this.container = container; this._setup(); } reset() { } update() { if (!this.container) { return; } this._calculateField(); this.noiseZ += this.options.increment; if (this.options.draw) { this.container.canvas.draw(ctx => this._drawField(ctx)); } } _resetField() { const container = this.container; if (!container) { return; } const sourceOptions = container.actualOptions.particles.move.path.options, { options } = this; options.size = sourceOptions.size > 0 ? sourceOptions.size : defaultOptions.size; options.increment = sourceOptions.increment > 0 ? sourceOptions.increment : defaultOptions.increment; options.draw = !!sourceOptions.draw; const offset = sourceOptions.offset; options.offset.x = offset?.x ?? defaultOptions.offset.x; options.offset.y = offset?.y ?? defaultOptions.offset.y; const factor = sourceOptions.factor; options.factor.angle = factor?.angle ?? defaultOptions.factor.angle; options.factor.length = factor?.length ?? defaultOptions.factor.length; options.width = container.canvas.size.width; options.height = container.canvas.size.height; this.options.seed = sourceOptions.seed; this.noiseGen.seed(this.options.seed ?? getRandom()); options.columns = Math.floor(this.options.width / this.options.size) + 1; options.rows = Math.floor(this.options.height / this.options.size) + 1; this._initField(); } _setup() { this.noiseZ = 0; this._resetField(); window.addEventListener("resize", () => this._resetField()); } }