Initial
This commit is contained in:
125
modules/big-emote/big-emote.js
Normal file
125
modules/big-emote/big-emote.js
Normal file
@@ -0,0 +1,125 @@
|
||||
;(function() {
|
||||
const moduleUrl = window.getModuleUrl();
|
||||
loadCSSModule('overlay-bigemote-css', moduleUrl + '/css/big-emote.css');
|
||||
|
||||
function initModule() {
|
||||
const container = document.getElementById('mainContainer') || document.body;
|
||||
if (!document.getElementById('bigEmoteContainer')) {
|
||||
const bigEmoteContainer = document.createElement('div');
|
||||
bigEmoteContainer.id = 'bigEmoteContainer';
|
||||
container.appendChild(bigEmoteContainer);
|
||||
}
|
||||
}
|
||||
initModule();
|
||||
|
||||
if (window.SBdispatcher) {
|
||||
SBdispatcher.on('stream-alert:gigantify_an_emote', data => {
|
||||
spawnAnimatedImage(data.param1);
|
||||
});
|
||||
}
|
||||
|
||||
function spawnAnimatedImage(url) {
|
||||
const img = document.createElement("img");
|
||||
img.src = url;
|
||||
img.classList.add("bigEmote", "hidden-scale");
|
||||
|
||||
img.onload = () => {
|
||||
const container = document.getElementById("bigEmoteContainer");
|
||||
container.appendChild(img);
|
||||
|
||||
img.classList.remove("hidden-scale");
|
||||
|
||||
// Apparition de l'emote avec un zoom
|
||||
img.classList.add("appear");
|
||||
|
||||
// Lancer le déplacement de l'emote après animation initiale
|
||||
setTimeout(() => {
|
||||
img.classList.remove("appear");
|
||||
|
||||
// Démarrer le rebond à partir de la position actuelle
|
||||
const x = window.innerWidth / 2;
|
||||
const y = window.innerHeight / 2;
|
||||
|
||||
startBouncing(img, x, y, true); // flag to keep transform translate
|
||||
}, 3000);
|
||||
};
|
||||
}
|
||||
|
||||
function startBouncing(img, startX, startY) {
|
||||
const imgSize = 112;
|
||||
const halfSize = imgSize / 2;
|
||||
const margin = 50;
|
||||
|
||||
const minX = margin + halfSize;
|
||||
const maxX = window.innerWidth - margin - halfSize;
|
||||
const minY = margin + halfSize;
|
||||
const maxY = window.innerHeight - margin - halfSize;
|
||||
|
||||
let x = startX;
|
||||
let y = startY;
|
||||
|
||||
const pageDiagonal = Math.sqrt(window.innerWidth ** 2 + window.innerHeight ** 2);
|
||||
const totalDistance = 3 * pageDiagonal;
|
||||
const duration = 30000; // 30s
|
||||
const speed = totalDistance / duration;
|
||||
|
||||
const angle = getValidAngle();
|
||||
let dx = Math.cos(angle) * speed;
|
||||
let dy = Math.sin(angle) * speed;
|
||||
|
||||
let startTime = null;
|
||||
let fadeOutStarted = false;
|
||||
|
||||
function getValidAngle() {
|
||||
while (true) {
|
||||
const angle = Math.random() * 2 * Math.PI;
|
||||
const deg = angle * (180 / Math.PI);
|
||||
const prohibited = [0, 90, 180, 270];
|
||||
const tooClose = prohibited.some(a => {
|
||||
const delta = Math.abs(deg - a) % 360;
|
||||
return delta < 15 || delta > 345;
|
||||
});
|
||||
if (!tooClose) return angle;
|
||||
}
|
||||
}
|
||||
|
||||
function animate(timestamp) {
|
||||
if (!startTime) startTime = timestamp;
|
||||
const elapsed = timestamp - startTime;
|
||||
const dt = timestamp - (animate.lastTime || timestamp);
|
||||
animate.lastTime = timestamp;
|
||||
|
||||
x += dx * dt;
|
||||
y += dy * dt;
|
||||
|
||||
if (x <= minX || x >= maxX) {
|
||||
dx = -dx;
|
||||
x = Math.max(minX, Math.min(x, maxX));
|
||||
}
|
||||
if (y <= minY || y >= maxY) {
|
||||
dy = -dy;
|
||||
y = Math.max(minY, Math.min(y, maxY));
|
||||
}
|
||||
|
||||
img.style.left = `${x}px`;
|
||||
img.style.top = `${y}px`;
|
||||
img.style.transform = "translate(-50%, -50%)";
|
||||
|
||||
// Déclencher le fade-out à 29s
|
||||
if (!fadeOutStarted && elapsed >= duration - 1000) {
|
||||
fadeOutStarted = true;
|
||||
img.classList.add("fade-out");
|
||||
}
|
||||
|
||||
if (elapsed < duration) {
|
||||
requestAnimationFrame(animate);
|
||||
} else {
|
||||
img.remove();
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
47
modules/big-emote/css/big-emote.css
Normal file
47
modules/big-emote/css/big-emote.css
Normal file
@@ -0,0 +1,47 @@
|
||||
#bigEmoteContainer {
|
||||
z-index: 400;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#bigEmoteContainer .bigEmote {
|
||||
position: absolute;
|
||||
width: 112px;
|
||||
height: auto;
|
||||
pointer-events: none;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: center center;
|
||||
}
|
||||
#bigEmoteContainer .hidden-scale {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
#bigEmoteContainer .appear {
|
||||
animation: appear-grow-shrink 3s ease-out forwards;
|
||||
}
|
||||
#bigEmoteContainer .fade-out {
|
||||
transition: opacity 1s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
@keyframes appear-grow-shrink {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
transform: translate(-50%, -50%) scale(5);
|
||||
opacity: 1;
|
||||
}
|
||||
60% {
|
||||
transform: translate(-50%, -50%) scale(5);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
54
modules/big-emote/css/big-emote.less
Normal file
54
modules/big-emote/css/big-emote.less
Normal file
@@ -0,0 +1,54 @@
|
||||
// out: big-emote.css, sourcemap: false, compress: false
|
||||
#bigEmoteContainer {
|
||||
z-index: 400;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.bigEmote {
|
||||
position: absolute;
|
||||
width: 112px;
|
||||
height: auto;
|
||||
pointer-events: none;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.hidden-scale {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.appear {
|
||||
animation: appear-grow-shrink 3s ease-out forwards;
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
transition: opacity 1s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes appear-grow-shrink {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
transform: translate(-50%, -50%) scale(5);
|
||||
opacity: 1;
|
||||
}
|
||||
60% {
|
||||
transform: translate(-50%, -50%) scale(5);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user