diff --git a/docs/assets/stylesheets/main.css b/docs/assets/stylesheets/main.css index 03f3c36..6cb7644 100644 --- a/docs/assets/stylesheets/main.css +++ b/docs/assets/stylesheets/main.css @@ -9,3 +9,10 @@ width: 100%; height: 100%; } + +#pseudo-3d-layer { + position: fixed; + width: 100%; + height: 100%; + pointer-events: none; +} diff --git a/overrides/main.html b/overrides/main.html index 1d39593..9d1b868 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -14,6 +14,8 @@ +
+ \ No newline at end of file diff --git a/src/index.js b/src/index.js index 716eacf..716507c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,31 @@ -import ThreeViewport from "./three.js"; +import WorldViewport from "./world-viewport.js"; import WebGL from "three/examples/jsm/capabilities/WebGL.js"; +import Pseudo3DLayer from "./pseudo-3d-layer.js"; if (WebGL.isWebGL2Available()) { - new ThreeViewport(document.getElementById('three-viewport')).setup(); + const canvas = document.getElementById('three-viewport'); + const world = new WorldViewport(canvas); + world.setup(); + console.log(world); + + const container = document.getElementById('pseudo-3d-layer'); + const layer = new Pseudo3DLayer(container); + layer.bind(world); + console.log(layer); + + const test1 = document.createElement('div'); + test1.style.width = '10%'; + test1.style.height = '10%'; + test1.style.background = 'red'; + test1.style.pointerEvents = 'fill'; + layer.add(test1, { x: 0, y: 0, z: 0 }); + + const test2 = document.createElement('div'); + test2.style.width = '5%'; + test2.style.height = '5%'; + test2.style.background = 'green'; + test2.style.pointerEvents = 'fill'; + layer.add(test2, { x: 0, y: 0, z: 1 }); } else { document.body.appendChild(WebGL.getWebGL2ErrorMessage()); } diff --git a/src/pseudo-3d-layer.js b/src/pseudo-3d-layer.js new file mode 100644 index 0000000..5b2a0f2 --- /dev/null +++ b/src/pseudo-3d-layer.js @@ -0,0 +1,56 @@ +export default class Pseudo3DLayer { + /** @param {HTMLDivElement} container */ + constructor(container) { + this.container = container; + } + + /** @param {WorldViewport} world */ + bind(world) { + this.world = world; + this.originX = world.camera.position.z; + world.renderPseudo = this.render.bind(this); + } + + /** @type {[ { wrapper: HTMLDivElement, element: HTMLElement, x: (layer: Pseudo3DLayer) => number, y: (layer: Pseudo3DLayer) => number, z: (layer: Pseudo3DLayer) => number } ]} */ + items = []; + /** + * @param {HTMLElement} element + * @param {{ x: number | (() => number), y?: number | (() => number), z?: number | (() => number) }} options + */ + add(element, options) { + const wrapper = document.createElement('div'); + wrapper.style.position = 'absolute'; + wrapper.style.width = '100%'; + wrapper.style.height = '100%'; + wrapper.appendChild(element); + this.container.appendChild(wrapper); + // const + const value = x => typeof x === 'function' ? x : () => (x || 0); + this.items.push({ + wrapper, + element, + x: value(options.x), + y: value(options.y), + z: value(options.z), + }); + } + + static PixelToBlockMultiple = 40; + render(item) { + if (!item) return this.items.forEach(item => this.render(item)); + + const { innerWidth: windowWidth, innerHeight: windowHeight } = window; + const { clientWidth: width, clientHeight: height } = item.element; + const [ x, y, z ] = [ item.x(this), item.y(this), item.z(this) ]; + const cameraZ = this.world.camera.position.z; + + const top = windowHeight / 2 - height / 2 + y; + const left = windowWidth / 2 - width / 2 + + x + + (this.originX - cameraZ) * Pseudo3DLayer.PixelToBlockMultiple + * (1 + z); + + item.wrapper.style.top = `${top}px`; + item.wrapper.style.left = `${left}px`; + } +} diff --git a/src/three.js b/src/world-viewport.js similarity index 98% rename from src/three.js rename to src/world-viewport.js index 10e7114..8c1610c 100644 --- a/src/three.js +++ b/src/world-viewport.js @@ -34,7 +34,7 @@ const motionBlurShader = { `, }; -export default class ThreeViewport { +export default class WorldViewport { /** @param {HTMLCanvasElement} canvas */ constructor(canvas) { this.canvas = canvas; @@ -229,8 +229,6 @@ export default class ThreeViewport { this.camera.position.set(-34, -12, -0.1); this.camera.rotation.set(0, THREE.MathUtils.degToRad(270), 0); - // this.camera.position.z += -3; - this.controller(); this.animate(); } @@ -249,12 +247,13 @@ export default class ThreeViewport { this.canvas.addEventListener('touchstart', event => this.previousX = event.touches[0].clientX); this.canvas.addEventListener('touchmove', event => { const currentX = event.touches[0].clientX; - if (this.previousX) this.targetZ += (this.previousX - currentX) * 0.02; + if (this.previousX) this.targetZ += (this.previousX - currentX) * 0.025; this.previousX = currentX; }); window.addEventListener('touchend', () => this.previousX = null); } + renderPseudo; animate() { requestAnimationFrame(this.animate.bind(this)); @@ -275,6 +274,8 @@ export default class ThreeViewport { this.animatePetals(); + if (this.renderPseudo) this.renderPseudo(); + this.composer.render(); } }