openscad-remote/tools/multi-uploader.html

271 lines
9.9 KiB
HTML

<!doctype html>
<html>
<head lang="en">
<title>Generate a model with OpenSCAD Remote</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/custom.css">
<link rel="stylesheet" href="css/tachyons-4.12.0.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous">
</head>
<body>
<div class="mw5 mw7-ns center bg-light-gray pa3 ph5-ns shadow-2 avenir">
<h1 class="f1">OpenSCAD Remote</h1>
<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">
<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>
<div class="w-100">
<div class="w-100 bb b--black-30 pb3"></div>
<div class="pt2"></div>
</div>
<h2 class="f4">Parameters JSON file</h2>
<div class="w-100 mt2 mb2 flex">
<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>
<div class="w-100">
<div class="w-100 bb b--black-30 pb3"></div>
<div class="pt2"></div>
</div>
<div class="flex items-center">
<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>
<div class="w-100">
<div class="w-100 bb b--black-30 pb3"></div>
<div class="pt2"></div>
</div>
<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>
<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";
let inc = 0;
let camera, controls, cameraTarget, scene, renderer;
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);
inc++;
});
const send_form = document.getElementById("files-form");
send_form.addEventListener("submit", (event) => {
const url = "https://cad.interstellai.re/upload";
fetch(url, {
method: "POST",
body: new FormData(event.target)
})
.then( res => res.blob() )
.then( blob => {
addResult(blob);
});
event.preventDefault();
});
function addResult(blob) {
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");
dl_icon.setAttribute("aria-hidden", "true");
const dl_button = document.createElement("button");
dl_button.appendChild(dl_icon);
dl_button.appendChild(document.createTextNode(" Download"));
dl_button.classList.add(..."f4 white bg-green ba b--dark-green mt2 ph4 pv3 center mw5 db shadow-2 grow".split(" "));
dl_button.addEventListener("click", (event) => {
const file = window.URL.createObjectURL(blob);
window.location.assign(file);
});
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_button);
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 );
}
</script>
</body>
</html>