Tomater
This commit is contained in:
commit
efff561c74
BIN
crosshair.png
Normal file
BIN
crosshair.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
173
index.html
Normal file
173
index.html
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Tomater</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: #db4343;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 900px;
|
||||||
|
|
||||||
|
background: #97b73d;
|
||||||
|
border-radius: 99px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-family: sans;
|
||||||
|
}
|
||||||
|
|
||||||
|
#picture-container {
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tomato {
|
||||||
|
position: absolute;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
object-fit: contain;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#picture {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 80vw;
|
||||||
|
max-height: 80vh;
|
||||||
|
object-fit: contain;
|
||||||
|
cursor: url(/crosshair.png), default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-picker {
|
||||||
|
background: brown;
|
||||||
|
max-width: max-content;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sign {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
rotate: 3deg;
|
||||||
|
height: 187px;
|
||||||
|
right: -120px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="col">
|
||||||
|
<h1>Tomater</h1>
|
||||||
|
<div id="picture-container">
|
||||||
|
<img ondragstart="return false;" src="wall.jpg" alt="" id="picture" />
|
||||||
|
<img src="/tomate-with-me.png" alt="" id="sign" />
|
||||||
|
</div>
|
||||||
|
<input type="file" id="file-picker" />
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const picture = document.getElementById("picture");
|
||||||
|
const pictureContainer = document.getElementById("picture-container");
|
||||||
|
const filePicker = document.getElementById("file-picker");
|
||||||
|
|
||||||
|
filePicker.onchange = () => {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
picture.src = e.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(filePicker.files[0]);
|
||||||
|
|
||||||
|
const tomatos = document.querySelectorAll(".tomato");
|
||||||
|
tomatos.forEach((tomato) => {
|
||||||
|
tomato.remove();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTomato = (tomato) => {
|
||||||
|
if (tomato.progress > 100) {
|
||||||
|
tomato.src = "/splat.png";
|
||||||
|
|
||||||
|
tomato.style.left = `${tomato.end_x - 50}px`;
|
||||||
|
tomato.style.top = `${tomato.end_y - 50}px`;
|
||||||
|
tomato.style.width = "100px";
|
||||||
|
tomato.style.height = "100px";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_x = lerp(tomato.progress, tomato.start_x, tomato.end_x);
|
||||||
|
let new_y = lerp(tomato.progress, tomato.start_y, tomato.end_y);
|
||||||
|
|
||||||
|
// apply a curve effect to path
|
||||||
|
// the lower the target height, the bigger the "curve"
|
||||||
|
const targetHeightContribution = tomato.end_y / picture.height / 2;
|
||||||
|
|
||||||
|
// the closer to the middle of the path
|
||||||
|
// the bigger the curve effect
|
||||||
|
const progressContribution = Math.sin(
|
||||||
|
(tomato.progress / 100) * Math.PI,
|
||||||
|
);
|
||||||
|
|
||||||
|
new_y -= 500 * targetHeightContribution * progressContribution;
|
||||||
|
|
||||||
|
const scale = lerp(tomato.progress, 150, 40);
|
||||||
|
const imageSize = (50 * scale) / 100;
|
||||||
|
|
||||||
|
tomato.style.left = `${new_x - imageSize / 2}px`;
|
||||||
|
tomato.style.top = `${new_y - imageSize / 2}px`;
|
||||||
|
tomato.style.rotate = `${tomato.rotation}deg`;
|
||||||
|
|
||||||
|
tomato.style.width = `${scale}px`;
|
||||||
|
tomato.style.height = `${scale}px`;
|
||||||
|
|
||||||
|
tomato.progress += 2.0;
|
||||||
|
tomato.rotation += tomato.angularMomentum;
|
||||||
|
};
|
||||||
|
|
||||||
|
picture.onclick = (e) => {
|
||||||
|
let rect = e.target.getBoundingClientRect();
|
||||||
|
let x = e.clientX - rect.left;
|
||||||
|
let y = e.clientY - rect.top;
|
||||||
|
|
||||||
|
let tomato = document.createElement("img");
|
||||||
|
tomato.src = "/tomato.png";
|
||||||
|
tomato.classList.add("tomato");
|
||||||
|
|
||||||
|
tomato.progress = 0;
|
||||||
|
tomato.start_x = picture.width / 2;
|
||||||
|
tomato.start_y = picture.height;
|
||||||
|
|
||||||
|
tomato.end_x = x;
|
||||||
|
tomato.end_y = y;
|
||||||
|
|
||||||
|
tomato.angularMomentum = Math.random() * 20 - 10;
|
||||||
|
tomato.rotation = 0;
|
||||||
|
tomato.scale = 1;
|
||||||
|
|
||||||
|
updateTomato(tomato);
|
||||||
|
|
||||||
|
pictureContainer.appendChild(tomato);
|
||||||
|
};
|
||||||
|
|
||||||
|
const lerp = (progress, start, end) => {
|
||||||
|
return start + (end - start) * (progress / 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const tomatos = document.querySelectorAll(".tomato");
|
||||||
|
tomatos.forEach(updateTomato);
|
||||||
|
}, 10);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
tomate-with-me.png
Normal file
BIN
tomate-with-me.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
BIN
tomato.png
Normal file
BIN
tomato.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 226 KiB |
Loading…
Reference in a new issue