Browse Source

fall

master
jiannibang 6 years ago
parent
commit
ea61ea4396
  1. 93
      src/App.js
  2. 6
      src/App.scss
  3. BIN
      src/images/10.jpg
  4. BIN
      src/images/11.jpg
  5. BIN
      src/images/12.jpg
  6. BIN
      src/images/13.jpg
  7. BIN
      src/images/14.jpg
  8. BIN
      src/images/4.jpg
  9. BIN
      src/images/5.jpg
  10. BIN
      src/images/6.jpg
  11. BIN
      src/images/7.jpg
  12. BIN
      src/images/8.jpg
  13. BIN
      src/images/9.jpg
  14. 11
      src/images/image-helper.js
  15. 99
      src/wall/Wall.js

93
src/App.js

@ -5,21 +5,16 @@ import Wall from "./wall/Wall";
import Sphere from "./wall/Sphere"; import Sphere from "./wall/Sphere";
import createTouches from "touches"; import createTouches from "touches";
import "./App.scss"; import "./App.scss";
import i1 from "./images/1.jpg";
import i2 from "./images/2.jpg";
import i3 from "./images/3.jpg";
import images from "./images/image-helper";
const videoWidth = 600; const videoWidth = 600;
const videoHeight = 500; const videoHeight = 500;
const width = 1080;
const height = 1920;
const width = window.innerWidth;
const height = window.innerHeight;
const radius = 412; const radius = 412;
const displacement = 412;
const displacement = 600;
const POSENET_URL = const POSENET_URL =
"https://lg-cjdqwkbo-1256266248.cos.ap-shanghai.myqcloud.com/mobile-net/50/model-stride16.json"; "https://lg-cjdqwkbo-1256266248.cos.ap-shanghai.myqcloud.com/mobile-net/50/model-stride16.json";
const Block = ({ style }) => <div style={style}></div>;
const Mist = ({ style }) => ( const Mist = ({ style }) => (
<div className="mist" style={style}> <div className="mist" style={style}>
<div className="ball"></div> <div className="ball"></div>
@ -98,21 +93,27 @@ const App = () => {
} }
}, [video]); }, [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(() => { 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({ let sphere = new Sphere({
x: width / 2, x: width / 2,
y: height / 2, y: height / 2,
@ -120,34 +121,36 @@ const App = () => {
displacement, displacement,
width, width,
}); });
if (wall) {
wall.attachSphere(sphere);
}
setSphere(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]); }, [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 ( return (
<div className="App">
<div
className="App"
onClick={async (e) => {
await wall.dispose();
setWall(null);
initWall();
}}
>
{list.map(([key, el]) => ( {list.map(([key, el]) => (
<Block key={key} style={el.style}></Block>
<div className="block" key={key} style={el.style}></div>
))} ))}
{sphere && <Mist style={sphere.style}></Mist>} {sphere && <Mist style={sphere.style}></Mist>}
</div> </div>

6
src/App.scss

@ -15,6 +15,12 @@
height: 100vh; height: 100vh;
z-index: 1; z-index: 1;
} }
.block {
background-size: cover;
background-position: center;
opacity: 1;
position: absolute;
}
.mist { .mist {
position: absolute; position: absolute;
z-index: 100; z-index: 100;

BIN
src/images/10.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
src/images/11.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

BIN
src/images/12.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

BIN
src/images/13.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

BIN
src/images/14.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
src/images/4.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
src/images/5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
src/images/6.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
src/images/7.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
src/images/8.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/images/9.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

11
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;

99
src/wall/Wall.js

@ -1,7 +1,5 @@
import { Vector3 } from "three"; import { Vector3 } from "three";
export const fps = 60;
export const mspf = 1000 / fps;
const g = 0.55 / 1000;
class El { class El {
constructor(seed) { constructor(seed) {
const { data, row, wall, key, index } = seed; const { data, row, wall, key, index } = seed;
@ -11,32 +9,28 @@ class El {
const point = new Vector3(x, y, 0); const point = new Vector3(x, y, 0);
const targetPoint = new Vector3(x, y, 0); const targetPoint = new Vector3(x, y, 0);
const spherePoint = sphere ? sphere.point : null; const spherePoint = sphere ? sphere.point : null;
let scale = 1;
if (sphere && point.distanceTo(spherePoint) < sphere.displacement) { if (sphere && point.distanceTo(spherePoint) < sphere.displacement) {
const direction = point.clone().sub(spherePoint); const direction = point.clone().sub(spherePoint);
const displacementAmount = sphere.displacement - direction.length(); const displacementAmount = sphere.displacement - direction.length();
scale = ((1 - displacementAmount / sphere.displacement) / 1) * 0.3 + 0.7;
direction.setLength(displacementAmount); direction.setLength(displacementAmount);
direction.add(point); 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) { if (point.distanceTo(targetPoint) > 0.01) {
point.lerp(targetPoint, 0.27); // ✨ magic number point.lerp(targetPoint, 0.27); // ✨ magic number
} }
const top = point.y - imgHeight / 2; const top = point.y - imgHeight / 2;
const left = point.x - imgWidth / 2; const left = point.x - imgWidth / 2;
const { url } = data; const { url } = data;
const style = { const style = {
position: "absolute",
width: `${imgWidth}px`, width: `${imgWidth}px`,
height: `${imgHeight}px`, height: `${imgHeight}px`,
top: `${top}px`, top: `${top}px`,
left: `${left}px`, left: `${left}px`,
backgroundSize: "cover",
backgroundImage: `url(${url})`, backgroundImage: `url(${url})`,
opacity: 1,
transform: `scale(${scale})`,
zIndex: row.size - Math.floor(Math.abs(row.size / 2 - row.index)), zIndex: row.size - Math.floor(Math.abs(row.size / 2 - row.index)),
}; };
Object.assign(this, { seed, data, style, key, point }); Object.assign(this, { seed, data, style, key, point });
@ -45,10 +39,14 @@ class El {
} }
class Row { class Row {
falled = false;
q = [];
fst;
t1;
t2;
constructor({ wall, index }) { constructor({ wall, index }) {
Object.assign(this, { Object.assign(this, {
wall, wall,
q: [],
minSize: wall.colNum + 1, minSize: wall.colNum + 1,
index, index,
ratio: Math.random(), ratio: Math.random(),
@ -67,7 +65,13 @@ class Row {
const { wall } = this; const { wall } = this;
const data = wall.getNext(); const data = wall.getNext();
const key = wall.getKey(); 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); const el = new El(seed);
this.wall.elMap.set(key, el); this.wall.elMap.set(key, el);
this.q.push(el); this.q.push(el);
@ -76,6 +80,22 @@ class Row {
const el = this.q.shift(); const el = this.q.shift();
this.wall.elMap.delete(el.key); 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) { nextFrame(ratioSpeed) {
this.ratio += ratioSpeed; this.ratio += ratioSpeed;
if (this.ratio > 1) { if (this.ratio > 1) {
@ -86,15 +106,19 @@ class Row {
}); });
this.ratio -= 1; this.ratio -= 1;
} }
this.q.forEach((el) => {
this.wall.elMap.set(el.key, new El(el.seed));
});
this.update();
} }
} }
export default class Wall { export default class Wall {
#rafID;
#rafID = null;
#lastTime; #lastTime;
falling = false;
rows = [];
key = 0;
time = 0;
index = 0;
maxDeltaTime = 1 / 30;
constructor({ constructor({
items, items,
imgWidth, imgWidth,
@ -112,37 +136,27 @@ export default class Wall {
const blockHeight = containerHeight / (rowNum - 1); const blockHeight = containerHeight / (rowNum - 1);
const elMap = new Map(); const elMap = new Map();
Object.assign(this, { Object.assign(this, {
time: 0,
index: 0,
items, items,
colNum, colNum,
rowNum, rowNum,
elNum, elNum,
imgWidth, imgWidth,
imgHeight, imgHeight,
containerWidth,
containerHeight,
ratioSpeed, ratioSpeed,
rows: [],
key: 0,
blockWidth, blockWidth,
blockHeight, blockHeight,
elMap, elMap,
onListChange, onListChange,
maxDeltaTime: 1 / 30,
}); });
} }
getNext() { 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() { init() {
const { rowNum } = this; const { rowNum } = this;
for (let i = 0; i < rowNum; i++) { for (let i = 0; i < rowNum; i++) {
const row = new Row({ wall: this, index: i }); const row = new Row({ wall: this, index: i });
row.init(); row.init();
@ -154,20 +168,29 @@ export default class Wall {
} }
animate = () => { animate = () => {
if (!this.isRunning) return; if (!this.isRunning) return;
window.requestAnimationFrame(this.animate);
const now = performance.now(); const now = performance.now();
const dt = Math.min(this.maxDeltaTime, (now - this.#lastTime) / 1000); 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.getList();
this.time += dt; this.time += dt;
this.#lastTime = now; this.#lastTime = now;
this.#rafID = window.requestAnimationFrame(this.animate);
}; };
dispose() {
async dispose() {
if (this.#rafID === null) return; 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; return this;
} }
getKey() { getKey() {

Loading…
Cancel
Save