Unrestrict 3D layer view camera — full x/y/z orbit
- Add rotateY axis (drag left/right rotates Y, up/down rotates X) - Shift+drag for Z-axis roll - Remove 10-80° clamp on rotateX — full ±180° range - Remove backface-visibility:hidden so layers visible from all angles - Fix overflow:hidden → overflow:visible for proper 3D perspective - Increase layer spacing 80→120px for more dramatic depth - Increase viewport height 340→420px, perspective origin centered Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d62a5e9b15
commit
bf28e96ae6
|
|
@ -101,6 +101,7 @@ export class RStackTabBar extends HTMLElement {
|
|||
#flowDialogTargetId = "";
|
||||
// 3D scene state
|
||||
#sceneRotX = 55;
|
||||
#sceneRotY = 0;
|
||||
#sceneRotZ = -15;
|
||||
#scenePerspective = 1200;
|
||||
#orbitDragging = false;
|
||||
|
|
@ -555,7 +556,7 @@ export class RStackTabBar extends HTMLElement {
|
|||
const layerCount = this.#layers.length;
|
||||
if (layerCount === 0) return "";
|
||||
|
||||
const layerSpacing = 80;
|
||||
const layerSpacing = 120;
|
||||
const animDuration = 2 / this.#simSpeed;
|
||||
|
||||
// Build layer planes
|
||||
|
|
@ -676,7 +677,7 @@ export class RStackTabBar extends HTMLElement {
|
|||
<div class="stack-view-3d" id="stack-3d"
|
||||
style="perspective:${this.#scenePerspective}px;">
|
||||
<div class="stack-scene" id="stack-scene"
|
||||
style="transform: rotateX(${this.#sceneRotX}deg) rotateZ(${this.#sceneRotZ}deg);">
|
||||
style="transform: rotateX(${this.#sceneRotX}deg) rotateY(${this.#sceneRotY}deg) rotateZ(${this.#sceneRotZ}deg);">
|
||||
${layersHtml}
|
||||
${tubesHtml}
|
||||
${particlesHtml}
|
||||
|
|
@ -684,7 +685,7 @@ export class RStackTabBar extends HTMLElement {
|
|||
</div>
|
||||
<div class="stack-legend">${legendHtml}</div>
|
||||
${scrubberHtml}
|
||||
${this.#layers.length >= 2 ? `<div class="stack-hint">Click an output port to wire, or drag between layers · Drag empty space to orbit</div>` : ""}
|
||||
${this.#layers.length >= 2 ? `<div class="stack-hint">Drag to orbit · Shift+drag to roll · Scroll to zoom · Click output ports to wire</div>` : ""}
|
||||
${this.#flowDialogOpen ? this.#renderFlowDialog() : ""}
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -777,7 +778,7 @@ export class RStackTabBar extends HTMLElement {
|
|||
scene.querySelectorAll(".flow-tube, .flow-particle").forEach(el => el.remove());
|
||||
|
||||
const layerZMap = new Map<string, number>();
|
||||
const layerSpacing = 80;
|
||||
const layerSpacing = 120;
|
||||
this.#layers.forEach((layer, i) => layerZMap.set(layer.id, i * layerSpacing));
|
||||
|
||||
const animDuration = 2 / this.#simSpeed;
|
||||
|
|
@ -1123,12 +1124,18 @@ export class RStackTabBar extends HTMLElement {
|
|||
if (this.#orbitDragging) {
|
||||
const dx = e.clientX - this.#orbitLastX;
|
||||
const dy = e.clientY - this.#orbitLastY;
|
||||
this.#sceneRotZ += dx * 0.3;
|
||||
this.#sceneRotX = Math.max(10, Math.min(80, this.#sceneRotX - dy * 0.3));
|
||||
if (e.shiftKey) {
|
||||
// Shift+drag: rotate around Z axis
|
||||
this.#sceneRotZ += dx * 0.3;
|
||||
} else {
|
||||
// Normal drag: rotate around X and Y axes
|
||||
this.#sceneRotY += dx * 0.3;
|
||||
this.#sceneRotX = Math.max(-180, Math.min(180, this.#sceneRotX - dy * 0.3));
|
||||
}
|
||||
this.#orbitLastX = e.clientX;
|
||||
this.#orbitLastY = e.clientY;
|
||||
const scene = this.#shadow.getElementById("stack-scene");
|
||||
if (scene) scene.style.transform = `rotateX(${this.#sceneRotX}deg) rotateZ(${this.#sceneRotZ}deg)`;
|
||||
if (scene) scene.style.transform = `rotateX(${this.#sceneRotX}deg) rotateY(${this.#sceneRotY}deg) rotateZ(${this.#sceneRotZ}deg)`;
|
||||
}
|
||||
|
||||
// Drag-to-connect: track target via bounding rects (robust for 3D)
|
||||
|
|
@ -1781,8 +1788,8 @@ const STYLES = `
|
|||
|
||||
.stack-view {
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
max-height: 60vh;
|
||||
overflow: visible;
|
||||
max-height: 80vh;
|
||||
transition: max-height 0.3s ease;
|
||||
position: relative;
|
||||
background: color-mix(in srgb, var(--rs-bg-surface) 50%, transparent);
|
||||
|
|
@ -1790,14 +1797,15 @@ const STYLES = `
|
|||
}
|
||||
|
||||
.stack-view-3d {
|
||||
perspective-origin: 50% 40%;
|
||||
perspective-origin: 50% 50%;
|
||||
width: 100%;
|
||||
height: 340px;
|
||||
height: 420px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.stack-scene {
|
||||
|
|
@ -1819,7 +1827,6 @@ const STYLES = `
|
|||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
transform-style: preserve-3d;
|
||||
backface-visibility: hidden;
|
||||
background: color-mix(in srgb, var(--rs-bg-surface) 65%, transparent);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
|
|
@ -2297,7 +2304,7 @@ const STYLES = `
|
|||
.tab-label { display: none; }
|
||||
.tab { padding: 4px 8px; }
|
||||
.stack-view { max-height: 40vh; }
|
||||
.stack-view-3d { height: 260px; }
|
||||
.stack-view-3d { height: 320px; }
|
||||
.stack-scene { width: 240px; }
|
||||
.layer-plane { width: 240px; min-height: 40px; padding: 8px 10px; }
|
||||
.io-chip { font-size: 0.5rem; padding: 1px 5px; max-width: 100px; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue