mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-08 02:49:56 +00:00
First commit
This commit is contained in:
parent
c0615e20ec
commit
8a1ec1d055
@ -6,7 +6,8 @@
|
||||
"tiddlywiki/railroad",
|
||||
"tiddlywiki/evernote",
|
||||
"tiddlywiki/internals",
|
||||
"tiddlywiki/menubar"
|
||||
"tiddlywiki/menubar",
|
||||
"tiddlywiki/confetti"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
|
15
plugins/tiddlywiki/confetti/files/LICENSE
Normal file
15
plugins/tiddlywiki/confetti/files/LICENSE
Normal file
@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020, Kiril Vatev
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
626
plugins/tiddlywiki/confetti/files/confetti.js
Normal file
626
plugins/tiddlywiki/confetti/files/confetti.js
Normal file
@ -0,0 +1,626 @@
|
||||
(function main(global, module, isWorker, workerSize) {
|
||||
var canUseWorker = !!(
|
||||
global.Worker &&
|
||||
global.Blob &&
|
||||
global.Promise &&
|
||||
global.OffscreenCanvas &&
|
||||
global.OffscreenCanvasRenderingContext2D &&
|
||||
global.HTMLCanvasElement &&
|
||||
global.HTMLCanvasElement.prototype.transferControlToOffscreen &&
|
||||
global.URL &&
|
||||
global.URL.createObjectURL);
|
||||
|
||||
function noop() {}
|
||||
|
||||
// create a promise if it exists, otherwise, just
|
||||
// call the function directly
|
||||
function promise(func) {
|
||||
var ModulePromise = module.exports.Promise;
|
||||
var Prom = ModulePromise !== void 0 ? ModulePromise : global.Promise;
|
||||
|
||||
if (typeof Prom === 'function') {
|
||||
return new Prom(func);
|
||||
}
|
||||
|
||||
func(noop, noop);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var raf = (function () {
|
||||
var TIME = Math.floor(1000 / 60);
|
||||
var frame, cancel;
|
||||
var frames = {};
|
||||
var lastFrameTime = 0;
|
||||
|
||||
if (typeof requestAnimationFrame === 'function' && typeof cancelAnimationFrame === 'function') {
|
||||
frame = function (cb) {
|
||||
var id = Math.random();
|
||||
|
||||
frames[id] = requestAnimationFrame(function onFrame(time) {
|
||||
if (lastFrameTime === time || lastFrameTime + TIME - 1 < time) {
|
||||
lastFrameTime = time;
|
||||
delete frames[id];
|
||||
|
||||
cb();
|
||||
} else {
|
||||
frames[id] = requestAnimationFrame(onFrame);
|
||||
}
|
||||
});
|
||||
|
||||
return id;
|
||||
};
|
||||
cancel = function (id) {
|
||||
if (frames[id]) {
|
||||
cancelAnimationFrame(frames[id]);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
frame = function (cb) {
|
||||
return setTimeout(cb, TIME);
|
||||
};
|
||||
cancel = function (timer) {
|
||||
return clearTimeout(timer);
|
||||
};
|
||||
}
|
||||
|
||||
return { frame: frame, cancel: cancel };
|
||||
}());
|
||||
|
||||
var getWorker = (function () {
|
||||
var worker;
|
||||
var prom;
|
||||
var resolves = {};
|
||||
|
||||
function decorate(worker) {
|
||||
function execute(options, callback) {
|
||||
worker.postMessage({ options: options || {}, callback: callback });
|
||||
}
|
||||
worker.init = function initWorker(canvas) {
|
||||
var offscreen = canvas.transferControlToOffscreen();
|
||||
worker.postMessage({ canvas: offscreen }, [offscreen]);
|
||||
};
|
||||
|
||||
worker.fire = function fireWorker(options, size, done) {
|
||||
if (prom) {
|
||||
execute(options, null);
|
||||
return prom;
|
||||
}
|
||||
|
||||
var id = Math.random().toString(36).slice(2);
|
||||
|
||||
prom = promise(function (resolve) {
|
||||
function workerDone(msg) {
|
||||
if (msg.data.callback !== id) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete resolves[id];
|
||||
worker.removeEventListener('message', workerDone);
|
||||
|
||||
prom = null;
|
||||
done();
|
||||
resolve();
|
||||
}
|
||||
|
||||
worker.addEventListener('message', workerDone);
|
||||
execute(options, id);
|
||||
|
||||
resolves[id] = workerDone.bind(null, { data: { callback: id }});
|
||||
});
|
||||
|
||||
return prom;
|
||||
};
|
||||
|
||||
worker.reset = function resetWorker() {
|
||||
worker.postMessage({ reset: true });
|
||||
|
||||
for (var id in resolves) {
|
||||
resolves[id]();
|
||||
delete resolves[id];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return function () {
|
||||
if (worker) {
|
||||
return worker;
|
||||
}
|
||||
|
||||
if (!isWorker && canUseWorker) {
|
||||
var code = [
|
||||
'var CONFETTI, SIZE = {}, module = {};',
|
||||
'(' + main.toString() + ')(this, module, true, SIZE);',
|
||||
'onmessage = function(msg) {',
|
||||
' if (msg.data.options) {',
|
||||
' CONFETTI(msg.data.options).then(function () {',
|
||||
' if (msg.data.callback) {',
|
||||
' postMessage({ callback: msg.data.callback });',
|
||||
' }',
|
||||
' });',
|
||||
' } else if (msg.data.reset) {',
|
||||
' CONFETTI && CONFETTI.reset();',
|
||||
' } else if (msg.data.resize) {',
|
||||
' SIZE.width = msg.data.resize.width;',
|
||||
' SIZE.height = msg.data.resize.height;',
|
||||
' } else if (msg.data.canvas) {',
|
||||
' SIZE.width = msg.data.canvas.width;',
|
||||
' SIZE.height = msg.data.canvas.height;',
|
||||
' CONFETTI = module.exports.create(msg.data.canvas);',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n');
|
||||
try {
|
||||
worker = new Worker(URL.createObjectURL(new Blob([code])));
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
typeof console !== undefined && typeof console.warn === 'function' ? console.warn('🎊 Could not load worker', e) : null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
decorate(worker);
|
||||
}
|
||||
|
||||
return worker;
|
||||
};
|
||||
})();
|
||||
|
||||
var defaults = {
|
||||
particleCount: 50,
|
||||
angle: 90,
|
||||
spread: 45,
|
||||
startVelocity: 45,
|
||||
decay: 0.9,
|
||||
gravity: 1,
|
||||
drift: 0,
|
||||
ticks: 200,
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
shapes: ['square', 'circle'],
|
||||
zIndex: 100,
|
||||
colors: [
|
||||
'#26ccff',
|
||||
'#a25afd',
|
||||
'#ff5e7e',
|
||||
'#88ff5a',
|
||||
'#fcff42',
|
||||
'#ffa62d',
|
||||
'#ff36ff'
|
||||
],
|
||||
// probably should be true, but back-compat
|
||||
disableForReducedMotion: false,
|
||||
scalar: 1
|
||||
};
|
||||
|
||||
function convert(val, transform) {
|
||||
return transform ? transform(val) : val;
|
||||
}
|
||||
|
||||
function isOk(val) {
|
||||
return !(val === null || val === undefined);
|
||||
}
|
||||
|
||||
function prop(options, name, transform) {
|
||||
return convert(
|
||||
options && isOk(options[name]) ? options[name] : defaults[name],
|
||||
transform
|
||||
);
|
||||
}
|
||||
|
||||
function onlyPositiveInt(number){
|
||||
return number < 0 ? 0 : Math.floor(number);
|
||||
}
|
||||
|
||||
function randomInt(min, max) {
|
||||
// [min, max)
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
function toDecimal(str) {
|
||||
return parseInt(str, 16);
|
||||
}
|
||||
|
||||
function colorsToRgb(colors) {
|
||||
return colors.map(hexToRgb);
|
||||
}
|
||||
|
||||
function hexToRgb(str) {
|
||||
var val = String(str).replace(/[^0-9a-f]/gi, '');
|
||||
|
||||
if (val.length < 6) {
|
||||
val = val[0]+val[0]+val[1]+val[1]+val[2]+val[2];
|
||||
}
|
||||
|
||||
return {
|
||||
r: toDecimal(val.substring(0,2)),
|
||||
g: toDecimal(val.substring(2,4)),
|
||||
b: toDecimal(val.substring(4,6))
|
||||
};
|
||||
}
|
||||
|
||||
function getOrigin(options) {
|
||||
var origin = prop(options, 'origin', Object);
|
||||
origin.x = prop(origin, 'x', Number);
|
||||
origin.y = prop(origin, 'y', Number);
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
function setCanvasWindowSize(canvas) {
|
||||
canvas.width = document.documentElement.clientWidth;
|
||||
canvas.height = document.documentElement.clientHeight;
|
||||
}
|
||||
|
||||
function setCanvasRectSize(canvas) {
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
|
||||
function getCanvas(zIndex) {
|
||||
var canvas = document.createElement('canvas');
|
||||
|
||||
canvas.style.position = 'fixed';
|
||||
canvas.style.top = '0px';
|
||||
canvas.style.left = '0px';
|
||||
canvas.style.pointerEvents = 'none';
|
||||
canvas.style.zIndex = zIndex;
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function ellipse(context, x, y, radiusX, radiusY, rotation, startAngle, endAngle, antiClockwise) {
|
||||
context.save();
|
||||
context.translate(x, y);
|
||||
context.rotate(rotation);
|
||||
context.scale(radiusX, radiusY);
|
||||
context.arc(0, 0, 1, startAngle, endAngle, antiClockwise);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
function randomPhysics(opts) {
|
||||
var radAngle = opts.angle * (Math.PI / 180);
|
||||
var radSpread = opts.spread * (Math.PI / 180);
|
||||
|
||||
return {
|
||||
x: opts.x,
|
||||
y: opts.y,
|
||||
wobble: Math.random() * 10,
|
||||
wobbleSpeed: Math.min(0.11, Math.random() * 0.1 + 0.05),
|
||||
velocity: (opts.startVelocity * 0.5) + (Math.random() * opts.startVelocity),
|
||||
angle2D: -radAngle + ((0.5 * radSpread) - (Math.random() * radSpread)),
|
||||
tiltAngle: (Math.random() * (0.75 - 0.25) + 0.25) * Math.PI,
|
||||
color: opts.color,
|
||||
shape: opts.shape,
|
||||
tick: 0,
|
||||
totalTicks: opts.ticks,
|
||||
decay: opts.decay,
|
||||
drift: opts.drift,
|
||||
random: Math.random() + 2,
|
||||
tiltSin: 0,
|
||||
tiltCos: 0,
|
||||
wobbleX: 0,
|
||||
wobbleY: 0,
|
||||
gravity: opts.gravity * 3,
|
||||
ovalScalar: 0.6,
|
||||
scalar: opts.scalar
|
||||
};
|
||||
}
|
||||
|
||||
function updateFetti(context, fetti) {
|
||||
fetti.x += Math.cos(fetti.angle2D) * fetti.velocity + fetti.drift;
|
||||
fetti.y += Math.sin(fetti.angle2D) * fetti.velocity + fetti.gravity;
|
||||
fetti.wobble += fetti.wobbleSpeed;
|
||||
fetti.velocity *= fetti.decay;
|
||||
fetti.tiltAngle += 0.1;
|
||||
fetti.tiltSin = Math.sin(fetti.tiltAngle);
|
||||
fetti.tiltCos = Math.cos(fetti.tiltAngle);
|
||||
fetti.random = Math.random() + 2;
|
||||
fetti.wobbleX = fetti.x + ((10 * fetti.scalar) * Math.cos(fetti.wobble));
|
||||
fetti.wobbleY = fetti.y + ((10 * fetti.scalar) * Math.sin(fetti.wobble));
|
||||
|
||||
var progress = (fetti.tick++) / fetti.totalTicks;
|
||||
|
||||
var x1 = fetti.x + (fetti.random * fetti.tiltCos);
|
||||
var y1 = fetti.y + (fetti.random * fetti.tiltSin);
|
||||
var x2 = fetti.wobbleX + (fetti.random * fetti.tiltCos);
|
||||
var y2 = fetti.wobbleY + (fetti.random * fetti.tiltSin);
|
||||
|
||||
context.fillStyle = 'rgba(' + fetti.color.r + ', ' + fetti.color.g + ', ' + fetti.color.b + ', ' + (1 - progress) + ')';
|
||||
context.beginPath();
|
||||
|
||||
if (fetti.shape === 'circle') {
|
||||
context.ellipse ?
|
||||
context.ellipse(fetti.x, fetti.y, Math.abs(x2 - x1) * fetti.ovalScalar, Math.abs(y2 - y1) * fetti.ovalScalar, Math.PI / 10 * fetti.wobble, 0, 2 * Math.PI) :
|
||||
ellipse(context, fetti.x, fetti.y, Math.abs(x2 - x1) * fetti.ovalScalar, Math.abs(y2 - y1) * fetti.ovalScalar, Math.PI / 10 * fetti.wobble, 0, 2 * Math.PI);
|
||||
} else if (fetti.shape === 'star') {
|
||||
var rot = Math.PI / 2 * 3;
|
||||
var innerRadius = 4 * fetti.scalar;
|
||||
var outerRadius = 8 * fetti.scalar;
|
||||
var x = fetti.x;
|
||||
var y = fetti.y;
|
||||
var spikes = 5;
|
||||
var step = Math.PI / spikes;
|
||||
|
||||
while (spikes--) {
|
||||
x = fetti.x + Math.cos(rot) * outerRadius;
|
||||
y = fetti.y + Math.sin(rot) * outerRadius;
|
||||
context.lineTo(x, y);
|
||||
rot += step;
|
||||
|
||||
x = fetti.x + Math.cos(rot) * innerRadius;
|
||||
y = fetti.y + Math.sin(rot) * innerRadius;
|
||||
context.lineTo(x, y);
|
||||
rot += step;
|
||||
}
|
||||
} else {
|
||||
context.moveTo(Math.floor(fetti.x), Math.floor(fetti.y));
|
||||
context.lineTo(Math.floor(fetti.wobbleX), Math.floor(y1));
|
||||
context.lineTo(Math.floor(x2), Math.floor(y2));
|
||||
context.lineTo(Math.floor(x1), Math.floor(fetti.wobbleY));
|
||||
}
|
||||
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
return fetti.tick < fetti.totalTicks;
|
||||
}
|
||||
|
||||
function animate(canvas, fettis, resizer, size, done) {
|
||||
var animatingFettis = fettis.slice();
|
||||
var context = canvas.getContext('2d');
|
||||
var animationFrame;
|
||||
var destroy;
|
||||
|
||||
var prom = promise(function (resolve) {
|
||||
function onDone() {
|
||||
animationFrame = destroy = null;
|
||||
|
||||
context.clearRect(0, 0, size.width, size.height);
|
||||
|
||||
done();
|
||||
resolve();
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (isWorker && !(size.width === workerSize.width && size.height === workerSize.height)) {
|
||||
size.width = canvas.width = workerSize.width;
|
||||
size.height = canvas.height = workerSize.height;
|
||||
}
|
||||
|
||||
if (!size.width && !size.height) {
|
||||
resizer(canvas);
|
||||
size.width = canvas.width;
|
||||
size.height = canvas.height;
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, size.width, size.height);
|
||||
|
||||
animatingFettis = animatingFettis.filter(function (fetti) {
|
||||
return updateFetti(context, fetti);
|
||||
});
|
||||
|
||||
if (animatingFettis.length) {
|
||||
animationFrame = raf.frame(update);
|
||||
} else {
|
||||
onDone();
|
||||
}
|
||||
}
|
||||
|
||||
animationFrame = raf.frame(update);
|
||||
destroy = onDone;
|
||||
});
|
||||
|
||||
return {
|
||||
addFettis: function (fettis) {
|
||||
animatingFettis = animatingFettis.concat(fettis);
|
||||
|
||||
return prom;
|
||||
},
|
||||
canvas: canvas,
|
||||
promise: prom,
|
||||
reset: function () {
|
||||
if (animationFrame) {
|
||||
raf.cancel(animationFrame);
|
||||
}
|
||||
|
||||
if (destroy) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function confettiCannon(canvas, globalOpts) {
|
||||
var isLibCanvas = !canvas;
|
||||
var allowResize = !!prop(globalOpts || {}, 'resize');
|
||||
var globalDisableForReducedMotion = prop(globalOpts, 'disableForReducedMotion', Boolean);
|
||||
var shouldUseWorker = canUseWorker && !!prop(globalOpts || {}, 'useWorker');
|
||||
var worker = shouldUseWorker ? getWorker() : null;
|
||||
var resizer = isLibCanvas ? setCanvasWindowSize : setCanvasRectSize;
|
||||
var initialized = (canvas && worker) ? !!canvas.__confetti_initialized : false;
|
||||
var preferLessMotion = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion)').matches;
|
||||
var animationObj;
|
||||
|
||||
function fireLocal(options, size, done) {
|
||||
var particleCount = prop(options, 'particleCount', onlyPositiveInt);
|
||||
var angle = prop(options, 'angle', Number);
|
||||
var spread = prop(options, 'spread', Number);
|
||||
var startVelocity = prop(options, 'startVelocity', Number);
|
||||
var decay = prop(options, 'decay', Number);
|
||||
var gravity = prop(options, 'gravity', Number);
|
||||
var drift = prop(options, 'drift', Number);
|
||||
var colors = prop(options, 'colors', colorsToRgb);
|
||||
var ticks = prop(options, 'ticks', Number);
|
||||
var shapes = prop(options, 'shapes');
|
||||
var scalar = prop(options, 'scalar');
|
||||
var origin = getOrigin(options);
|
||||
|
||||
var temp = particleCount;
|
||||
var fettis = [];
|
||||
|
||||
var startX = canvas.width * origin.x;
|
||||
var startY = canvas.height * origin.y;
|
||||
|
||||
while (temp--) {
|
||||
fettis.push(
|
||||
randomPhysics({
|
||||
x: startX,
|
||||
y: startY,
|
||||
angle: angle,
|
||||
spread: spread,
|
||||
startVelocity: startVelocity,
|
||||
color: colors[temp % colors.length],
|
||||
shape: shapes[randomInt(0, shapes.length)],
|
||||
ticks: ticks,
|
||||
decay: decay,
|
||||
gravity: gravity,
|
||||
drift: drift,
|
||||
scalar: scalar
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// if we have a previous canvas already animating,
|
||||
// add to it
|
||||
if (animationObj) {
|
||||
return animationObj.addFettis(fettis);
|
||||
}
|
||||
|
||||
animationObj = animate(canvas, fettis, resizer, size , done);
|
||||
|
||||
return animationObj.promise;
|
||||
}
|
||||
|
||||
function fire(options) {
|
||||
var disableForReducedMotion = globalDisableForReducedMotion || prop(options, 'disableForReducedMotion', Boolean);
|
||||
var zIndex = prop(options, 'zIndex', Number);
|
||||
|
||||
if (disableForReducedMotion && preferLessMotion) {
|
||||
return promise(function (resolve) {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
if (isLibCanvas && animationObj) {
|
||||
// use existing canvas from in-progress animation
|
||||
canvas = animationObj.canvas;
|
||||
} else if (isLibCanvas && !canvas) {
|
||||
// create and initialize a new canvas
|
||||
canvas = getCanvas(zIndex);
|
||||
document.body.appendChild(canvas);
|
||||
}
|
||||
|
||||
if (allowResize && !initialized) {
|
||||
// initialize the size of a user-supplied canvas
|
||||
resizer(canvas);
|
||||
}
|
||||
|
||||
var size = {
|
||||
width: canvas.width,
|
||||
height: canvas.height
|
||||
};
|
||||
|
||||
if (worker && !initialized) {
|
||||
worker.init(canvas);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
if (worker) {
|
||||
canvas.__confetti_initialized = true;
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
if (worker) {
|
||||
// TODO this really shouldn't be immediate, because it is expensive
|
||||
var obj = {
|
||||
getBoundingClientRect: function () {
|
||||
if (!isLibCanvas) {
|
||||
return canvas.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
resizer(obj);
|
||||
|
||||
worker.postMessage({
|
||||
resize: {
|
||||
width: obj.width,
|
||||
height: obj.height
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// don't actually query the size here, since this
|
||||
// can execute frequently and rapidly
|
||||
size.width = size.height = null;
|
||||
}
|
||||
|
||||
function done() {
|
||||
animationObj = null;
|
||||
|
||||
if (allowResize) {
|
||||
global.removeEventListener('resize', onResize);
|
||||
}
|
||||
|
||||
if (isLibCanvas && canvas) {
|
||||
document.body.removeChild(canvas);
|
||||
canvas = null;
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowResize) {
|
||||
global.addEventListener('resize', onResize, false);
|
||||
}
|
||||
|
||||
if (worker) {
|
||||
return worker.fire(options, size, done);
|
||||
}
|
||||
|
||||
return fireLocal(options, size, done);
|
||||
}
|
||||
|
||||
fire.reset = function () {
|
||||
if (worker) {
|
||||
worker.reset();
|
||||
}
|
||||
|
||||
if (animationObj) {
|
||||
animationObj.reset();
|
||||
}
|
||||
};
|
||||
|
||||
return fire;
|
||||
}
|
||||
|
||||
// Make default export lazy to defer worker creation until called.
|
||||
var defaultFire;
|
||||
function getDefaultFire() {
|
||||
if (!defaultFire) {
|
||||
defaultFire = confettiCannon(null, { useWorker: true, resize: true });
|
||||
}
|
||||
return defaultFire;
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
return getDefaultFire().apply(this, arguments);
|
||||
};
|
||||
module.exports.reset = function() {
|
||||
getDefaultFire().reset();
|
||||
};
|
||||
module.exports.create = confettiCannon;
|
||||
}((function () {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window;
|
||||
}
|
||||
|
||||
if (typeof self !== 'undefined') {
|
||||
return self;
|
||||
}
|
||||
|
||||
return this || {};
|
||||
})(), module, false));
|
20
plugins/tiddlywiki/confetti/files/tiddlywiki.files
Normal file
20
plugins/tiddlywiki/confetti/files/tiddlywiki.files
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "confetti.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "$:/plugins/tiddlywiki/confetti/confetti.js",
|
||||
"module-type": "library"
|
||||
},
|
||||
"prefix": "",
|
||||
"suffix": ""
|
||||
},{
|
||||
"file": "LICENSE",
|
||||
"fields": {
|
||||
"type": "text/plain",
|
||||
"title": "$:/plugins/tiddlywiki/confetti/license"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
6
plugins/tiddlywiki/confetti/plugin.info
Normal file
6
plugins/tiddlywiki/confetti/plugin.info
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "$:/plugins/tiddlywiki/confetti",
|
||||
"name": "Confetti",
|
||||
"description": "Animated confetti effect",
|
||||
"list": "readme"
|
||||
}
|
39
plugins/tiddlywiki/confetti/readme.tid
Normal file
39
plugins/tiddlywiki/confetti/readme.tid
Normal file
@ -0,0 +1,39 @@
|
||||
title: $:/plugins/tiddlywiki/confetti/readme
|
||||
|
||||
! Introduction
|
||||
|
||||
This plugin adds a programmable confetti cannon to your TiddlyWiki. It is based on https://www.kirilv.com/canvas-confetti/ by Kiril Vatev.
|
||||
|
||||
! Usage
|
||||
|
||||
The confetti cannon is controlled using messages.
|
||||
|
||||
!! Message: tm-confetti-launch
|
||||
|
||||
The `tm-confetti-launch` message launches the confetti cannon. The following options are supported:
|
||||
|
||||
|!Name |!Description |!Default |
|
||||
|''particleCount'' |The number of confetti to launch |50 |
|
||||
|''angle'' |The angle in which to launch the confetti, in degrees (90 is straight up) |90 |
|
||||
|''spread'' |How far off center the confetti can go, in degrees. 45 means the confetti will launch at the defined `angle` plus or minus 22.5 degrees |45 |
|
||||
|''startVelocity'' |How fast the confetti will start going, in pixels |45 |
|
||||
|''decay'' |How quickly the confetti will lose speed. Keep this number between 0 and 1, otherwise the confetti will gain speed |0.9 |
|
||||
|''gravity'' |How quickly the particles are pulled down. 1 is full gravity, 0.5 is half gravity, etc. |1 |
|
||||
|''drift'' |How much to the side the confetti will drift. The default is 0, meaning that they will fall straight down. Use a negative number for left and positive number for right |0 |
|
||||
|''ticks'' |How many times the confetti will move (this is an abstract quantity; the designed recommends playing with it if the confetti disappears too quickly for you) |200 |
|
||||
|''originX'' |The `x` position on the page, with `0` being the left edge and `1` being the right edge |0.5 |
|
||||
|''originY'' |The `y` position on the page, with `0` being the top edge and `1` being the bottom edge |0.5 |
|
||||
|''colors'' |A space separated list of color strings in hex format (eg `#bada55` or `#ce5`) | |
|
||||
|''shapes'' |A space separated list of shapes for the confetti. The possible values are `square`, `circle`, and `star`. The default is to use both squares and circles in an even mix. To use a single shape, you can provide just one shape in the list, such as `star`. You can also change the mix by providing a value such as `circle circle square` to use two third circles and one third squares | |
|
||||
|''scalar'' |Scale factor for each confetti particle. Use decimals to make the confetti smaller |1 |
|
||||
|''zIndex'' |Z-index of confetti. Increase the value if the confetti is appearing behind other on-screen elements|100 |
|
||||
|''disableForReducedMotion'' |Set to `yes` to entirely disable confetti for users that [[prefer reduced motion|https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion]] |`no` |
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-confetti-launch"/>
|
||||
Launch
|
||||
</$button>
|
||||
|
||||
!! Message: tm-confetti-reset
|
||||
|
||||
The `tm-confetti-reset` message stops any active confetti.
|
52
plugins/tiddlywiki/confetti/startup.js
Normal file
52
plugins/tiddlywiki/confetti/startup.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/confetti/startup.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Setup the root widget event handlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var confetti = require("$:/plugins/tiddlywiki/confetti/confetti.js");
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "confetti";
|
||||
exports.platforms = ["browser"];
|
||||
exports.after = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
// Install the root widget event handlers
|
||||
exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tm-confetti-launch",function(event) {
|
||||
var paramObject = event.paramObject || {},
|
||||
options = {};
|
||||
options.particleCount = paramObject.particleCount && $tw.utils.parseNumber(paramObject.particleCount);
|
||||
options.angle = paramObject.angle && $tw.utils.parseNumber(paramObject.angle);
|
||||
options.spread = paramObject.spread && $tw.utils.parseNumber(paramObject.spread);
|
||||
options.startVelocity = paramObject.startVelocity && $tw.utils.parseNumber(paramObject.startVelocity);
|
||||
options.decay = paramObject.decay && $tw.utils.parseNumber(paramObject.decay);
|
||||
options.gravity = paramObject.gravity && $tw.utils.parseNumber(paramObject.gravity);
|
||||
options.drift = paramObject.drift && $tw.utils.parseNumber(paramObject.drift);
|
||||
options.ticks = paramObject.ticks && $tw.utils.parseNumber(paramObject.ticks);
|
||||
options.origin = {
|
||||
x: paramObject.originX && $tw.utils.parseNumber(paramObject.originX),
|
||||
y: paramObject.originY && $tw.utils.parseNumber(paramObject.originY)
|
||||
};
|
||||
options.colors = paramObject.colors && $tw.utils.parseStringArray(paramObject.colors);
|
||||
options.shapes = paramObject.shapes && $tw.utils.parseStringArray(paramObject.shapes);
|
||||
options.scalar = paramObject.scalar && $tw.utils.parseNumber(paramObject.scalar);
|
||||
options.zIndex = paramObject.zIndex && $tw.utils.parseNumber(paramObject.zIndex);
|
||||
options.disableForReducedMotion = paramObject.disableForReducedMotion && paramObject.disableForReducedMotion === "yes";
|
||||
confetti(options);
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-confetti-launch",function(event) {
|
||||
confetti.reset();
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
Loading…
Reference in New Issue
Block a user