[FEAT] add grid metrics

This commit is contained in:
2026-01-01 17:14:21 +01:00
parent 281a37fa7e
commit 1f9fc4d5bb
5 changed files with 352 additions and 128 deletions

View File

@@ -1,7 +1,6 @@
import { ref, computed, type Ref, type ComputedRef } from 'vue';
import type { Sprite, Layer } from '@/types/sprites';
import { getMaxDimensions } from './useSprites';
import { calculateNegativeSpacing } from './useNegativeSpacing';
import { useGridMetrics, type GridMetrics } from './useGridMetrics';
export interface CellPosition {
col: number;
@@ -70,70 +69,42 @@ export function useDragSprite(options: DragSpriteOptions) {
const ghostSprite = ref<{ id: string; x: number; y: number } | null>(null);
const highlightCell = ref<CellPosition | null>(null);
// Cache for max dimensions
const lastMaxWidth = ref(1);
const lastMaxHeight = ref(1);
// Use the new useGridMetrics composable for consistent calculations
const gridMetricsComposable = useGridMetrics({
layers: options.layers,
sprites: options.sprites,
negativeSpacingEnabled: options.negativeSpacingEnabled,
manualCellSizeEnabled: options.manualCellSizeEnabled,
manualCellWidth: options.manualCellWidth,
manualCellHeight: options.manualCellHeight,
});
const calculateMaxDimensions = () => {
const negativeSpacingEnabled = getNegativeSpacingEnabled();
const manualCellSizeEnabled = getManualCellSizeEnabled();
// If manual cell size is enabled, use manual dimensions
if (manualCellSizeEnabled) {
const maxWidth = getManualCellWidth();
const maxHeight = getManualCellHeight();
// When manual cell size is used, negative spacing is not applied
const negativeSpacing = 0;
// Don't update lastMaxWidth/lastMaxHeight when in manual mode
return { maxWidth, maxHeight, negativeSpacing };
}
// Get all sprites to calculate dimensions from
// If layers are provided, use ALL layers (regardless of visibility) to keep canvas size stable
const layers = getLayers();
const spritesToMeasure = layers ? layers.flatMap(l => l.sprites) : getSprites();
// Otherwise, calculate based on sprite dimensions across all visible layers
const base = getMaxDimensions(spritesToMeasure);
// When switching back from manual mode, reset to actual sprite dimensions
const baseMaxWidth = Math.max(1, base.maxWidth);
const baseMaxHeight = Math.max(1, base.maxHeight);
lastMaxWidth.value = baseMaxWidth;
lastMaxHeight.value = baseMaxHeight;
// Calculate negative spacing using shared composable
const negativeSpacing = Math.round(calculateNegativeSpacing(spritesToMeasure, negativeSpacingEnabled));
// Add negative spacing to expand each cell
const maxWidth = Math.round(baseMaxWidth + negativeSpacing);
const maxHeight = Math.round(baseMaxHeight + negativeSpacing);
return { maxWidth, maxHeight, negativeSpacing };
const calculateMaxDimensions = (): GridMetrics => {
return gridMetricsComposable.calculateCellDimensions();
};
// Computed sprite positions
const spritePositions = computed<SpritePosition[]>(() => {
const sprites = getSprites();
const columns = getColumns();
const { maxWidth, maxHeight, negativeSpacing } = calculateMaxDimensions();
const metrics = calculateMaxDimensions();
return sprites.map((sprite, index) => {
const col = index % columns;
const row = Math.floor(index / columns);
const cellPos = gridMetricsComposable.getCellPosition(index, columns, metrics);
const canvasPos = gridMetricsComposable.getSpriteCanvasPosition(sprite, index, columns, metrics);
// With negative spacing, sprites are positioned at bottom-right of cell
// (spacing added to top and left)
return {
id: sprite.id,
canvasX: Math.round(col * maxWidth + negativeSpacing + sprite.x),
canvasY: Math.round(row * maxHeight + negativeSpacing + sprite.y),
cellX: Math.round(col * maxWidth),
cellY: Math.round(row * maxHeight),
canvasX: canvasPos.canvasX,
canvasY: canvasPos.canvasY,
cellX: canvasPos.cellX,
cellY: canvasPos.cellY,
width: Math.round(sprite.width),
height: Math.round(sprite.height),
maxWidth: Math.round(maxWidth),
maxHeight: Math.round(maxHeight),
col,
row,
maxWidth: metrics.maxWidth,
maxHeight: metrics.maxHeight,
col: cellPos.col,
row: cellPos.row,
index,
x: sprite.x,
y: sprite.y,