@tsparticles/plugin-emitters-shape-canvas
Version:
tsParticles emitters shape canvas plugin
92 lines (91 loc) • 3.28 kB
JavaScript
import { EmitterShapeBase } from "@tsparticles/plugin-emitters";
import { getRandom, isFunction, isNull, isString, } from "@tsparticles/engine";
import { getCanvasImageData, getImageData, getTextData } from "./utils.js";
const maxRetries = 100, half = 0.5;
export class EmittersCanvasShape extends EmitterShapeBase {
constructor(position, size, fill, options) {
super(position, size, fill, options);
const filter = options.filter, minAlpha = 0;
let filterFunc = (pixel) => pixel.a > minAlpha;
if (filter !== undefined) {
if (isString(filter)) {
if (Object.hasOwn(window, filter)) {
const wndFilter = window[filter];
if (isFunction(wndFilter)) {
filterFunc = wndFilter;
}
}
}
else {
filterFunc = filter;
}
}
this.filter = filterFunc;
this.scale = options.scale;
this.pixelData = {
pixels: [],
height: 0,
width: 0,
};
}
async init() {
let pixelData;
const options = this.options, selector = options.selector, pixels = options.pixels, image = options.image, element = options.element, text = options.text, offset = pixels.offset;
if (image) {
const url = image.src;
if (!url) {
return;
}
pixelData = await getImageData(url, offset);
}
else if (text) {
const data = getTextData(text, offset, this.fill);
if (isNull(data)) {
return;
}
pixelData = data;
}
else if (element ?? selector) {
const canvas = element ?? (selector && document.querySelector(selector));
if (!canvas) {
return;
}
const context = canvas.getContext("2d");
if (!context) {
return;
}
pixelData = getCanvasImageData(context, canvas, offset);
}
if (!pixelData) {
return;
}
this.pixelData = pixelData;
}
randomPosition() {
const { height, width } = this.pixelData, data = this.pixelData, position = this.position, scale = this.scale, positionOffset = {
x: position.x - width * scale * half,
y: position.y - height * scale * half,
};
for (let i = 0; i < maxRetries; i++) {
const nextIndex = Math.floor(getRandom() * width * height), pixelPos = {
x: nextIndex % width,
y: Math.floor(nextIndex / width),
}, pixel = data.pixels[pixelPos.y][pixelPos.x], shouldCreateParticle = this.filter(pixel);
if (!shouldCreateParticle) {
continue;
}
return {
position: {
x: pixelPos.x * scale + positionOffset.x,
y: pixelPos.y * scale + positionOffset.y,
},
color: { ...pixel },
opacity: pixel.a,
};
}
return null;
}
resize(position, size) {
super.resize(position, size);
}
}