diff --git a/src/components/MainContent.vue b/src/components/MainContent.vue index 56f9424..cdbeae4 100644 --- a/src/components/MainContent.vue +++ b/src/components/MainContent.vue @@ -6,252 +6,392 @@ Spritesheet - -
-
- +
+ Zoom: {{ Math.round(store.zoomLevel.value * 100) }}% +
+
+
+
+
-
- - -
- {{ tooltipText }}
+ + \ No newline at end of file diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 28f9dff..b7e4424 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -50,7 +50,22 @@ + +
+
Zoom Controls
+ + + +
+
+
Keyboard Shortcuts
Shift Fine-tune position @@ -63,6 +78,30 @@ Esc Close preview
+
+
+ Ctrl + + + + +
+ Zoom in +
+
+
+ Ctrl + + + - +
+ Zoom out +
+
+
+ Ctrl + + + 0 +
+ Reset zoom +
@@ -104,5 +143,5 @@ }; // Expose store methods directly - const { autoArrangeSprites, downloadSpritesheet } = store; + const { autoArrangeSprites, downloadSpritesheet, zoomIn, zoomOut, resetZoom } = store; diff --git a/src/composables/useSpritesheetStore.ts b/src/composables/useSpritesheetStore.ts index 8870169..32ca1e2 100644 --- a/src/composables/useSpritesheetStore.ts +++ b/src/composables/useSpritesheetStore.ts @@ -37,6 +37,7 @@ const draggedSprite = ref(null); const dragOffset = reactive({ x: 0, y: 0 }); const isShiftPressed = ref(false); const isModalOpen = ref(false); +const zoomLevel = ref(1); // Default zoom level (1 = 100%) export function useSpritesheetStore() { const animation = reactive({ @@ -143,6 +144,11 @@ export function useSpritesheetStore() { canvas.value.width = newWidth; canvas.value.height = newHeight; + + // Emit an event to update the wrapper dimensions + window.dispatchEvent(new CustomEvent('canvas-size-updated', { + detail: { width: newWidth, height: newHeight } + })); } catch (error) { console.error('Store: Error updating canvas size:', error); } @@ -206,6 +212,10 @@ export function useSpritesheetStore() { // Clear the canvas ctx.value.clearRect(0, 0, canvas.value.width, canvas.value.height); + // Apply zoom transformation + ctx.value.save(); + ctx.value.scale(zoomLevel.value, zoomLevel.value); + if (showGrid) { drawGrid(); } @@ -226,7 +236,10 @@ export function useSpritesheetStore() { // If image isn't loaded yet, set an onload handler sprite.img.onload = () => { if (ctx.value && canvas.value) { + ctx.value.save(); + ctx.value.scale(zoomLevel.value, zoomLevel.value); ctx.value.drawImage(sprite.img, sprite.x, sprite.y); + ctx.value.restore(); } }; } @@ -234,6 +247,9 @@ export function useSpritesheetStore() { console.error(`Store: Error rendering sprite at index ${index}:`, spriteError); } }); + + // Restore the canvas state + ctx.value.restore(); } catch (error) { console.error('Store: Error rendering spritesheet preview:', error); } @@ -243,21 +259,25 @@ export function useSpritesheetStore() { if (!ctx.value || !canvas.value) return; ctx.value.strokeStyle = '#333'; - ctx.value.lineWidth = 1; + ctx.value.lineWidth = 1 / zoomLevel.value; // Adjust line width based on zoom level + + // Calculate the visible area based on zoom level + const visibleWidth = canvas.value.width / zoomLevel.value; + const visibleHeight = canvas.value.height / zoomLevel.value; // Draw vertical lines - for (let x = 0; x <= canvas.value.width; x += cellSize.width) { + for (let x = 0; x <= visibleWidth; x += cellSize.width) { ctx.value.beginPath(); ctx.value.moveTo(x, 0); - ctx.value.lineTo(x, canvas.value.height); + ctx.value.lineTo(x, visibleHeight); ctx.value.stroke(); } // Draw horizontal lines - for (let y = 0; y <= canvas.value.height; y += cellSize.height) { + for (let y = 0; y <= visibleHeight; y += cellSize.height) { ctx.value.beginPath(); ctx.value.moveTo(0, y); - ctx.value.lineTo(canvas.value.width, y); + ctx.value.lineTo(visibleWidth, y); ctx.value.stroke(); } } @@ -411,6 +431,27 @@ export function useSpritesheetStore() { }, 3000); } + function zoomIn() { + // Increase zoom level by 0.1, max 3.0 (300%) + zoomLevel.value = Math.min(3.0, zoomLevel.value + 0.1); + renderSpritesheetPreview(); + showNotification(`Zoom: ${Math.round(zoomLevel.value * 100)}%`); + } + + function zoomOut() { + // Decrease zoom level by 0.1, min 0.5 (50%) + zoomLevel.value = Math.max(0.5, zoomLevel.value - 0.1); + renderSpritesheetPreview(); + showNotification(`Zoom: ${Math.round(zoomLevel.value * 100)}%`); + } + + function resetZoom() { + // Reset to default zoom level (100%) + zoomLevel.value = 1; + renderSpritesheetPreview(); + showNotification('Zoom reset to 100%'); + } + return { sprites, canvas, @@ -423,6 +464,7 @@ export function useSpritesheetStore() { isModalOpen, animation, notification, + zoomLevel, addSprites, updateCellSize, updateCanvasSize, @@ -436,5 +478,8 @@ export function useSpritesheetStore() { stopAnimation, renderAnimationFrame, showNotification, + zoomIn, + zoomOut, + resetZoom, }; }