Restore orbit and zoom for silhouette model

This commit is contained in:
2026-08-25 22:55:23 +02:00
parent 8fed9dc61e
commit ed205945d9
3 changed files with 25 additions and 9 deletions
+20 -5
View File
@@ -2,7 +2,8 @@
const canvas = document.querySelector('#model-canvas');
const stage = document.querySelector('.rov-stage');
const ctx = canvas.getContext('2d');
let vertices = null, frame = 0;
let vertices = null, frame = 0, yaw = 0, pitch = 0, zoom = 1;
let dragging = false, lastX = 0, lastY = 0;
const renderScale = .62;
function parseStl(buffer) {
@@ -45,13 +46,21 @@
ctx.setTransform(1,0,0,1,0,0);ctx.clearRect(0,0,width,height);
const mask=document.createElement('canvas'),maskCtx=mask.getContext('2d');
mask.width=width;mask.height=height;
const size=Math.min(width,height)*.43,cx=width/2,cy=height/2;
const size=Math.min(width,height)*.43*zoom,cx=width/2,cy=height/2;
const cosY=Math.cos(yaw),sinY=Math.sin(yaw),cosP=Math.cos(pitch),sinP=Math.sin(pitch);
const project=(x,y,z)=>{
const rx=x*cosY+z*sinY,rz=-x*sinY+z*cosY;
return [rx,y*cosP-rz*sinP];
};
maskCtx.fillStyle='#fff';
for(let i=0;i<vertices.length;i+=9){
const a=project(vertices[i],vertices[i+1],vertices[i+2]);
const b=project(vertices[i+3],vertices[i+4],vertices[i+5]);
const c=project(vertices[i+6],vertices[i+7],vertices[i+8]);
maskCtx.beginPath();
maskCtx.moveTo(cx+vertices[i]*size,cy-vertices[i+1]*size);
maskCtx.lineTo(cx+vertices[i+3]*size,cy-vertices[i+4]*size);
maskCtx.lineTo(cx+vertices[i+6]*size,cy-vertices[i+7]*size);
maskCtx.moveTo(cx+a[0]*size,cy-a[1]*size);
maskCtx.lineTo(cx+b[0]*size,cy-b[1]*size);
maskCtx.lineTo(cx+c[0]*size,cy-c[1]*size);
maskCtx.closePath();maskCtx.fill();
}
// A filtered copy creates only the exterior contour; triangle boundaries
@@ -68,12 +77,18 @@
ctx.drawImage(surface,0,0);
}
function requestDraw(){if(!frame)frame=requestAnimationFrame(draw)}
canvas.addEventListener('pointerdown',event=>{dragging=true;lastX=event.clientX;lastY=event.clientY;canvas.setPointerCapture(event.pointerId)});
canvas.addEventListener('pointermove',event=>{if(!dragging)return;yaw+=(event.clientX-lastX)*.012;pitch=Math.max(-1.45,Math.min(1.45,pitch+(event.clientY-lastY)*.012));lastX=event.clientX;lastY=event.clientY;requestDraw()});
canvas.addEventListener('pointerup',()=>dragging=false);
canvas.addEventListener('pointercancel',()=>dragging=false);
canvas.addEventListener('wheel',event=>{event.preventDefault();zoom=Math.max(.55,Math.min(2.2,zoom*(event.deltaY>0?.9:1.1)));requestDraw()},{passive:false});
addEventListener('resize',requestDraw);
window.rovModel = {
loadBuffer(buffer, name) {
vertices=parseStl(buffer);stage.classList.add('model-loaded');
document.querySelector('#model-file-name').textContent=name;
yaw=0;pitch=0;zoom=1;
requestDraw();
return {name,triangles:vertices.length/9};
},