Last active
October 25, 2019 07:24
-
-
Save luruke/71d199c1254799abbabcad6854f6b0c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Button DOM | |
<a href="#" data-component="trackable" data-type="button">Yo, button</a> | |
// Trackable kapla component (https://github.com/thierrymichel/kapla) | |
// Using it just to track when some dom is "mounted/unmounted" | |
import { Component } from 'kapla'; | |
import dom from 'gl/dom'; | |
export default class extends Component { | |
init() { | |
dom.register(this.$el); | |
} | |
destroy() { | |
dom.unregister(this.$el); | |
} | |
} | |
// dom.js | |
// Makes sure to load the correct type of "3D element" based on DOM `data-type` | |
import Button from './button/button'; | |
import Person from './person/person'; | |
import Cover from './cover/cover'; | |
import Footer from './footer/footer'; | |
import Datep from './date/date'; | |
import Placeholder from './placeholder/placeholder'; | |
import Line from './line/line'; | |
import Listhover from './listhover/listhover'; | |
import Glitch from './glitch/glitch'; | |
import Image from './image/image'; | |
const elements = { | |
button: Button, | |
person: Person, | |
cover: Cover, | |
footer: Footer, | |
date: Datep, | |
placeholder: Placeholder, | |
line: Line, | |
listhover: Listhover, | |
glitch: Glitch, | |
image: Image, | |
}; | |
class Dom { | |
constructor() { | |
this.id = 0; | |
this.instances = {}; | |
} | |
register(el) { | |
const id = `id_${this.id++}`; | |
el.dataset.glid = id; | |
const type = el.dataset.type || 'button'; | |
const instance = new elements[type](el); | |
this.instances[id] = instance; | |
el.classList.add('gl'); | |
} | |
getInstanceFromEl(el) { | |
return this.instances[el.dataset.glid]; | |
} | |
unregister(el) { | |
const instance = this.getInstanceFromEl(el); | |
el.classList.remove('gl'); | |
instance.destroy(); | |
} | |
} | |
export default new Dom(); | |
// button.js | |
// That's our three.js "object" | |
import { | |
Mesh, | |
PlaneBufferGeometry, | |
RawShaderMaterial, | |
} from 'three'; | |
import dom3D from '../dom3D'; | |
import scene from '../scene'; | |
import textures from 'gl/utils/textures'; | |
const geometry = new PlaneBufferGeometry(1, 1, 1, 1); | |
const material = new RawShaderMaterial({ | |
transparent: true, | |
fragmentShader: require('./button.frag'), | |
vertexShader: require('./button.vert'), | |
}); | |
export default class extends dom3D { | |
init() { | |
super.init(); | |
this.geometry = geometry; | |
this.material = material.clone(); | |
this.material.uniforms = { | |
uTime: { value: 0 }, | |
uProgress: { value: 0 }, | |
uWind: { value: textures.fromAsset('wind') }, | |
uShow: { value: 0 }, | |
uClipping: { value: 1.0 } | |
}; | |
this.mesh = new Mesh(this.geometry, this.material); | |
this.add(this.mesh); | |
scene.add(this); | |
} | |
onRaf({ delta }) { | |
super.onRaf(); | |
this.material.uniforms.uTime.value += delta * 0.1; | |
} | |
} | |
// dom3D.js | |
// Where the "magic happens", calculate the size and position | |
// converting the 2D DOM coordinates to the PerspectiveCamera | |
import { Object3D } from 'three'; | |
import { component } from 'bidello'; | |
import { viewport, scroll } from './bidello'; | |
import camera from './camera'; | |
export default class extends component(Object3D) { | |
init() { | |
this.element = this._args[0]; | |
} | |
onResize() { | |
if (!this.element) { | |
return; | |
} | |
const rect = this.element.getBoundingClientRect(); | |
this.bounds = { | |
left: rect.left, | |
top: rect.top, | |
width: rect.width, | |
height: rect.height, | |
}; | |
this.updateSize(); | |
this.updatePosition(); | |
} | |
updateSize() { | |
this.camUnit = camera.calculateUnitSize(camera.position.z - this.position.z); | |
/* | |
calculateUnitSize(distance = this.position.z) { | |
const vFov = this.fov * Math.PI / 180; | |
const height = 2 * Math.tan(vFov / 2) * distance; | |
const width = height * this.aspect; | |
return { | |
width, | |
height | |
}; | |
} | |
*/ | |
// Set size | |
const x = this.bounds.width / viewport.width; | |
const y = this.bounds.height / viewport.height; | |
if (!x || !y) { | |
return; | |
} | |
this.scale.x = this.camUnit.width * x; | |
this.scale.y = this.camUnit.height * y; | |
} | |
updatePosition(pos = scroll.y) { | |
const y = pos; | |
// Set origin to top left | |
this.position.x = -(this.camUnit.width / 2) + (this.scale.x / 2); | |
this.position.y = (this.camUnit.height / 2) - (this.scale.y / 2); | |
// Set position | |
this.position.x += (this.bounds.left / viewport.width) * this.camUnit.width; | |
this.position.y -= ((this.bounds.top - y) / viewport.height) * this.camUnit.height; | |
} | |
onRaf() { | |
this.updatePosition(scroll.easeY); | |
} | |
destroy() { | |
this.parent && this.parent.remove(this); | |
this.visible = false; | |
super.destroy(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment