@tsparticles/plugin-canvas-mask
Version:
tsParticles canvas mask plugin
299 lines (283 loc) • 14 kB
JavaScript
(function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
/* Plugin v4.3.2 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tsparticles/engine'), require('@tsparticles/canvas-utils')) :
typeof define === 'function' && define.amd ? define(['exports', '@tsparticles/engine', '@tsparticles/canvas-utils'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.plugins = global.__tsParticlesInternals.plugins || {}, global.__tsParticlesInternals.plugins.canvasMask = global.__tsParticlesInternals.plugins.canvasMask || {}), global.__tsParticlesInternals.engine, global.__tsParticlesInternals.canvas.utils));
})(this, (function (exports, engine, canvasUtils) { 'use strict';
class CanvasMaskOverride {
color = true;
opacity = false;
load(data) {
if (engine.isNull(data)) {
return;
}
engine.loadProperty(this, "color", data.color);
engine.loadProperty(this, "opacity", data.opacity);
}
}
const minAlpha = 0;
class CanvasMaskPixels {
offset = 4;
filter = (pixel) => pixel.a > minAlpha;
load(data) {
if (engine.isNull(data)) {
return;
}
if (data.filter !== undefined) {
if (engine.isString(data.filter)) {
if (data.filter in globalThis) {
const filter = globalThis[data.filter];
if (engine.isFunction(filter)) {
this.filter = filter;
}
}
}
else {
this.filter = data.filter;
}
}
engine.loadProperty(this, "offset", data.offset);
}
}
class ImageMask {
src = "";
load(data) {
if (engine.isNull(data)) {
return;
}
engine.loadProperty(this, "src", data.src);
}
}
class FontTextMask {
family = "sans-serif";
size = 100;
style = "";
variant = "";
weight = "";
load(data) {
if (engine.isNull(data)) {
return;
}
engine.loadProperty(this, "family", data.family);
engine.loadProperty(this, "size", data.size);
engine.loadProperty(this, "style", data.style);
engine.loadProperty(this, "variant", data.variant);
engine.loadProperty(this, "weight", data.weight);
}
}
class TextMaskLine {
separator = "\n";
spacing = 10;
load(data) {
if (engine.isNull(data)) {
return;
}
engine.loadProperty(this, "separator", data.separator);
engine.loadProperty(this, "spacing", data.spacing);
}
}
class TextMask {
color = "#000000";
fill = true;
font = new FontTextMask();
lines = new TextMaskLine();
text = "";
load(data) {
if (engine.isNull(data)) {
return;
}
engine.loadProperty(this, "color", data.color);
engine.loadProperty(this, "fill", data.fill);
this.font.load(data.font);
this.lines.load(data.lines);
engine.loadProperty(this, "text", data.text);
}
}
class CanvasMask {
element;
enable = false;
image;
override = new CanvasMaskOverride();
pixels = new CanvasMaskPixels();
position;
scale = 1;
selector;
text;
constructor() {
this.position = {
x: 50,
y: 50,
};
}
load(data) {
if (engine.isNull(data)) {
return;
}
if (data.element !== undefined && data.element instanceof HTMLCanvasElement) {
this.element = data.element;
}
engine.loadProperty(this, "enable", data.enable);
if (data.image) {
this.image ??= new ImageMask();
this.image.load(data.image);
}
this.pixels.load(data.pixels);
if (data.position) {
this.position = {
x: data.position.x ?? this.position.x,
y: data.position.y ?? this.position.y,
};
}
this.override.load(data.override);
engine.loadProperty(this, "scale", data.scale);
engine.loadProperty(this, "selector", data.selector);
if (data.text) {
this.text ??= new TextMask();
this.text.load(data.text);
}
}
}
class CanvasMaskPlugin {
id = "canvas-mask";
async getPlugin(container) {
const { CanvasMaskPluginInstance } = await Promise.resolve().then(function () { return CanvasMaskPluginInstance$1; });
return new CanvasMaskPluginInstance(container);
}
loadOptions(_container, options, source) {
if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
return;
}
let canvasMaskOptions = options.canvasMask;
if (canvasMaskOptions?.load === undefined) {
options.canvasMask = canvasMaskOptions = new CanvasMask();
}
canvasMaskOptions.load(source?.canvasMask);
}
needsPlugin(options) {
return options?.canvasMask?.enable ?? false;
}
}
async function loadCanvasMaskPlugin(engine) {
engine.checkVersion("4.3.2");
await engine.pluginManager.register(e => {
e.pluginManager.addPlugin(new CanvasMaskPlugin());
});
}
const globalObject = globalThis;
globalObject.__tsParticlesInternals = globalObject.__tsParticlesInternals ?? {};
globalObject.loadCanvasMaskPlugin = loadCanvasMaskPlugin;
function addParticlesFromCanvasPixels(container, data, position, scale, override, filter) {
const { height, width } = data, numPixels = height * width, indexArray = shuffle(range(numPixels)), maxParticles = Math.min(numPixels, container.actualOptions.particles.number.value), canvasSize = container.canvas.size;
let selectedPixels = 0;
const positionOffset = {
x: (canvasSize.width * position.x) / engine.percentDenominator - width * scale * engine.half,
y: (canvasSize.height * position.y) / engine.percentDenominator - height * scale * engine.half,
};
while (selectedPixels < maxParticles && indexArray.length) {
const defaultIndex = 0, nextIndex = indexArray.pop() ?? defaultIndex, pixelPos = {
x: nextIndex % width,
y: Math.floor(nextIndex / width),
}, row = data.pixels[pixelPos.y];
if (!row) {
continue;
}
const pixel = row[pixelPos.x];
if (!pixel) {
continue;
}
const shouldCreateParticle = filter(pixel);
if (!shouldCreateParticle) {
continue;
}
const pos = {
x: pixelPos.x * scale + positionOffset.x,
y: pixelPos.y * scale + positionOffset.y,
}, pOptions = {};
if (override.color) {
pOptions.paint = {
fill: {
color: {
value: pixel,
},
enable: true,
},
};
}
if (override.opacity) {
pOptions["opacity"] = {
value: pixel.a,
};
}
container.particles.addParticle(pos, pOptions);
selectedPixels++;
}
}
function shuffle(array) {
const lengthOffset = 1, minIndex = 0;
for (let currentIndex = array.length - lengthOffset; currentIndex >= minIndex; currentIndex--) {
const randomIndex = Math.floor(engine.getRandom() * currentIndex), currentItem = array[currentIndex], randomItem = array[randomIndex];
if (randomItem === currentItem) {
continue;
}
if (randomItem === undefined || currentItem === undefined) {
continue;
}
array[currentIndex] = randomItem;
array[randomIndex] = currentItem;
}
return array;
}
const range = (n) => [...Array(n).keys()];
class CanvasMaskPluginInstance {
#container;
constructor(container) {
this.#container = container;
}
async init() {
const container = this.#container, options = container.actualOptions.canvasMask;
if (!options?.enable) {
return;
}
let pixelData = {
pixels: [],
height: 0,
width: 0,
};
const offset = options.pixels.offset;
if (options.image) {
const url = options.image.src;
if (!url) {
return;
}
pixelData = await canvasUtils.getImageData(url, offset, container.canvas.render.settings);
}
else if (options.text) {
const textOptions = options.text, data = canvasUtils.getTextData(textOptions, offset, textOptions.fill, container.canvas.render.settings);
if (engine.isNull(data)) {
return;
}
pixelData = data;
}
else if (options.element ?? options.selector) {
const canvas = options.element ?? (options.selector && engine.safeDocument().querySelector(options.selector));
if (!canvas) {
return;
}
const context = canvas.getContext("2d", container.canvas.render.settings);
if (!context) {
return;
}
pixelData = canvasUtils.getCanvasImageData(context, canvas, offset);
}
addParticlesFromCanvasPixels(container, pixelData, options.position, options.scale, options.override, options.pixels.filter);
}
}
var CanvasMaskPluginInstance$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
CanvasMaskPluginInstance: CanvasMaskPluginInstance
});
exports.loadCanvasMaskPlugin = loadCanvasMaskPlugin;
}));
Object.assign(globalThis.window || globalThis, { loadCanvasMaskPlugin: (globalThis.__tsParticlesInternals.plugins.canvasMask || {}).loadCanvasMaskPlugin });
delete (globalThis.window || globalThis).tsparticlesInternalExports;