Fixes
This commit is contained in:
parent
1a16457efc
commit
293bed9135
@ -57,15 +57,7 @@
|
|||||||
<button @click="zoomIn" :disabled="previewZoom >= 5" class="flex items-center justify-center w-8 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500">
|
<button @click="zoomIn" :disabled="previewZoom >= 5" class="flex items-center justify-center w-8 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500">
|
||||||
<i class="fas fa-search-plus"></i>
|
<i class="fas fa-search-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<!-- Apply Offset button removed -->
|
||||||
@click="applyOffsetsToMainView"
|
|
||||||
:disabled="!hasSpriteOffset"
|
|
||||||
class="flex items-center gap-1 px-2 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded text-xs transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500"
|
|
||||||
title="Permanently apply offset to sprite position"
|
|
||||||
>
|
|
||||||
<i class="fas fa-save"></i>
|
|
||||||
Apply Offset
|
|
||||||
</button>
|
|
||||||
<button @click="resetZoom" :disabled="previewZoom === 1" class="flex items-center justify-center px-2 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded text-xs transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500">Reset Zoom</button>
|
<button @click="resetZoom" :disabled="previewZoom === 1" class="flex items-center justify-center px-2 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded text-xs transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500">Reset Zoom</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -78,23 +70,17 @@
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<!-- Reset sprite position button -->
|
<!-- Reset sprite position button -->
|
||||||
<button
|
<button @click="resetSpritePosition" :disabled="!hasSpriteOffset" class="flex items-center gap-1 px-2 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded text-xs transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500" title="Center sprite in cell">
|
||||||
@click="resetSpritePosition"
|
|
||||||
:disabled="!hasSpriteOffset"
|
|
||||||
class="flex items-center gap-1 px-2 h-8 bg-gray-700 text-gray-200 border border-gray-600 rounded text-xs transition-colors disabled:opacity-60 disabled:cursor-not-allowed hover:border-blue-500"
|
|
||||||
title="Reset sprite to original position"
|
|
||||||
>
|
|
||||||
<i class="fas fa-crosshairs"></i>
|
<i class="fas fa-crosshairs"></i>
|
||||||
Reset Position
|
Center Sprite
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col justify-center items-center bg-gray-700 p-6 rounded mb-6 relative overflow-auto flex-grow">
|
<div class="flex flex-col justify-center items-center bg-gray-700 p-6 rounded mb-6 relative overflow-auto flex-grow">
|
||||||
<!-- Tooltip for dragging instructions -->
|
<!-- Tooltip for dragging instructions -->
|
||||||
<div class="text-xs text-gray-400 mb-2" v-if="hasSpriteOffset || sprites.length > 0">
|
<div class="text-xs text-gray-400 mb-2" v-if="sprites.length > 0">
|
||||||
<span v-if="hasSpriteOffset">Sprite offset: {{ Math.round(spriteOffset.x) }}px, {{ Math.round(spriteOffset.y) }}px</span>
|
<span>Position: {{ Math.round(spriteOffset.x) }}px, {{ Math.round(spriteOffset.y) }}px (drag to move within cell)</span>
|
||||||
<span v-else>Click and drag the sprite to move it within the cell</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -201,10 +187,7 @@
|
|||||||
return spriteOffset.x !== 0 || spriteOffset.y !== 0;
|
return spriteOffset.x !== 0 || spriteOffset.y !== 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
const applyOffsetsToMainView = () => {
|
// applyOffsetsToMainView function removed
|
||||||
store.applyOffsetsToMainView();
|
|
||||||
store.showNotification('Offset permanently applied to sprite position');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (!isModalOpen.value) return;
|
if (!isModalOpen.value) return;
|
||||||
@ -245,33 +228,17 @@
|
|||||||
resetSpritePosition();
|
resetSpritePosition();
|
||||||
} else {
|
} else {
|
||||||
// R: Reset both sprite position and viewport
|
// R: Reset both sprite position and viewport
|
||||||
// Reset the sprite offset for the current frame
|
resetSpritePosition();
|
||||||
const frameOffset = store.getSpriteOffset(currentFrame.value);
|
|
||||||
frameOffset.x = 0;
|
|
||||||
frameOffset.y = 0;
|
|
||||||
store.currentSpriteOffset.x = 0;
|
|
||||||
store.currentSpriteOffset.y = 0;
|
|
||||||
viewportOffset.value = { x: 0, y: 0 };
|
|
||||||
updateFrame();
|
updateFrame();
|
||||||
store.showNotification('View and position reset');
|
store.showNotification('View and position reset');
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (previewZoom.value > 1) {
|
} else if (e.key === 'ArrowLeft' && animation.value.isPlaying) {
|
||||||
// Arrow key navigation for panning when zoomed in
|
viewportOffset.value.x += panAmount / previewZoom.value;
|
||||||
const panAmount = 10;
|
e.preventDefault();
|
||||||
if (e.key === 'ArrowUp') {
|
} else if (e.key === 'ArrowRight' && animation.value.isPlaying) {
|
||||||
viewportOffset.value.y += panAmount / previewZoom.value;
|
viewportOffset.value.x -= panAmount / previewZoom.value;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (e.key === 'ArrowDown') {
|
|
||||||
viewportOffset.value.y -= panAmount / previewZoom.value;
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (e.key === 'ArrowLeft' && animation.value.isPlaying) {
|
|
||||||
viewportOffset.value.x += panAmount / previewZoom.value;
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (e.key === 'ArrowRight' && animation.value.isPlaying) {
|
|
||||||
viewportOffset.value.x -= panAmount / previewZoom.value;
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,9 +282,22 @@
|
|||||||
|
|
||||||
// Force render the first frame
|
// Force render the first frame
|
||||||
if (sprites.value.length > 0) {
|
if (sprites.value.length > 0) {
|
||||||
|
// Get the current sprite
|
||||||
|
const currentSprite = sprites.value[0];
|
||||||
|
|
||||||
|
// Calculate center position
|
||||||
|
const centerX = Math.max(0, Math.floor((store.cellSize.width - currentSprite.width) / 2));
|
||||||
|
const centerY = Math.max(0, Math.floor((store.cellSize.height - currentSprite.height) / 2));
|
||||||
|
|
||||||
// Get the frame-specific offset for the first frame
|
// Get the frame-specific offset for the first frame
|
||||||
const frameOffset = store.getSpriteOffset(0);
|
const frameOffset = store.getSpriteOffset(0);
|
||||||
|
|
||||||
|
// If the offset is (0,0), center the sprite
|
||||||
|
if (frameOffset.x === 0 && frameOffset.y === 0) {
|
||||||
|
frameOffset.x = centerX;
|
||||||
|
frameOffset.y = centerY;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the current offset for UI display
|
// Update the current offset for UI display
|
||||||
store.currentSpriteOffset.x = frameOffset.x;
|
store.currentSpriteOffset.x = frameOffset.x;
|
||||||
store.currentSpriteOffset.y = frameOffset.y;
|
store.currentSpriteOffset.y = frameOffset.y;
|
||||||
@ -448,22 +428,30 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset sprite position to original
|
// Reset sprite position to center
|
||||||
const resetSpritePosition = () => {
|
const resetSpritePosition = () => {
|
||||||
// Reset the sprite offset for the current frame to zero
|
// Get current sprite
|
||||||
|
const currentSprite = sprites.value[currentFrame.value];
|
||||||
|
if (!currentSprite) return;
|
||||||
|
|
||||||
|
// Calculate center position
|
||||||
|
const centerX = Math.max(0, Math.floor((store.cellSize.width - currentSprite.width) / 2));
|
||||||
|
const centerY = Math.max(0, Math.floor((store.cellSize.height - currentSprite.height) / 2));
|
||||||
|
|
||||||
|
// Reset the sprite offset for the current frame to the center position
|
||||||
const frameOffset = store.getSpriteOffset(currentFrame.value);
|
const frameOffset = store.getSpriteOffset(currentFrame.value);
|
||||||
frameOffset.x = 0;
|
frameOffset.x = centerX;
|
||||||
frameOffset.y = 0;
|
frameOffset.y = centerY;
|
||||||
|
|
||||||
// Also update the current offset
|
// Also update the current offset
|
||||||
store.currentSpriteOffset.x = 0;
|
store.currentSpriteOffset.x = centerX;
|
||||||
store.currentSpriteOffset.y = 0;
|
store.currentSpriteOffset.y = centerY;
|
||||||
|
|
||||||
// Update the frame to reflect the change
|
// Update the frame to reflect the change
|
||||||
updateFrame();
|
updateFrame();
|
||||||
|
|
||||||
// Show a notification
|
// Show a notification
|
||||||
store.showNotification('Sprite position reset to original');
|
store.showNotification('Sprite position reset to center');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update canvas container size based on zoom level
|
// Update canvas container size based on zoom level
|
||||||
@ -477,74 +465,85 @@
|
|||||||
// Canvas drag functions for moving the sprite within its cell
|
// Canvas drag functions for moving the sprite within its cell
|
||||||
const startCanvasDrag = (e: MouseEvent) => {
|
const startCanvasDrag = (e: MouseEvent) => {
|
||||||
if (sprites.value.length === 0) return;
|
if (sprites.value.length === 0) return;
|
||||||
|
|
||||||
// Don't start sprite dragging if we're already dragging the viewport
|
|
||||||
if (isViewportDragging.value) return;
|
if (isViewportDragging.value) return;
|
||||||
|
|
||||||
isCanvasDragging.value = true;
|
isCanvasDragging.value = true;
|
||||||
|
|
||||||
|
// Store initial position
|
||||||
canvasDragStart.value = {
|
canvasDragStart.value = {
|
||||||
x: e.clientX,
|
x: e.clientX,
|
||||||
y: e.clientY,
|
y: e.clientY,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add temporary event listeners
|
window.addEventListener('mousemove', handleCanvasDrag, { capture: true });
|
||||||
window.addEventListener('mousemove', handleCanvasDrag);
|
window.addEventListener('mouseup', stopCanvasDrag, { capture: true });
|
||||||
window.addEventListener('mouseup', stopCanvasDrag);
|
|
||||||
|
|
||||||
// Prevent default to avoid text selection
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCanvasDrag = (e: MouseEvent) => {
|
const handleCanvasDrag = (e: MouseEvent) => {
|
||||||
if (!isCanvasDragging.value) return;
|
if (!isCanvasDragging.value) return;
|
||||||
|
|
||||||
const deltaX = e.clientX - canvasDragStart.value.x;
|
|
||||||
const deltaY = e.clientY - canvasDragStart.value.y;
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
// Get the frame-specific offset
|
|
||||||
const frameOffset = store.getSpriteOffset(currentFrame.value);
|
|
||||||
|
|
||||||
// Calculate new position and round to nearest pixel
|
|
||||||
const newX = Math.round(frameOffset.x + deltaX / previewZoom.value);
|
|
||||||
const newY = Math.round(frameOffset.y + deltaY / previewZoom.value);
|
|
||||||
|
|
||||||
// Get current sprite
|
// Get current sprite
|
||||||
const currentSprite = sprites.value[currentFrame.value];
|
const currentSprite = sprites.value[currentFrame.value];
|
||||||
if (!currentSprite) return;
|
if (!currentSprite) return;
|
||||||
|
|
||||||
// Calculate maximum allowed offset based on sprite and cell size
|
// Calculate delta from last position
|
||||||
const maxOffsetX = Math.floor((store.cellSize.width - currentSprite.width) / 2);
|
const deltaX = e.clientX - canvasDragStart.value.x;
|
||||||
const maxOffsetY = Math.floor((store.cellSize.height - currentSprite.height) / 2);
|
const deltaY = e.clientY - canvasDragStart.value.y;
|
||||||
|
|
||||||
// Constrain movement to stay within cell boundaries, preventing negative offsets
|
// Only move when delta exceeds the threshold for one pixel movement at current zoom
|
||||||
const constrainedX = Math.max(0, Math.min(maxOffsetX, newX));
|
const pixelThreshold = previewZoom.value; // One pixel at current zoom level
|
||||||
const constrainedY = Math.max(0, Math.min(maxOffsetY, newY));
|
|
||||||
|
|
||||||
// Update both the current offset and the frame-specific offset
|
// Get the frame-specific offset
|
||||||
frameOffset.x = constrainedX;
|
const frameOffset = store.getSpriteOffset(currentFrame.value);
|
||||||
frameOffset.y = constrainedY;
|
|
||||||
store.currentSpriteOffset.x = constrainedX;
|
|
||||||
store.currentSpriteOffset.y = constrainedY;
|
|
||||||
|
|
||||||
// Reset drag start position
|
// Calculate the maximum allowed offset
|
||||||
canvasDragStart.value = {
|
const maxOffsetX = Math.max(0, store.cellSize.width - currentSprite.width);
|
||||||
x: e.clientX,
|
const maxOffsetY = Math.max(0, store.cellSize.height - currentSprite.height);
|
||||||
y: e.clientY,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the frame with the new offset
|
// Move one pixel at a time when threshold is reached
|
||||||
|
if (Math.abs(deltaX) >= pixelThreshold) {
|
||||||
|
const pixelsToMove = Math.sign(deltaX);
|
||||||
|
const newX = frameOffset.x + pixelsToMove;
|
||||||
|
frameOffset.x = Math.max(0, Math.min(maxOffsetX, newX));
|
||||||
|
|
||||||
|
// Reset the start X position for next pixel move
|
||||||
|
canvasDragStart.value.x = e.clientX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(deltaY) >= pixelThreshold) {
|
||||||
|
const pixelsToMove = Math.sign(deltaY);
|
||||||
|
const newY = frameOffset.y + pixelsToMove;
|
||||||
|
frameOffset.y = Math.max(0, Math.min(maxOffsetY, newY));
|
||||||
|
|
||||||
|
// Reset the start Y position for next pixel move
|
||||||
|
canvasDragStart.value.y = e.clientY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the current offset to match
|
||||||
|
store.currentSpriteOffset.x = frameOffset.x;
|
||||||
|
store.currentSpriteOffset.y = frameOffset.y;
|
||||||
|
|
||||||
|
// Update the frame
|
||||||
updateFrame();
|
updateFrame();
|
||||||
|
|
||||||
// Re-render the main view to reflect the changes
|
// Re-render the main view
|
||||||
store.renderSpritesheetPreview();
|
store.renderSpritesheetPreview();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopCanvasDrag = () => {
|
const stopCanvasDrag = (e: MouseEvent) => {
|
||||||
|
if (!isCanvasDragging.value) return;
|
||||||
|
|
||||||
isCanvasDragging.value = false;
|
isCanvasDragging.value = false;
|
||||||
window.removeEventListener('mousemove', handleCanvasDrag);
|
window.removeEventListener('mousemove', handleCanvasDrag, { capture: true });
|
||||||
window.removeEventListener('mouseup', stopCanvasDrag);
|
window.removeEventListener('mouseup', stopCanvasDrag, { capture: true });
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Canvas viewport navigation functions
|
// Canvas viewport navigation functions
|
||||||
|
@ -527,8 +527,9 @@ export function useSpritesheetStore() {
|
|||||||
const originalOffsetY = Math.round(currentSprite.y - cellY * cellSize.height);
|
const originalOffsetY = Math.round(currentSprite.y - cellY * cellSize.height);
|
||||||
|
|
||||||
// Calculate precise offset for pixel-perfect rendering, including the user's drag offset
|
// Calculate precise offset for pixel-perfect rendering, including the user's drag offset
|
||||||
const offsetX = originalOffsetX + spriteOffset.x;
|
// Use the spriteOffset directly as the position within the cell
|
||||||
const offsetY = originalOffsetY + spriteOffset.y;
|
const offsetX = spriteOffset.x;
|
||||||
|
const offsetY = spriteOffset.y;
|
||||||
|
|
||||||
// Draw the current sprite at full opacity at the new position
|
// Draw the current sprite at full opacity at the new position
|
||||||
animation.ctx.drawImage(currentSprite.img, offsetX, offsetY);
|
animation.ctx.drawImage(currentSprite.img, offsetX, offsetY);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user