⚡ Cleaning code and squashing small bugs
This commit is contained in:
parent
ecc52fe412
commit
34f3fb9344
|
@ -14,4 +14,8 @@
|
|||
|
||||
.h6 {
|
||||
height: 32rem;
|
||||
}
|
||||
|
||||
.disabled div {
|
||||
background-color: gray !important;
|
||||
}
|
3
tools/js/config.js
Normal file
3
tools/js/config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export class Configuration {
|
||||
static url = "http://127.0.0.1:5000/";
|
||||
}
|
183
tools/js/utils.js
Normal file
183
tools/js/utils.js
Normal file
|
@ -0,0 +1,183 @@
|
|||
import * as THREE from "https://cdn.jsdelivr.net/npm/three@v0.120.0/build/three.module.js";
|
||||
import { STLLoader } from "https://cdn.jsdelivr.net/npm/three@v0.120.0/examples/jsm/loaders/STLLoader.js";
|
||||
import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@v0.120.0/examples/jsm/controls/OrbitControls.js";
|
||||
|
||||
|
||||
class STLViewer {
|
||||
|
||||
constructor(container, blob) {
|
||||
this.container = container;
|
||||
this.camera = new THREE.PerspectiveCamera(
|
||||
60,
|
||||
this.container.clientWidth / this.container.clientHeight,
|
||||
1,
|
||||
1000
|
||||
);
|
||||
this.camera.position.set(10, 10, 10);
|
||||
|
||||
// Renderer
|
||||
this.renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
this.setRenderer();
|
||||
|
||||
// Controls
|
||||
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
||||
this.setControls();
|
||||
|
||||
// World
|
||||
this.scene = new THREE.Scene();
|
||||
this.scene.background = new THREE.Color( 0xdddddd );
|
||||
//scene.fog = new THREE.Fog(0xdddddd, 10, 100);
|
||||
|
||||
// Ground
|
||||
const plane = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry( 1000, 1000 ),
|
||||
new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
|
||||
);
|
||||
plane.rotation.x = - Math.PI / 2;
|
||||
plane.position.y = - 0.5;
|
||||
this.scene.add( plane );
|
||||
|
||||
plane.receiveShadow = true;
|
||||
|
||||
const loader = new STLLoader();
|
||||
blob.arrayBuffer().then(buffer => {
|
||||
const geometry = loader.parse(buffer);
|
||||
|
||||
const material = new THREE.MeshPhongMaterial( { color: 0xff5533, specular: 0x111111, shininess: 200 } );
|
||||
const mesh = new THREE.Mesh( geometry, material );
|
||||
|
||||
mesh.position.set(0, 0, 0);
|
||||
mesh.rotation.set(0, 0, 0);
|
||||
mesh.scale.set(1, 1, 1 );
|
||||
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
this.scene.add(mesh);
|
||||
});
|
||||
|
||||
// Lights
|
||||
this.scene.add(new THREE.HemisphereLight(0x443333, 0x111122));
|
||||
|
||||
this.addShadowedLight(1, 1, 1, 0xffffff, 1.35);
|
||||
this.addShadowedLight(0.5, 1, - 1, 0xffffff, 1);
|
||||
|
||||
this.container.appendChild(this.renderer.domElement);
|
||||
|
||||
// Events listeners
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
|
||||
this.animate();
|
||||
}
|
||||
|
||||
setControls() {
|
||||
this.controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
|
||||
this.controls.dampingFactor = 0.05;
|
||||
|
||||
this.controls.screenSpacePanning = false;
|
||||
this.controls.enablePan = false;
|
||||
|
||||
this.controls.minDistance = 1;
|
||||
this.controls.maxDistance = 500;
|
||||
|
||||
this.controls.maxPolarAngle = Math.PI;
|
||||
}
|
||||
|
||||
setRenderer() {
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
|
||||
this.renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
|
||||
this.renderer.shadowMap.enabled = true;
|
||||
}
|
||||
|
||||
addShadowedLight(x, y, z, color, intensity) {
|
||||
const directionalLight = new THREE.DirectionalLight(color, intensity);
|
||||
directionalLight.position.set(x, y, z);
|
||||
this.scene.add(directionalLight);
|
||||
|
||||
directionalLight.castShadow = false;
|
||||
|
||||
const d = 1;
|
||||
directionalLight.shadow.camera.left = - d;
|
||||
directionalLight.shadow.camera.right = d;
|
||||
directionalLight.shadow.camera.top = d;
|
||||
directionalLight.shadow.camera.bottom = - d;
|
||||
|
||||
directionalLight.shadow.camera.near = 1;
|
||||
directionalLight.shadow.camera.far = 4;
|
||||
|
||||
directionalLight.shadow.bias = - 0.002;
|
||||
}
|
||||
|
||||
onWindowResize() {
|
||||
this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
|
||||
this.camera.updateProjectionMatrix();
|
||||
|
||||
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
|
||||
}
|
||||
|
||||
animate() {
|
||||
requestAnimationFrame(this.animate.bind(this));
|
||||
this.render(this.renderer, this.scene, this.camera);
|
||||
}
|
||||
|
||||
render() {
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
}
|
||||
}
|
||||
|
||||
function addFileInput(parent, id) {
|
||||
const newLine = document.createElement("div");
|
||||
const newInput = document.createElement("input");
|
||||
const newLabel = document.createElement("label");
|
||||
const newButton = document.createElement("button");
|
||||
|
||||
const uploadIcon = document.createElement("i");
|
||||
const removeIcon = document.createElement("i");
|
||||
|
||||
const uploadText = document.createElement("span");
|
||||
|
||||
newLine.classList.add(..."w-100 mt2 mb2 flex".split(" "));
|
||||
newInput.classList = ["clip"];
|
||||
newLabel.classList.add(..."f6 pointer dim blue bl bt bb b--dark-blue w-90 ph3 pv2 link mr0 ml0 dib".split(" "));
|
||||
newButton.classList.add(..."f6 pointer dim white bg-red ba b--dark-red ph3 pv2 w-10".split(" "));
|
||||
|
||||
uploadIcon.classList.add("fa", "fa-upload");
|
||||
removeIcon.classList.add("fa", "fa-trash");
|
||||
|
||||
uploadIcon.setAttribute("aria-hidden", "true");
|
||||
removeIcon.setAttribute("aria-hidden", "true");
|
||||
|
||||
uploadText.textContent = " Choose a file to upload";
|
||||
|
||||
newInput.type = "file";
|
||||
newInput.name = id;
|
||||
newInput.id = id;
|
||||
|
||||
newLabel.htmlFor = id;
|
||||
newLabel.appendChild(uploadIcon);
|
||||
newLabel.appendChild(uploadText);
|
||||
|
||||
newButton.appendChild(removeIcon);
|
||||
|
||||
newLine.appendChild(newInput);
|
||||
newLine.appendChild(newLabel);
|
||||
newLine.appendChild(newButton);
|
||||
|
||||
newInput.addEventListener('change', (event) => {
|
||||
const fileName = event.target.value.split('\\').pop();
|
||||
uploadText.textContent = fileName ? ` ${fileName}` : " Choose a file to upload";
|
||||
});
|
||||
|
||||
newButton.addEventListener('click', (event) => {
|
||||
newLine.remove();
|
||||
});
|
||||
|
||||
parent.appendChild(newLine);
|
||||
}
|
||||
|
||||
export {
|
||||
STLViewer,
|
||||
addFileInput
|
||||
};
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
<form id="files-form" enctype="multipart/form-data">
|
||||
<h2 class="f4">Main SCAD file</h2>
|
||||
|
||||
<div class="w-100 mt2 mb2 flex">
|
||||
<input class="clip" type=file name="main-file" id="fileForUpload" accept=".scad">
|
||||
|
||||
<div class="w-100 mt2 mb2 flex fileinput">
|
||||
<input class="clip" type=file name="main-file" id="fileForUpload" accept=".scad" required>
|
||||
<label class="f6 pointer dim blue ba b--dark-blue w-100 ph3 pv2 link mr0 ml0 dib" for="fileForUpload"><i class="fa fa-upload" aria-hidden="true"></i> Choose a file to upload (.scad)</label>
|
||||
</div>
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
|||
|
||||
<h2 class="f4">Parameters JSON file</h2>
|
||||
|
||||
<div class="w-100 mt2 mb2 flex">
|
||||
<div class="w-100 mt2 mb2 flex fileinput">
|
||||
<input class="clip" type=file name="parameters-file" id="paramFile" accept=".json">
|
||||
<label class="f6 pointer dim blue ba b--dark-blue w-100 ph3 pv2 link mr0 ml0 dib" for="paramFile"><i class="fa fa-upload" aria-hidden="true"></i> Choose a file to upload (.json)</label>
|
||||
</div>
|
||||
|
@ -41,7 +41,6 @@
|
|||
<h3 class="f4 w-100">Extra files</h3>
|
||||
<button type="button" id="add-file-button" class="f6 w5 h2 white bg-blue ba b--dark-blue ph3 pv2 db br-pill shadow-2 grow"><i class="fa fa-plus" aria-hidden="true"></i> Add a file</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex flex-column" id="extra-files-list"></div>
|
||||
|
||||
|
@ -53,64 +52,49 @@
|
|||
<button type="submit" class="f4 white bg-green ba b--dark-green mt2 ph4 pv3 center mw5 db shadow-2 grow" id="send-buttonbak"><i class="fa fa-paper-plane" aria-hidden="true"></i> Send</button>
|
||||
</form>
|
||||
</div>
|
||||
<div id="result-viewer" class="mw5 mw7-ns center bg-light-gray shadow-2 avenir pt3 mt3"></div>
|
||||
<div id="result-viewer" class="mw5 mw7-ns center bg-light-gray shadow-2 avenir pt3 mt3">
|
||||
<h3 class="f3 mr3 ml3 mr5-ns ml5-ns">Result</h3>
|
||||
<div id="three-container" class="w-100 center h6"></div>
|
||||
|
||||
<a id="dl-link" class="center no-underline db mw5 disabled">
|
||||
<div class="f4 white bg-green ba b--dark-green mt2 flex items-center justify-center pv3 center db shadow-2 grow">
|
||||
<i class="fa fa-download mr2" aria-hidden="true"></i>Download
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<script type="module">
|
||||
import * as THREE from "https://cdn.jsdelivr.net/npm/three@v0.120.0/build/three.module.js";
|
||||
import { STLLoader } from "https://cdn.jsdelivr.net/npm/three@v0.120.0/examples/jsm/loaders/STLLoader.js";
|
||||
import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@v0.120.0/examples/jsm/controls/OrbitControls.js";
|
||||
import {
|
||||
STLViewer,
|
||||
addFileInput
|
||||
} from "./js/utils.js";
|
||||
|
||||
import { Configuration } from "./js/config.js";
|
||||
|
||||
let inc = 0;
|
||||
let camera, controls, cameraTarget, scene, renderer;
|
||||
let stlviewer;
|
||||
|
||||
console.log( document.getElementsByClassName("fileinput"));
|
||||
|
||||
[...document.getElementsByClassName("fileinput")].forEach(element => {
|
||||
const input = element.getElementsByTagName("input")[0];
|
||||
const label = element.getElementsByTagName("label")[0];
|
||||
input.addEventListener('change', (event) => {
|
||||
const fileName = event.target.value.split('\\').pop();
|
||||
label.textContent = fileName ? ` ${fileName}` : " Choose a file to upload";
|
||||
});
|
||||
|
||||
if (input.value != "") {
|
||||
const fileName = input.value.split('\\').pop();
|
||||
label.textContent = fileName ? ` ${fileName}` : " Choose a file to upload";
|
||||
}
|
||||
});
|
||||
|
||||
const add_button = document.getElementById("add-file-button")
|
||||
add_button.addEventListener("click", (event) => {
|
||||
const newLine = document.createElement("div");
|
||||
const newInput = document.createElement("input");
|
||||
const newLabel = document.createElement("label");
|
||||
const newButton = document.createElement("button");
|
||||
|
||||
const uploadIcon = document.createElement("i");
|
||||
const removeIcon = document.createElement("i");
|
||||
|
||||
const uploadText = document.createElement("span");
|
||||
|
||||
newLine.classList.add(..."w-100 mt2 mb2 flex".split(" "));
|
||||
newInput.classList = ["clip"];
|
||||
newLabel.classList.add(..."f6 pointer dim blue bl bt bb b--dark-blue w-90 ph3 pv2 link mr0 ml0 dib".split(" "));
|
||||
newButton.classList.add(..."f6 pointer dim white bg-red ba b--dark-red ph3 pv2 w-10".split(" "));
|
||||
|
||||
uploadIcon.classList.add("fa", "fa-upload");
|
||||
removeIcon.classList.add("fa", "fa-trash");
|
||||
|
||||
uploadIcon.setAttribute("aria-hidden", "true");
|
||||
removeIcon.setAttribute("aria-hidden", "true");
|
||||
|
||||
uploadText.textContent = " Choose a file to upload";
|
||||
|
||||
newInput.type = "file";
|
||||
newInput.name = `extra-file-${inc}`;
|
||||
newInput.id = `extra-file-${inc}`;
|
||||
|
||||
newLabel.htmlFor = `extra-file-${inc}`;
|
||||
newLabel.appendChild(uploadIcon);
|
||||
newLabel.appendChild(uploadText);
|
||||
|
||||
newButton.appendChild(removeIcon);
|
||||
|
||||
newLine.appendChild(newInput);
|
||||
newLine.appendChild(newLabel);
|
||||
newLine.appendChild(newButton);
|
||||
|
||||
newInput.addEventListener('change', (event) => {
|
||||
const fileName = event.target.value.split('\\').pop();
|
||||
uploadText.textContent = fileName ? ` ${fileName}` : " Choose a file to upload";
|
||||
});
|
||||
|
||||
newButton.addEventListener('click', (event) => {
|
||||
newLine.remove();
|
||||
});
|
||||
|
||||
document.getElementById("extra-files-list").appendChild(newLine);
|
||||
addFileInput(
|
||||
document.getElementById("extra-files-list"),
|
||||
`extra-file-${inc}`
|
||||
);
|
||||
inc++;
|
||||
});
|
||||
|
||||
|
@ -118,8 +102,7 @@
|
|||
|
||||
const send_form = document.getElementById("files-form");
|
||||
send_form.addEventListener("submit", (event) => {
|
||||
const url = "https://cad.interstellai.re/upload";
|
||||
fetch(url, {
|
||||
fetch(Configuration.url, {
|
||||
method: "POST",
|
||||
body: new FormData(event.target)
|
||||
})
|
||||
|
@ -136,147 +119,15 @@
|
|||
});
|
||||
|
||||
function addResult(blob, filename) {
|
||||
const container = document.getElementById("result-viewer");
|
||||
|
||||
const title = document.createElement("h3");
|
||||
title.classList.add(..."f3 mr3 ml3 mr5-ns ml5-ns".split(" "));
|
||||
title.textContent = "Result";
|
||||
|
||||
const dl_icon = document.createElement("i");
|
||||
dl_icon.classList.add("fa", "fa-download", "mr2");
|
||||
dl_icon.setAttribute("aria-hidden", "true");
|
||||
|
||||
const dl_link = document.createElement("a");
|
||||
|
||||
const dl_button = document.createElement("div");
|
||||
dl_button.appendChild(dl_icon);
|
||||
dl_button.appendChild(document.createTextNode("Download"));
|
||||
dl_button.classList.add(..."f4 white bg-green ba b--dark-green mt2 flex items-center justify-center pv3 center db shadow-2 grow".split(" "));
|
||||
const dl_link = document.getElementById("dl-link");
|
||||
|
||||
dl_link.href = window.URL.createObjectURL(blob);
|
||||
dl_link.download = filename;
|
||||
|
||||
dl_link.classList.add(..."center no-underline db mw5".split(" "));
|
||||
dl_link.classList.remove("disabled");
|
||||
|
||||
dl_link.appendChild(dl_button);
|
||||
|
||||
const threejs_view = document.createElement("div");
|
||||
threejs_view.classList.add(..."w-100 center h6".split(" "));
|
||||
|
||||
container.appendChild(title);
|
||||
container.appendChild(threejs_view);
|
||||
container.appendChild(dl_link);
|
||||
|
||||
init(threejs_view, blob);
|
||||
animate();
|
||||
}
|
||||
|
||||
function init(container, blob) {
|
||||
camera = new THREE.PerspectiveCamera( 35, container.clientWidth / container.clientHeight, 1, 1000 );
|
||||
camera.position.set(10, 10, 10);
|
||||
|
||||
// Renderer
|
||||
renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
|
||||
renderer.shadowMap.enabled = true;
|
||||
|
||||
// Controls
|
||||
controls = new OrbitControls( camera, renderer.domElement );
|
||||
|
||||
controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
|
||||
controls.dampingFactor = 0.05;
|
||||
|
||||
controls.screenSpacePanning = false;
|
||||
controls.enablePan = false;
|
||||
|
||||
controls.minDistance = 1;
|
||||
controls.maxDistance = 500;
|
||||
|
||||
controls.maxPolarAngle = Math.PI;
|
||||
|
||||
// World
|
||||
scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color( 0xdddddd );
|
||||
//scene.fog = new THREE.Fog(0xdddddd, 10, 100);
|
||||
|
||||
// Ground
|
||||
const plane = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry( 1000, 1000 ),
|
||||
new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
|
||||
);
|
||||
plane.rotation.x = - Math.PI / 2;
|
||||
plane.position.y = - 0.5;
|
||||
scene.add( plane );
|
||||
|
||||
plane.receiveShadow = true;
|
||||
|
||||
const loader = new STLLoader();
|
||||
blob.arrayBuffer().then(buffer => {
|
||||
const geometry = loader.parse(buffer);
|
||||
|
||||
const material = new THREE.MeshPhongMaterial( { color: 0xff5533, specular: 0x111111, shininess: 200 } );
|
||||
const mesh = new THREE.Mesh( geometry, material );
|
||||
|
||||
mesh.position.set(0, 0, 0);
|
||||
mesh.rotation.set(0, 0, 0);
|
||||
mesh.scale.set(1, 1, 1 );
|
||||
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
scene.add( mesh );
|
||||
});
|
||||
|
||||
// Lights
|
||||
scene.add( new THREE.HemisphereLight( 0x443333, 0x111122 ) );
|
||||
|
||||
addShadowedLight( 1, 1, 1, 0xffffff, 1.35 );
|
||||
addShadowedLight( 0.5, 1, - 1, 0xffffff, 1 );
|
||||
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
// Events listeners
|
||||
window.addEventListener('resize', onWindowResize);
|
||||
}
|
||||
|
||||
function addShadowedLight(x, y, z, color, intensity) {
|
||||
const directionalLight = new THREE.DirectionalLight(color, intensity);
|
||||
directionalLight.position.set(x, y, z);
|
||||
scene.add(directionalLight);
|
||||
|
||||
directionalLight.castShadow = false;
|
||||
|
||||
const d = 1;
|
||||
directionalLight.shadow.camera.left = - d;
|
||||
directionalLight.shadow.camera.right = d;
|
||||
directionalLight.shadow.camera.top = d;
|
||||
directionalLight.shadow.camera.bottom = - d;
|
||||
|
||||
directionalLight.shadow.camera.near = 1;
|
||||
directionalLight.shadow.camera.far = 4;
|
||||
|
||||
directionalLight.shadow.bias = - 0.002;
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
const container = renderer.domElement.parentElement;
|
||||
|
||||
camera.aspect = container.clientWidth / container.clientHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderer.render( scene, camera );
|
||||
const threecontainer = document.getElementById("three-container");
|
||||
stlviewer = new STLViewer(threecontainer, blob);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue