Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -541,6 +541,68 @@ class CameraControl3D(gr.HTML):
|
|
| 541 |
|
| 542 |
canvas.addEventListener('mouseup', onMouseUp);
|
| 543 |
canvas.addEventListener('mouseleave', onMouseUp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 544 |
|
| 545 |
// Initial update
|
| 546 |
updatePositions();
|
|
|
|
| 541 |
|
| 542 |
canvas.addEventListener('mouseup', onMouseUp);
|
| 543 |
canvas.addEventListener('mouseleave', onMouseUp);
|
| 544 |
+
|
| 545 |
+
// Touch support for mobile
|
| 546 |
+
canvas.addEventListener('touchstart', (e) => {
|
| 547 |
+
e.preventDefault();
|
| 548 |
+
const touch = e.touches[0];
|
| 549 |
+
const rect = canvas.getBoundingClientRect();
|
| 550 |
+
mouse.x = ((touch.clientX - rect.left) / rect.width) * 2 - 1;
|
| 551 |
+
mouse.y = -((touch.clientY - rect.top) / rect.height) * 2 + 1;
|
| 552 |
+
|
| 553 |
+
raycaster.setFromCamera(mouse, camera);
|
| 554 |
+
const intersects = raycaster.intersectObjects([azimuthHandle, elevationHandle, distanceHandle]);
|
| 555 |
+
|
| 556 |
+
if (intersects.length > 0) {
|
| 557 |
+
isDragging = true;
|
| 558 |
+
dragTarget = intersects[0].object;
|
| 559 |
+
dragTarget.material.emissiveIntensity = 1.0;
|
| 560 |
+
dragTarget.scale.setScalar(1.3);
|
| 561 |
+
dragStartMouse.copy(mouse);
|
| 562 |
+
dragStartDistance = distanceFactor;
|
| 563 |
+
}
|
| 564 |
+
}, { passive: false });
|
| 565 |
+
|
| 566 |
+
canvas.addEventListener('touchmove', (e) => {
|
| 567 |
+
e.preventDefault();
|
| 568 |
+
const touch = e.touches[0];
|
| 569 |
+
const rect = canvas.getBoundingClientRect();
|
| 570 |
+
mouse.x = ((touch.clientX - rect.left) / rect.width) * 2 - 1;
|
| 571 |
+
mouse.y = -((touch.clientY - rect.top) / rect.height) * 2 + 1;
|
| 572 |
+
|
| 573 |
+
if (isDragging && dragTarget) {
|
| 574 |
+
raycaster.setFromCamera(mouse, camera);
|
| 575 |
+
|
| 576 |
+
if (dragTarget.userData.type === 'azimuth') {
|
| 577 |
+
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), -0.05);
|
| 578 |
+
if (raycaster.ray.intersectPlane(plane, intersection)) {
|
| 579 |
+
azimuthAngle = THREE.MathUtils.radToDeg(Math.atan2(intersection.x, intersection.z));
|
| 580 |
+
if (azimuthAngle < 0) azimuthAngle += 360;
|
| 581 |
+
}
|
| 582 |
+
} else if (dragTarget.userData.type === 'elevation') {
|
| 583 |
+
const plane = new THREE.Plane(new THREE.Vector3(1, 0, 0), -0.8);
|
| 584 |
+
if (raycaster.ray.intersectPlane(plane, intersection)) {
|
| 585 |
+
const relY = intersection.y - CENTER.y;
|
| 586 |
+
const relZ = intersection.z;
|
| 587 |
+
elevationAngle = THREE.MathUtils.clamp(THREE.MathUtils.radToDeg(Math.atan2(relY, relZ)), -30, 60);
|
| 588 |
+
}
|
| 589 |
+
} else if (dragTarget.userData.type === 'distance') {
|
| 590 |
+
const deltaY = mouse.y - dragStartMouse.y;
|
| 591 |
+
distanceFactor = THREE.MathUtils.clamp(dragStartDistance - deltaY * 1.5, 0.6, 1.4);
|
| 592 |
+
}
|
| 593 |
+
updatePositions();
|
| 594 |
+
}
|
| 595 |
+
}, { passive: false });
|
| 596 |
+
|
| 597 |
+
canvas.addEventListener('touchend', (e) => {
|
| 598 |
+
e.preventDefault();
|
| 599 |
+
onMouseUp();
|
| 600 |
+
}, { passive: false });
|
| 601 |
+
|
| 602 |
+
canvas.addEventListener('touchcancel', (e) => {
|
| 603 |
+
e.preventDefault();
|
| 604 |
+
onMouseUp();
|
| 605 |
+
}, { passive: false });
|
| 606 |
|
| 607 |
// Initial update
|
| 608 |
updatePositions();
|