generated from partypages/party-template
This commit is contained in:
parent
7a36dce160
commit
a4515d4e3e
16742
package-lock.json
generated
16742
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
126
src/AnnoyerHandler.tsx
Normal file
126
src/AnnoyerHandler.tsx
Normal file
@ -0,0 +1,126 @@
|
||||
|
||||
export type Annoyer = {
|
||||
image: string,
|
||||
x: number,
|
||||
y: number,
|
||||
angle: number,
|
||||
xSpeed: number,
|
||||
ySpeed: number,
|
||||
angleSpeed: number,
|
||||
isVisible: boolean,
|
||||
wasVisible: boolean,
|
||||
age: number,
|
||||
uuid: string
|
||||
};
|
||||
|
||||
const randomGaussian = () => {
|
||||
return Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random());
|
||||
}
|
||||
export class AnnoyerHandler {
|
||||
public annoyers: Set<Annoyer>;
|
||||
private images: string[];
|
||||
private max_annoyers: number;
|
||||
|
||||
constructor(images: string[], start_limit?: number) {
|
||||
this.annoyers = new Set<Annoyer>();
|
||||
this.images = images;
|
||||
this.max_annoyers = start_limit ?? 0;
|
||||
while (this.annoyers.size < this.max_annoyers) {
|
||||
this.annoyers.add(this.generateAnnoyer());
|
||||
}
|
||||
}
|
||||
|
||||
generateAnnoyer = (): Annoyer => {
|
||||
const usedImages = new Set(Array.from(this.annoyers).map(annoyer => annoyer.image));
|
||||
const possibleImages = this.images.filter(image => !usedImages.has(image));
|
||||
let image: string;
|
||||
if (possibleImages.length !== 0) {
|
||||
//console.log("there are unused images, taking one of them");
|
||||
const ims = Array.from(possibleImages);
|
||||
image = ims[Math.floor(Math.random() * ims.length)];
|
||||
} else {
|
||||
//console.log("all images are in use, taking one at random");
|
||||
image = this.images[Math.floor(Math.random() * this.images.length)];
|
||||
}
|
||||
const maxWidth = document.documentElement.clientWidth;
|
||||
const maxHeight = document.documentElement.clientHeight;
|
||||
const outerMargin = 150;
|
||||
|
||||
const startingPosition = (): [number, number] => {
|
||||
const r1 = Math.random() * 2 - 1;
|
||||
const r2 = Math.random() * 2 - 1;
|
||||
const marginX = r1 * outerMargin;
|
||||
const marginY = r2 * outerMargin;
|
||||
const x = r1 < 0 ? marginX : maxWidth + marginX;
|
||||
const y = r2 < 0 ? marginY : maxHeight + marginY;
|
||||
return [x,y];
|
||||
};
|
||||
const [startX, startY] = startingPosition();
|
||||
|
||||
const speed = (startingPosition: [number, number]): [number, number] => {
|
||||
const r1 = Math.random();
|
||||
const r2 = Math.random();
|
||||
const targetX = r1 * maxWidth;
|
||||
const targetY = r2 * maxHeight;
|
||||
const distance = Math.sqrt(
|
||||
(targetX - startingPosition[0]) * (targetX - startingPosition[0]) +
|
||||
(targetY - startingPosition[1]) * (targetY - startingPosition[1])
|
||||
)
|
||||
const speed = ( Math.abs(randomGaussian()) + 0.5) * 2;
|
||||
const normalizedSpeed = speed / distance;
|
||||
return [(targetX - startingPosition[0]) * normalizedSpeed, (targetY - startingPosition[1]) * normalizedSpeed];
|
||||
};
|
||||
const [speedX, speedY] = speed([startX, startY]);
|
||||
const newAnnoyer = {
|
||||
image: image,
|
||||
x: startX,
|
||||
y: startY,
|
||||
angle: 0,
|
||||
angleSpeed: randomGaussian(),
|
||||
xSpeed: speedX ,
|
||||
ySpeed: speedY ,
|
||||
age: Math.random() * -1000,
|
||||
isVisible: false,
|
||||
wasVisible: false,
|
||||
uuid: "" + Math.random()
|
||||
};
|
||||
return newAnnoyer;
|
||||
};
|
||||
|
||||
die = (annoyer: Annoyer) => {
|
||||
this.annoyers.delete(annoyer);
|
||||
this.spawnUntilLimit();
|
||||
};
|
||||
|
||||
changeLimit = (newValue: number) => {
|
||||
this.max_annoyers = newValue;
|
||||
this.spawnUntilLimit();
|
||||
};
|
||||
|
||||
spawnUntilLimit = () => {
|
||||
while (this.annoyers.size < this.max_annoyers)
|
||||
this.annoyers.add(this.generateAnnoyer());
|
||||
};
|
||||
|
||||
|
||||
tick = () => {
|
||||
this.annoyers.forEach(annoyer => {
|
||||
//if (annoyer.age > 10000) return;
|
||||
annoyer.x += annoyer.xSpeed;
|
||||
annoyer.y += annoyer.ySpeed;
|
||||
annoyer.angle += annoyer.angleSpeed;
|
||||
annoyer.age++;
|
||||
|
||||
if (annoyer.isVisible && !annoyer.wasVisible) {
|
||||
//console.log("annoyer became visible");
|
||||
} else if (annoyer.wasVisible && !annoyer.isVisible) {
|
||||
//console.log("annoyer became invisible");
|
||||
//console.log("annoyer died at the age of ",annoyer.age);
|
||||
this.die(annoyer);
|
||||
} else if (annoyer.age > 10000) this.die(annoyer);
|
||||
annoyer.wasVisible = annoyer.isVisible;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}
|
45
src/KrassesOverlay.tsx
Normal file
45
src/KrassesOverlay.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Annoyer, AnnoyerHandler } from './AnnoyerHandler';
|
||||
import './Krassesoverlay.css';
|
||||
|
||||
const emojis = Array.from("🥐🥯🥞🍦🧁🍰🎂🍮🍭🍫🍬🍩🍪");
|
||||
|
||||
|
||||
export const KrassesOverlay: React.FC = () => {
|
||||
|
||||
const [annoyerHandler, ] = useState(() => new AnnoyerHandler(emojis, 2));
|
||||
const [x, setX] = useState(0);
|
||||
const update = () => setX(x+1);
|
||||
|
||||
const handler = () => {
|
||||
annoyerHandler.tick();
|
||||
update();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(handler, 10);
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
|
||||
const ref = (annoyer: Annoyer) => (element: HTMLImageElement) => {
|
||||
if (!element) return;
|
||||
const rect = element.getBoundingClientRect();
|
||||
const visible = rect.bottom >= 0 &&
|
||||
rect.right >= 0 &&
|
||||
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
rect.left <= (window.innerWidth || document.documentElement.clientWidth);
|
||||
annoyer.isVisible = visible;
|
||||
};
|
||||
|
||||
return <div className="overlay">
|
||||
{Array.from(annoyerHandler.annoyers).map((annoyer, index) => (
|
||||
<span ref={ref(annoyer)} key={index} className="annoyer" style={
|
||||
{
|
||||
fontSize: 40,
|
||||
top: annoyer.y, left: annoyer.x,
|
||||
transform: `rotate(${annoyer.angle}deg)`
|
||||
}
|
||||
}>{annoyer.image}</span>
|
||||
))}
|
||||
</div>;
|
||||
}
|
12
src/Krassesoverlay.css
Normal file
12
src/Krassesoverlay.css
Normal file
@ -0,0 +1,12 @@
|
||||
.overlay {
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.annoyer {
|
||||
position: absolute;
|
||||
max-block-size: 70px;
|
||||
}
|
@ -68,4 +68,23 @@ input[type="radio"]:checked+label {
|
||||
|
||||
#coming-no+label {
|
||||
--selected-color: #dc2626;
|
||||
}
|
||||
|
||||
.bg {
|
||||
background-image: url("https://www.inshape.de/fileadmin/user_upload/user_upload/Fotolia_216856994_Subscription_Monthly_M.jpg");
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
filter: blur(7px);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bgwrap {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.page :is(p, label, h1, h2, h3, h4, h5, h6) {
|
||||
filter: drop-shadow(1px 1px 3px white);
|
||||
}
|
@ -5,6 +5,7 @@ import { APIEndPoint, PartyContext } from './PartyContext';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faAngleDown, faCalendarDays, faLocationDot } from '@fortawesome/free-solid-svg-icons';
|
||||
import { modifySelfRequest, parseURI } from './partyApi';
|
||||
import { KrassesOverlay } from './KrassesOverlay';
|
||||
|
||||
export const PartyPage: React.FC = () => {
|
||||
const partyContext = useContext(PartyContext);
|
||||
@ -58,6 +59,10 @@ export const PartyPage: React.FC = () => {
|
||||
}
|
||||
|
||||
return <div className="App">
|
||||
<div className="bgwrap">
|
||||
<div className="bg" />
|
||||
<KrassesOverlay />
|
||||
</div>
|
||||
<div className='page'>
|
||||
<h1>Hallo {dear} {name},</h1>
|
||||
<div className='page-content'>
|
||||
|
Loading…
Reference in New Issue
Block a user