init and that it
This commit is contained in:
commit
66916e55fc
9 changed files with 392 additions and 0 deletions
8
README.md
Normal file
8
README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
A short experiment on Parent/Child interaction with Web Components. Creates Web Components for various ThreeJS base classes
|
||||
|
||||
Renderer
|
||||
Scene
|
||||
Group
|
||||
Light
|
||||
BoxGeometry
|
||||
SphereGeometry
|
77
ThreeBaseGeometry.js
Normal file
77
ThreeBaseGeometry.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
|
||||
const attrs_dimensions = [ 'height', 'width', 'depth' ];
|
||||
const attrs_position = [ 'x', 'y', 'z' ];
|
||||
const attrs_rotation = [ 'rx', 'ry', 'rz' ];
|
||||
|
||||
export class BaseGeometryElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
var attrs = BaseGeometryElement.observedAttributes;
|
||||
|
||||
for(let i in attrs) {
|
||||
Object.defineProperty(this, attrs[i], {
|
||||
get: function() {
|
||||
return this.getAttribute(attrs[i]);
|
||||
},
|
||||
set: function(v) {
|
||||
return this.setAttribute(attrs[i], v);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return [
|
||||
'color',
|
||||
'height', 'width', 'depth',
|
||||
'x', 'y', 'z',
|
||||
'rx', 'ry', 'rz',
|
||||
]
|
||||
}
|
||||
|
||||
parentO3DCallback() {}
|
||||
|
||||
connectedCallback() {
|
||||
var parentEl = this.parentElement.closest('three-group, three-scene');
|
||||
|
||||
if(!parentEl.ready) {
|
||||
var self = this;
|
||||
|
||||
parentEl.addEventListener('ready', function() {
|
||||
var o3d = parentEl.nodeName == "THREE-GROUP" ? parentEl.group : parentEl.scene;
|
||||
self.parentO3DCallback(o3d);
|
||||
|
||||
self.ready = true;
|
||||
self.dispatchEvent(new CustomEvent("ready"));
|
||||
});
|
||||
} else {
|
||||
var o3d = parentEl.nodeName == "THREE-GROUP" ? parentEl.group : parentEl.scene;
|
||||
this.parentO3DCallback(o3d);
|
||||
this.ready = true;
|
||||
this.dispatchEvent(new CustomEvent("ready"));
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old_value, value) {
|
||||
if(!this.ready) return;
|
||||
|
||||
var obj = {};
|
||||
|
||||
if(attrs_dimensions.includes(name)) {
|
||||
obj = this.geometry[name];
|
||||
}
|
||||
|
||||
if(attrs_position.includes(name)) {
|
||||
obj = this.mesh.position[name];
|
||||
}
|
||||
|
||||
if(attrs_rotation.includes(name)) {
|
||||
console.log(name);
|
||||
obj = this.mesh.rotation[name];
|
||||
}
|
||||
|
||||
obj[name] = value;
|
||||
}
|
||||
}
|
20
ThreeCube.js
Normal file
20
ThreeCube.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
import { BaseGeometryElement } from './ThreeBaseGeometry.js';
|
||||
|
||||
const attrs_position = [ 'x', 'y', 'z' ];
|
||||
const attrs_dimensions = [ 'height', 'width', 'depth' ];
|
||||
|
||||
export class CubeElement extends BaseGeometryElement {
|
||||
parentO3DCallback(parent) {
|
||||
var scene = this.closest('three-scene');
|
||||
|
||||
this.geometry = new THREE.BoxGeometry(this.width, this.height, this.depth); // width, height, depth
|
||||
this.material = new THREE.MeshLambertMaterial({ color: this.color });
|
||||
this.mesh = new THREE.Mesh(this.geometry, this.material);
|
||||
this.mesh.position.set(this.x, this.y, this.z); // Optional, 0,0,0 is the default
|
||||
|
||||
parent.add(this.mesh);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-cube', CubeElement);
|
29
ThreeGroup.js
Normal file
29
ThreeGroup.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
import { BaseGeometryElement } from './ThreeBaseGeometry.js';
|
||||
|
||||
export class GroupElement extends BaseGeometryElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
parentO3DCallback(parent) {
|
||||
this.group = new THREE.Group();
|
||||
this.group.position.set(this.getAttribute('x'), this.getAttribute('y'), this.getAttribute('z'));
|
||||
this.group.rotation.set(this.getAttribute('rx'), this.getAttribute('ry'), this.getAttribute('rz'));
|
||||
|
||||
parent.add(this.group);
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old, value) {
|
||||
if(this.group && [ 'x', 'y', 'z' ].includes(name)) {
|
||||
this.group.position[name] = parseInt(value);
|
||||
}
|
||||
|
||||
console.log(this.group, name);
|
||||
if(this.group && [ 'rx', 'ry', 'rz' ].includes(name)) {
|
||||
this.group.rotation[name] = parseInt(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-group', GroupElement);
|
37
ThreeLight.js
Normal file
37
ThreeLight.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
import { ThreeRendererElement } from './ThreeRendererElement.js';
|
||||
|
||||
export class LightElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.light = new THREE.DirectionalLight(this.getAttribute('color') || 0xfff, 0.5);
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return [ "color" ];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old_value, value) {
|
||||
if(name == 'color') {
|
||||
this.light.color = new THREE.Color(value);
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
var scene = this.closest('three-scene');
|
||||
|
||||
if(!scene.ready) {
|
||||
var self = this;
|
||||
|
||||
scene.addEventListener('ready', function() {
|
||||
scene.scene.add(self.light);
|
||||
})
|
||||
} else {
|
||||
scene.scene.add(this.light);
|
||||
}
|
||||
this.ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-light', LightElement);
|
113
ThreeRendererElement.js
Normal file
113
ThreeRendererElement.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
|
||||
THREE.Object3D.DEFAULT_UP.set(0,0,1);
|
||||
|
||||
export class ThreeRendererElement extends HTMLCanvasElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
var parent_boundingbox = this.parentElement.getBoundingClientRect();
|
||||
this.height = parent_boundingbox.height;
|
||||
this.width = parent_boundingbox.width;
|
||||
|
||||
this.camera_persp = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
|
||||
//this.camera_ortho = new THREE.OrthographicCamera( this.width / - 2, this.width / 2, this.height / 2, this.height / - 2, 1, 1000 );
|
||||
|
||||
this.camera = this.camera_persp;
|
||||
this.camera.position.x = 0;
|
||||
this.camera.position.y = 0;
|
||||
this.camera.position.z = 0;
|
||||
|
||||
/*
|
||||
var light = this.light = new THREE.AmbientLight(0xab1f2c, 1);
|
||||
this.scene.add(light);
|
||||
|
||||
var point_light = this.point_light = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||
this.point_light.position.set(0, 0, 10);
|
||||
this.scene.add(point_light);
|
||||
*/
|
||||
|
||||
var renderer = this.renderer = new THREE.WebGLRenderer({
|
||||
canvas: this
|
||||
});
|
||||
var bb = this.parentElement.getBoundingClientRect();
|
||||
this.renderer.setSize(bb.width, bb.height);
|
||||
|
||||
|
||||
/*
|
||||
// ground plane
|
||||
const planeSize = 40;
|
||||
const loader = new THREE.TextureLoader();
|
||||
const texture = loader.load('checker.png');
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.magFilter = THREE.NearestFilter;
|
||||
const repeats = planeSize / 2;
|
||||
texture.repeat.set(repeats, repeats);
|
||||
|
||||
const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
|
||||
const planeMat = new THREE.MeshPhongMaterial({
|
||||
map: texture,
|
||||
side: THREE.DoubleSide,
|
||||
});
|
||||
const plane_mesh = new THREE.Mesh(planeGeo, planeMat);
|
||||
window.plane_mesh = plane_mesh;
|
||||
//plane_mesh.rotation.x = Math.PI * -.5;
|
||||
this.scene.add(plane_mesh);
|
||||
*/
|
||||
|
||||
// XXX applWHY?
|
||||
this.do_animate = this.do_animate.bind(this);
|
||||
this.do_animate();
|
||||
|
||||
// TODO improve value checking, current src="" will be true
|
||||
|
||||
/*
|
||||
this.childObserver = new MutationObserver(function(changes) {
|
||||
})
|
||||
|
||||
this.childObserver.observe(this, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return [ ];
|
||||
}
|
||||
|
||||
do_animate() {
|
||||
// TODO handle pausing
|
||||
requestAnimationFrame(this.do_animate);
|
||||
|
||||
if(this.active_scene) {
|
||||
this.renderer.render(this.active_scene, this.camera);
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old_value, value) {
|
||||
}
|
||||
|
||||
parsedCallack() {
|
||||
console.log('parsedCallack');
|
||||
}
|
||||
|
||||
setupRenderer() {
|
||||
this.scenes = this.querySelectorAll('three-scene');
|
||||
this.active_scene = this.scenes[this.scenes.length - 1].scene;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if(document.readyState != "complete") {
|
||||
document.addEventListener("DOMContentLoaded", this.setupRenderer.bind(this));
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent("renderer-ready", {
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-renderer', ThreeRendererElement, { extends: 'canvas' });
|
34
ThreeScene.js
Normal file
34
ThreeScene.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
import { ThreeRendererElement } from './ThreeRendererElement.js';
|
||||
|
||||
export class SceneElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
rendererConnected() {
|
||||
console.log('fjlkjsdflksjdf');
|
||||
}
|
||||
|
||||
findRenderer() {
|
||||
var p = this;
|
||||
while((p = p.parentElement) !== undefined)
|
||||
if(p instanceof ThreeRendererElement) return p;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.scene = new THREE.Scene();
|
||||
this.scene.background = new THREE.Color(this.getAttribute('background-color') || 0xababab);
|
||||
if(!(this.parentElement instanceof ThreeRendererElement)) {
|
||||
throw Error("Parent not ThreeRendererElement");
|
||||
}
|
||||
|
||||
this.parentElement.addEventListener("connected", this.rendererConnected.bind(this));
|
||||
|
||||
this.dispatchEvent(new CustomEvent('ready'));
|
||||
this.ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-scene', SceneElement);
|
18
ThreeSphere.js
Normal file
18
ThreeSphere.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import * as THREE from 'https://esm.sh/three';
|
||||
import { BaseGeometryElement } from './ThreeBaseGeometry.js';
|
||||
|
||||
const attrs_position = [ 'x', 'y', 'z' ];
|
||||
const attrs_dimensions = [ 'height', 'width', 'depth' ];
|
||||
|
||||
export class SphereElement extends BaseGeometryElement {
|
||||
parentO3DCallback(parent) {
|
||||
this.geometry = new THREE.SphereGeometry(this.getAttribute('radius')); // width, height, depth
|
||||
this.material = new THREE.MeshLambertMaterial({ color: this.color });
|
||||
this.mesh = new THREE.Mesh(this.geometry, this.material);
|
||||
this.mesh.position.set(this.x, this.y, this.z); // Optional, 0,0,0 is the default
|
||||
|
||||
parent.add(this.mesh);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('three-sphere', SphereElement);
|
56
index.html
Normal file
56
index.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="module">
|
||||
import * as THREE from 'https://esm.sh/three';
|
||||
import './ThreeRendererElement.js'
|
||||
import './ThreeCube.js';
|
||||
import './ThreeGroup.js';
|
||||
import './ThreeLight.js';
|
||||
import './ThreeScene.js';
|
||||
import './ThreeSphere.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var group = document.querySelector('three-group');
|
||||
var sphere = document.querySelector('three-sphere');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@keyframe position {
|
||||
from {
|
||||
x: 140;
|
||||
}
|
||||
|
||||
to {
|
||||
x: 0;
|
||||
}
|
||||
}
|
||||
|
||||
three-cube.left {
|
||||
animation-duration: 3s;
|
||||
animation-name: position;
|
||||
x: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas is=three-renderer>
|
||||
<three-scene name="main">
|
||||
<three-light color="#ee00aa"></three-light>
|
||||
<three-cube color="#ffffff" height=40 width=90 depth=10 x=0 y=40 z=-200 focus></three-cube>
|
||||
<three-sphere color="#a0a00f" radius=30 x=0 y=40 z=-200 focus></three-sphere>
|
||||
|
||||
<three-group x=35 y=20 rz=30>
|
||||
<three-cube color="#ffffff" height=40 width=90 depth=10 x=0 y=40 z=-200 focus></three-cube>
|
||||
<three-sphere color="#a0a00f" radius=30 x=0 y=40 z=-200 focus></three-sphere>
|
||||
</three-group>
|
||||
</three-scene>
|
||||
</canvas>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue