87 lines
2.3 KiB
Svelte
87 lines
2.3 KiB
Svelte
<script lang="ts">
|
|
import { createEventDispatcher, onMount } from "svelte";
|
|
const dispatch = createEventDispatcher();
|
|
|
|
export let src: string;
|
|
export let lookonly = false;
|
|
|
|
let root: HTMLElement;
|
|
|
|
onMount(async () => {
|
|
root.style.height = `${root.clientWidth}px`;
|
|
|
|
const THREE = await import("three");
|
|
const THREE_OC = await import("three/examples/jsm/controls/OrbitControls");
|
|
const THREE_STL = await import("three/examples/jsm/loaders/STLLoader");
|
|
|
|
const camera = new THREE.PerspectiveCamera(
|
|
70,
|
|
root.clientWidth / root.clientHeight,
|
|
);
|
|
|
|
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
|
renderer.setSize(root.clientWidth, root.clientHeight);
|
|
root.appendChild(renderer.domElement);
|
|
|
|
const controls = new THREE_OC.OrbitControls(camera, renderer.domElement);
|
|
controls.enableDamping = true;
|
|
controls.dampingFactor = 0.1;
|
|
controls.enableZoom = true;
|
|
controls.autoRotate = true;
|
|
controls.autoRotateSpeed = 3;
|
|
|
|
const scene = new THREE.Scene();
|
|
scene.add(new THREE.HemisphereLight(0xffffff, 1.5));
|
|
|
|
const loader = new THREE_STL.STLLoader();
|
|
loader.load(src, (geometry) => {
|
|
const material = new THREE.MeshPhongMaterial({
|
|
color: 0xdc322f,
|
|
specular: 100,
|
|
shininess: 70,
|
|
});
|
|
const mesh = new THREE.Mesh(geometry, material);
|
|
scene.add(mesh);
|
|
|
|
const middle = new THREE.Vector3();
|
|
geometry.computeBoundingBox();
|
|
geometry.boundingBox.getCenter(middle);
|
|
mesh.geometry.applyMatrix4(
|
|
new THREE.Matrix4().makeTranslation(-middle.x, -middle.y, -middle.z),
|
|
);
|
|
mesh.geometry.applyMatrix4(
|
|
new THREE.Matrix4().makeRotationX(-Math.PI / 2),
|
|
);
|
|
|
|
const largestDimension = Math.max(
|
|
geometry.boundingBox.max.x,
|
|
geometry.boundingBox.max.y,
|
|
geometry.boundingBox.max.z,
|
|
);
|
|
camera.position.z = largestDimension * 2;
|
|
});
|
|
|
|
function animate() {
|
|
controls.update();
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
animate();
|
|
|
|
dispatch("loaded");
|
|
});
|
|
</script>
|
|
|
|
<div class="modelviewer" class:lookonly bind:this={root} />
|
|
|
|
<style>
|
|
.modelviewer {
|
|
width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
|
|
.modelviewer.lookonly {
|
|
pointer-events: none;
|
|
}
|
|
</style>
|