## [1.7.0] - 2025-11-22
- Add layer support - Add background color picker - Improved UI
This commit is contained in:
@@ -116,9 +116,10 @@ export function useCanvas2D(canvasRef: Ref<HTMLCanvasElement | null>, options?:
|
||||
});
|
||||
};
|
||||
|
||||
// Fill cell background with theme-aware color
|
||||
// Fill cell background with selected color or transparent
|
||||
const fillCellBackground = (x: number, y: number, width: number, height: number) => {
|
||||
const color = settingsStore.darkMode ? '#1F2937' : '#f9fafb';
|
||||
if (settingsStore.backgroundColor === 'transparent') return;
|
||||
const color = settingsStore.backgroundColor === 'custom' ? settingsStore.backgroundColor : settingsStore.backgroundColor;
|
||||
fillRect(x, y, width, height, color);
|
||||
};
|
||||
|
||||
|
||||
@@ -156,8 +156,6 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>, negative
|
||||
|
||||
sprites.value.forEach(sprite => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = '#f9fafb';
|
||||
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||
ctx.drawImage(sprite.img, Math.floor(negativeSpacing + sprite.x), Math.floor(negativeSpacing + sprite.y));
|
||||
gif.addFrame(ctx, { copy: true, delay: 1000 / fps });
|
||||
});
|
||||
@@ -194,8 +192,6 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>, negative
|
||||
|
||||
sprites.value.forEach((sprite, index) => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = '#f9fafb';
|
||||
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||
ctx.drawImage(sprite.img, Math.floor(negativeSpacing + sprite.x), Math.floor(negativeSpacing + sprite.y));
|
||||
const dataURL = canvas.toDataURL('image/png');
|
||||
const binary = atob(dataURL.split(',')[1]);
|
||||
|
||||
@@ -6,14 +6,17 @@ import type { Layer, Sprite } from '@/types/sprites';
|
||||
import { getMaxDimensionsAcrossLayers } from './useLayers';
|
||||
import { calculateNegativeSpacing } from './useNegativeSpacing';
|
||||
|
||||
export const useExportLayers = (layersRef: Ref<Layer[]>, columns: Ref<number>, negativeSpacingEnabled: Ref<boolean>) => {
|
||||
export const useExportLayers = (layersRef: Ref<Layer[]>, columns: Ref<number>, negativeSpacingEnabled: Ref<boolean>, activeLayerId?: Ref<string>, backgroundColor?: Ref<string>) => {
|
||||
const getVisibleLayers = () => layersRef.value.filter(l => l.visible);
|
||||
const getAllVisibleSprites = () => getVisibleLayers().flatMap(l => l.sprites);
|
||||
|
||||
const drawCompositeCell = (ctx: CanvasRenderingContext2D, cellIndex: number, cellWidth: number, cellHeight: number, negativeSpacing: number) => {
|
||||
ctx.clearRect(0, 0, cellWidth, cellHeight);
|
||||
ctx.fillStyle = '#f9fafb';
|
||||
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||
// Apply background color if not transparent
|
||||
if (backgroundColor?.value && backgroundColor.value !== 'transparent') {
|
||||
ctx.fillStyle = backgroundColor.value;
|
||||
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||
}
|
||||
const vLayers = getVisibleLayers();
|
||||
vLayers.forEach(layer => {
|
||||
const sprite = layer.sprites[cellIndex];
|
||||
@@ -130,16 +133,32 @@ export const useExportLayers = (layersRef: Ref<Layer[]>, columns: Ref<number>, n
|
||||
const sprites: Sprite[] = await Promise.all(layerData.sprites.map((s: any) => loadSprite(s)));
|
||||
newLayers.push({ id: layerData.id || crypto.randomUUID(), name: layerData.name || 'Layer', visible: layerData.visible !== false, locked: !!layerData.locked, sprites });
|
||||
}
|
||||
// Ensure at least one layer with sprites is visible
|
||||
if (newLayers.length > 0 && !newLayers.some(l => l.visible && l.sprites.length > 0)) {
|
||||
const firstLayerWithSprites = newLayers.find(l => l.sprites.length > 0);
|
||||
if (firstLayerWithSprites) {
|
||||
firstLayerWithSprites.visible = true;
|
||||
}
|
||||
}
|
||||
layersRef.value = newLayers;
|
||||
// Set active layer to the first layer with sprites
|
||||
if (activeLayerId && newLayers.length > 0) {
|
||||
const firstWithSprites = newLayers.find(l => l.sprites.length > 0);
|
||||
activeLayerId.value = firstWithSprites ? firstWithSprites.id : newLayers[0].id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(data.sprites)) {
|
||||
const sprites: Sprite[] = await Promise.all(data.sprites.map((s: any) => loadSprite(s)));
|
||||
const baseLayerId = crypto.randomUUID();
|
||||
layersRef.value = [
|
||||
{ id: crypto.randomUUID(), name: 'Base', visible: true, locked: false, sprites },
|
||||
{ id: crypto.randomUUID(), name: 'Clothes', visible: true, locked: false, sprites: [] },
|
||||
{ id: baseLayerId, name: 'Base', visible: true, locked: false, sprites },
|
||||
{ id: crypto.randomUUID(), name: 'Other', visible: true, locked: false, sprites: [] },
|
||||
];
|
||||
if (activeLayerId) {
|
||||
activeLayerId.value = baseLayerId;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -222,9 +241,7 @@ export const useExportLayers = (layersRef: Ref<Layer[]>, columns: Ref<number>, n
|
||||
name: layer.name,
|
||||
visible: layer.visible,
|
||||
locked: layer.locked,
|
||||
sprites: await Promise.all(
|
||||
layer.sprites.map(async s => ({ id: s.id, width: s.width, height: s.height, x: s.x, y: s.y, name: s.file.name }))
|
||||
),
|
||||
sprites: await Promise.all(layer.sprites.map(async s => ({ id: s.id, width: s.width, height: s.height, x: s.x, y: s.y, name: s.file.name }))),
|
||||
}))
|
||||
);
|
||||
const meta = { version: 2, columns: columns.value, negativeSpacingEnabled: negativeSpacingEnabled.value, layers: layersPayload };
|
||||
|
||||
@@ -200,6 +200,6 @@ export const useLayers = () => {
|
||||
};
|
||||
|
||||
export const getMaxDimensionsAcrossLayers = (layers: Layer[]) => {
|
||||
const sprites = layers.flatMap(l => l.visible ? l.sprites : []);
|
||||
const sprites = layers.flatMap(l => (l.visible ? l.sprites : []));
|
||||
return getMaxDimensionsSingle(sprites);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user