Finish clean, add negative spacing toggle

This commit is contained in:
2025-11-18 20:27:06 +01:00
parent 5c33e77595
commit 590d76205f
5 changed files with 92 additions and 29 deletions

View File

@@ -30,6 +30,7 @@ export interface DragSpriteOptions {
columns: Ref<number> | number;
zoom?: Ref<number>;
allowCellSwap?: Ref<boolean>;
negativeSpacingEnabled?: Ref<boolean>;
getMousePosition: (event: MouseEvent, zoom?: number) => { x: number; y: number } | null;
onUpdateSprite: (id: string, x: number, y: number) => void;
onUpdateSpriteCell?: (id: string, newIndex: number) => void;
@@ -44,6 +45,7 @@ export function useDragSprite(options: DragSpriteOptions) {
const getColumns = () => (typeof options.columns === 'number' ? options.columns : options.columns.value);
const getZoom = () => options.zoom?.value ?? 1;
const getAllowCellSwap = () => options.allowCellSwap?.value ?? false;
const getNegativeSpacingEnabled = () => options.negativeSpacingEnabled?.value ?? false;
// Drag state
const isDragging = ref(false);
@@ -65,28 +67,47 @@ export function useDragSprite(options: DragSpriteOptions) {
const calculateMaxDimensions = () => {
const sprites = getSprites();
const negativeSpacingEnabled = getNegativeSpacingEnabled();
const base = getMaxDimensions(sprites);
const maxWidth = Math.max(1, base.maxWidth, lastMaxWidth.value);
const maxHeight = Math.max(1, base.maxHeight, lastMaxHeight.value);
lastMaxWidth.value = maxWidth;
lastMaxHeight.value = maxHeight;
return { maxWidth, maxHeight };
const baseMaxWidth = Math.max(1, base.maxWidth, lastMaxWidth.value);
const baseMaxHeight = Math.max(1, base.maxHeight, lastMaxHeight.value);
lastMaxWidth.value = baseMaxWidth;
lastMaxHeight.value = baseMaxHeight;
// Calculate negative spacing based on sprite size differences
let negativeSpacing = 0;
if (negativeSpacingEnabled && sprites.length > 0) {
// Find the smallest sprite dimensions
const minWidth = Math.min(...sprites.map(s => s.width));
const minHeight = Math.min(...sprites.map(s => s.height));
// Negative spacing is the difference between max and min dimensions
const widthDiff = baseMaxWidth - minWidth;
const heightDiff = baseMaxHeight - minHeight;
negativeSpacing = Math.max(widthDiff, heightDiff);
}
// Add negative spacing to expand each cell
const maxWidth = baseMaxWidth + negativeSpacing;
const maxHeight = baseMaxHeight + negativeSpacing;
return { maxWidth, maxHeight, negativeSpacing };
};
// Computed sprite positions
const spritePositions = computed<SpritePosition[]>(() => {
const sprites = getSprites();
const columns = getColumns();
const { maxWidth, maxHeight } = calculateMaxDimensions();
const { maxWidth, maxHeight, negativeSpacing } = calculateMaxDimensions();
return sprites.map((sprite, index) => {
const col = index % columns;
const row = Math.floor(index / columns);
// With negative spacing, sprites are positioned at bottom-right of cell
// (spacing added to top and left)
return {
id: sprite.id,
canvasX: col * maxWidth + sprite.x,
canvasY: row * maxHeight + sprite.y,
canvasX: col * maxWidth + negativeSpacing + sprite.x,
canvasY: row * maxHeight + negativeSpacing + sprite.y,
cellX: col * maxWidth,
cellY: row * maxHeight,
width: sprite.width,
@@ -162,7 +183,7 @@ export function useDragSprite(options: DragSpriteOptions) {
if (!activeSpriteId.value) return;
const sprites = getSprites();
const columns = getColumns();
const { maxWidth, maxHeight } = calculateMaxDimensions();
const { maxWidth, maxHeight, negativeSpacing } = calculateMaxDimensions();
// Use the sprite's current index in the array to calculate cell position
const cellCol = spriteIndex % columns;
@@ -170,11 +191,15 @@ export function useDragSprite(options: DragSpriteOptions) {
const cellX = cellCol * maxWidth;
const cellY = cellRow * maxHeight;
const newX = mouseX - cellX - dragOffsetX.value;
const newY = mouseY - cellY - dragOffsetY.value;
// Calculate new position relative to cell origin (without the negative spacing offset)
// The sprite's x,y is stored relative to where it would be drawn after the negativeSpacing offset
const newX = mouseX - cellX - negativeSpacing - dragOffsetX.value;
const newY = mouseY - cellY - negativeSpacing - dragOffsetY.value;
const constrainedX = Math.floor(Math.max(0, Math.min(maxWidth - sprites[spriteIndex].width, newX)));
const constrainedY = Math.floor(Math.max(0, Math.min(maxHeight - sprites[spriteIndex].height, newY)));
// The sprite can move within the full expanded cell area
// Allow negative values up to -negativeSpacing so sprite can fill the expanded area
const constrainedX = Math.floor(Math.max(-negativeSpacing, Math.min(maxWidth - negativeSpacing - sprites[spriteIndex].width, newX)));
const constrainedY = Math.floor(Math.max(-negativeSpacing, Math.min(maxHeight - negativeSpacing - sprites[spriteIndex].height, newY)));
onUpdateSprite(activeSpriteId.value, constrainedX, constrainedY);
onDraw();