Navigasjon: scroll=pan, Ctrl+scroll=zoom, piltaster, viewport-plassering
Canvas: scroll=pan, Ctrl+scroll=zoom, piltaster, dblclick=100%. BlockShell: Ctrl+scroll zoomer panel-innhold. Nye paneler plasseres i viewport-sentrum, ikke utenfor bildet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0d9837a917
commit
e94c22fcb8
3 changed files with 51 additions and 12 deletions
|
|
@ -73,6 +73,7 @@
|
|||
let dropFeedback = $state<string>('');
|
||||
let isResizing = $state(false);
|
||||
let isDragging = $state(false);
|
||||
let contentZoom = $state(1.0);
|
||||
let containerEl: HTMLDivElement | undefined = $state();
|
||||
let containerWidth = $state(0);
|
||||
|
||||
|
|
@ -422,7 +423,20 @@
|
|||
|
||||
<!-- Content area (hidden when minimized) -->
|
||||
{#if !minimized || isFullscreen}
|
||||
<div class="blockshell-content">
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="blockshell-content"
|
||||
style:transform="scale({contentZoom})"
|
||||
style:transform-origin="top left"
|
||||
onwheel={(e) => {
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const factor = e.deltaY > 0 ? 0.95 : 1.05;
|
||||
contentZoom = Math.min(3, Math.max(0.3, contentZoom * factor));
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if children}
|
||||
{@render children()}
|
||||
{:else}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,12 @@
|
|||
grid = { ...grid, enabled: !grid.enabled };
|
||||
onGridChange?.(grid.enabled);
|
||||
}
|
||||
// Piltaster = pan
|
||||
const PAN_STEP = 50;
|
||||
if (e.code === 'ArrowUp') { camera = { ...camera, y: camera.y + PAN_STEP }; e.preventDefault(); }
|
||||
if (e.code === 'ArrowDown') { camera = { ...camera, y: camera.y - PAN_STEP }; e.preventDefault(); }
|
||||
if (e.code === 'ArrowLeft') { camera = { ...camera, x: camera.x + PAN_STEP }; e.preventDefault(); }
|
||||
if (e.code === 'ArrowRight') { camera = { ...camera, x: camera.x - PAN_STEP }; e.preventDefault(); }
|
||||
}
|
||||
function onKeyUp(e: KeyboardEvent) {
|
||||
if (e.code === 'Space') {
|
||||
|
|
@ -146,11 +152,24 @@
|
|||
};
|
||||
});
|
||||
|
||||
// --- Zoom ---
|
||||
// --- Scroll: Ctrl = zoom, uten Ctrl = pan ---
|
||||
function handleWheel(e: WheelEvent) {
|
||||
// Ikke fang scroll inne i paneler (la innhold scrolle)
|
||||
if ((e.target as HTMLElement).closest('[data-canvas-object-id]')) return;
|
||||
|
||||
e.preventDefault();
|
||||
const zoomFactor = e.deltaY > 0 ? 0.92 : 1.08;
|
||||
zoomAt(e.clientX, e.clientY, zoomFactor);
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
// Ctrl+scroll = zoom
|
||||
const zoomFactor = e.deltaY > 0 ? 0.92 : 1.08;
|
||||
zoomAt(e.clientX, e.clientY, zoomFactor);
|
||||
} else {
|
||||
// Scroll = pan
|
||||
camera = {
|
||||
...camera,
|
||||
x: camera.x - e.deltaX - (e.shiftKey ? e.deltaY : 0),
|
||||
y: camera.y - (e.shiftKey ? 0 : e.deltaY),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function zoomAt(screenX: number, screenY: number, factor: number) {
|
||||
|
|
@ -459,7 +478,7 @@
|
|||
ondblclick={(e) => {
|
||||
if (!(e.target as HTMLElement).closest('[data-canvas-object-id]') &&
|
||||
!(e.target as HTMLElement).closest('.canvas-toolbar')) {
|
||||
zoomToFit();
|
||||
camera = { ...camera, zoom: 1.0 };
|
||||
}
|
||||
}}
|
||||
ontouchstart={handleTouchStart}
|
||||
|
|
|
|||
|
|
@ -230,18 +230,24 @@
|
|||
if (layout.panels.some(p => p.trait === trait)) return;
|
||||
const info = getPanelInfo(trait);
|
||||
const remembered = panelSizes[trait];
|
||||
const maxY = layout.panels.length > 0
|
||||
? Math.max(...layout.panels.map(p => p.y + p.height))
|
||||
: 0;
|
||||
const w = remembered?.width ?? info.defaultWidth;
|
||||
const h = remembered?.height ?? info.defaultHeight;
|
||||
|
||||
// Plasser i viewport-sentrum (hensyn til kamera pan/zoom)
|
||||
const vpW = typeof window !== 'undefined' ? window.innerWidth : 1024;
|
||||
const vpH = typeof window !== 'undefined' ? window.innerHeight - 44 : 700; // minus header
|
||||
const centerX = (vpW / 2 - savedCamera.x) / savedCamera.zoom - w / 2;
|
||||
const centerY = (vpH / 2 - savedCamera.y) / savedCamera.zoom - h / 2;
|
||||
|
||||
layout = {
|
||||
panels: [
|
||||
...layout.panels,
|
||||
{
|
||||
trait,
|
||||
x: 30,
|
||||
y: maxY + 30,
|
||||
width: remembered?.width ?? info.defaultWidth,
|
||||
height: remembered?.height ?? info.defaultHeight,
|
||||
x: Math.round(centerX),
|
||||
y: Math.round(centerY),
|
||||
width: w,
|
||||
height: h,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue