@@ -98,21 +93,27 @@ const App = () => {
}
}, [video]);
+ const initWall = () => {
+ const wall = new Wall({
+ items: Object.values(images).map((url) => ({ url })),
+ imgWidth: 90,
+ imgHeight: 100,
+ containerWidth: width,
+ containerHeight: height,
+ speed: 1,
+ onListChange: setList,
+ });
+ wall.init();
+ setWall(wall);
+ return wall;
+ };
useEffect(() => {
- if (!wall) {
- const wall = new Wall({
- items: [{ url: i1 }, { url: i2 }, { url: i3 }],
- imgWidth: 90,
- imgHeight: 100,
- containerWidth: 1080,
- containerHeight: 1920,
- speed: 1,
- onListChange: setList,
- });
- wall.init();
- setWall(wall);
- wall.getList();
- } else {
+ if (wall && sphere) {
+ wall.attachSphere(sphere);
+ }
+ }, [wall]);
+ useEffect(() => {
+ if (!sphere) {
let sphere = new Sphere({
x: width / 2,
y: height / 2,
@@ -120,34 +121,36 @@ const App = () => {
displacement,
width,
});
- if (wall) {
- wall.attachSphere(sphere);
- }
setSphere(sphere);
- }
- return () => {
- if (wall) wall.dispose();
- };
- }, [wall]);
-
- useEffect(() => {
- if (sphere) {
- const container = document.querySelector(".App");
- const touchHandler = createTouches(container, {
- target: container,
- filtered: true,
- });
- touchHandler.on("move", (_, [x, y]) => {
- sphere.x = x;
- sphere.y = y;
- });
+ initWall();
}
}, [sphere]);
+ // useEffect(() => {
+ // if (sphere) {
+ // const container = document.querySelector(".App");
+ // const touchHandler = createTouches(container, {
+ // target: container,
+ // filtered: true,
+ // });
+ // touchHandler.on("move", (_, [x, y]) => {
+ // sphere.x = x;
+ // sphere.y = y;
+ // });
+ // }
+ // }, [sphere]);
+
return (
-
+
{
+ await wall.dispose();
+ setWall(null);
+ initWall();
+ }}
+ >
{list.map(([key, el]) => (
-
+
))}
{sphere &&
}
diff --git a/src/App.scss b/src/App.scss
index 1ca0979..9fdb41c 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -15,6 +15,12 @@
height: 100vh;
z-index: 1;
}
+ .block {
+ background-size: cover;
+ background-position: center;
+ opacity: 1;
+ position: absolute;
+ }
.mist {
position: absolute;
z-index: 100;
diff --git a/src/images/10.jpg b/src/images/10.jpg
new file mode 100644
index 0000000..0e001cf
Binary files /dev/null and b/src/images/10.jpg differ
diff --git a/src/images/11.jpg b/src/images/11.jpg
new file mode 100644
index 0000000..ca95782
Binary files /dev/null and b/src/images/11.jpg differ
diff --git a/src/images/12.jpg b/src/images/12.jpg
new file mode 100644
index 0000000..90a083b
Binary files /dev/null and b/src/images/12.jpg differ
diff --git a/src/images/13.jpg b/src/images/13.jpg
new file mode 100644
index 0000000..0df2f9a
Binary files /dev/null and b/src/images/13.jpg differ
diff --git a/src/images/14.jpg b/src/images/14.jpg
new file mode 100644
index 0000000..39ee8ab
Binary files /dev/null and b/src/images/14.jpg differ
diff --git a/src/images/4.jpg b/src/images/4.jpg
new file mode 100644
index 0000000..fe5a8df
Binary files /dev/null and b/src/images/4.jpg differ
diff --git a/src/images/5.jpg b/src/images/5.jpg
new file mode 100644
index 0000000..7f81025
Binary files /dev/null and b/src/images/5.jpg differ
diff --git a/src/images/6.jpg b/src/images/6.jpg
new file mode 100644
index 0000000..6692433
Binary files /dev/null and b/src/images/6.jpg differ
diff --git a/src/images/7.jpg b/src/images/7.jpg
new file mode 100644
index 0000000..a9d8993
Binary files /dev/null and b/src/images/7.jpg differ
diff --git a/src/images/8.jpg b/src/images/8.jpg
new file mode 100644
index 0000000..27e2198
Binary files /dev/null and b/src/images/8.jpg differ
diff --git a/src/images/9.jpg b/src/images/9.jpg
new file mode 100644
index 0000000..b24fe8d
Binary files /dev/null and b/src/images/9.jpg differ
diff --git a/src/images/image-helper.js b/src/images/image-helper.js
new file mode 100644
index 0000000..729f2a4
--- /dev/null
+++ b/src/images/image-helper.js
@@ -0,0 +1,11 @@
+function importAll(r) {
+ let obj = {};
+ r.keys().forEach((key) => {
+ obj[key.replace("./", "").replace(".jpg", "")] = r(key);
+ });
+ return obj;
+}
+
+const images = importAll(require.context("./", false, /\.(png|jpe?g|svg)$/));
+
+export default images;
diff --git a/src/wall/Wall.js b/src/wall/Wall.js
index 6951521..fde22ff 100644
--- a/src/wall/Wall.js
+++ b/src/wall/Wall.js
@@ -1,7 +1,5 @@
import { Vector3 } from "three";
-export const fps = 60;
-export const mspf = 1000 / fps;
-
+const g = 0.55 / 1000;
class El {
constructor(seed) {
const { data, row, wall, key, index } = seed;
@@ -11,32 +9,28 @@ class El {
const point = new Vector3(x, y, 0);
const targetPoint = new Vector3(x, y, 0);
const spherePoint = sphere ? sphere.point : null;
+ let scale = 1;
if (sphere && point.distanceTo(spherePoint) < sphere.displacement) {
const direction = point.clone().sub(spherePoint);
const displacementAmount = sphere.displacement - direction.length();
+ scale = ((1 - displacementAmount / sphere.displacement) / 1) * 0.3 + 0.7;
direction.setLength(displacementAmount);
direction.add(point);
-
- point.lerp(direction, 1); // ✨ magic number
+ point.lerp(direction, 0.725); // ✨ magic number
}
-
- // and move them back to their original position
if (point.distanceTo(targetPoint) > 0.01) {
point.lerp(targetPoint, 0.27); // ✨ magic number
}
const top = point.y - imgHeight / 2;
const left = point.x - imgWidth / 2;
const { url } = data;
-
const style = {
- position: "absolute",
width: `${imgWidth}px`,
height: `${imgHeight}px`,
top: `${top}px`,
left: `${left}px`,
- backgroundSize: "cover",
backgroundImage: `url(${url})`,
- opacity: 1,
+ transform: `scale(${scale})`,
zIndex: row.size - Math.floor(Math.abs(row.size / 2 - row.index)),
};
Object.assign(this, { seed, data, style, key, point });
@@ -45,10 +39,14 @@ class El {
}
class Row {
+ falled = false;
+ q = [];
+ fst;
+ t1;
+ t2;
constructor({ wall, index }) {
Object.assign(this, {
wall,
- q: [],
minSize: wall.colNum + 1,
index,
ratio: Math.random(),
@@ -67,7 +65,13 @@ class Row {
const { wall } = this;
const data = wall.getNext();
const key = wall.getKey();
- const seed = { data, row: this, wall, key, index: this.q.length };
+ const seed = {
+ data,
+ row: this,
+ wall,
+ key,
+ index: this.q.length,
+ };
const el = new El(seed);
this.wall.elMap.set(key, el);
this.q.push(el);
@@ -76,6 +80,22 @@ class Row {
const el = this.q.shift();
this.wall.elMap.delete(el.key);
}
+ update() {
+ this.q.forEach((el) => {
+ this.wall.elMap.set(el.key, new El(el.seed));
+ });
+ }
+ fall(now) {
+ if (!this.fst) {
+ this.fst = now;
+ this.t1 = 0;
+ } else {
+ this.t2 = now - this.fst;
+ this.y += (g * (this.t2 * this.t2 - this.t1 * this.t1)) / 2;
+ this.t1 = this.t2;
+ }
+ this.update();
+ }
nextFrame(ratioSpeed) {
this.ratio += ratioSpeed;
if (this.ratio > 1) {
@@ -86,15 +106,19 @@ class Row {
});
this.ratio -= 1;
}
- this.q.forEach((el) => {
- this.wall.elMap.set(el.key, new El(el.seed));
- });
+ this.update();
}
}
export default class Wall {
- #rafID;
+ #rafID = null;
#lastTime;
+ falling = false;
+ rows = [];
+ key = 0;
+ time = 0;
+ index = 0;
+ maxDeltaTime = 1 / 30;
constructor({
items,
imgWidth,
@@ -112,37 +136,27 @@ export default class Wall {
const blockHeight = containerHeight / (rowNum - 1);
const elMap = new Map();
Object.assign(this, {
- time: 0,
- index: 0,
items,
colNum,
rowNum,
elNum,
imgWidth,
imgHeight,
+ containerWidth,
+ containerHeight,
ratioSpeed,
- rows: [],
- key: 0,
blockWidth,
blockHeight,
elMap,
onListChange,
- maxDeltaTime: 1 / 30,
});
}
getNext() {
- const { index, elNum, items } = this;
- if (index === elNum) {
- this.index = 1;
- return items[0];
- } else {
- this.index++;
- return items[index];
- }
+ const { items } = this;
+ return items[Math.floor(Math.random() * items.length)];
}
init() {
const { rowNum } = this;
-
for (let i = 0; i < rowNum; i++) {
const row = new Row({ wall: this, index: i });
row.init();
@@ -154,20 +168,29 @@ export default class Wall {
}
animate = () => {
if (!this.isRunning) return;
- window.requestAnimationFrame(this.animate);
-
const now = performance.now();
const dt = Math.min(this.maxDeltaTime, (now - this.#lastTime) / 1000);
- this.rows.forEach((row) => row.nextFrame(this.ratioSpeed));
+ this.rows.forEach((row) =>
+ this.falling ? row.fall(now) : row.nextFrame(this.ratioSpeed)
+ );
this.getList();
this.time += dt;
this.#lastTime = now;
+ this.#rafID = window.requestAnimationFrame(this.animate);
};
- dispose() {
+ async dispose() {
if (this.#rafID === null) return;
- window.cancelAnimationFrame(this.#rafID);
- this.#rafID = null;
- this.isRunning = false;
+ this.falling = true;
+ await new Promise((resolve) => {
+ setTimeout(() => {
+ this.falling = false;
+ window.cancelAnimationFrame(this.#rafID);
+ this.#rafID = null;
+ this.isRunning = false;
+ resolve();
+ }, Math.sqrt((this.containerHeight * 2) / g) + 500);
+ });
+
return this;
}
getKey() {