145 lines
4.1 KiB
TypeScript
145 lines
4.1 KiB
TypeScript
|
|
import { BaseCommand } from './base-command';
|
||
|
|
import type { Layer, TransformState, TransformBounds } from '@/types';
|
||
|
|
import { useLayerStore } from '@/store/layer-store';
|
||
|
|
import { applyTransformToCanvas } from '@/lib/transform-utils';
|
||
|
|
import { cloneCanvas } from '@/lib/canvas-utils';
|
||
|
|
|
||
|
|
export class TransformCommand extends BaseCommand {
|
||
|
|
private layerId: string;
|
||
|
|
private beforeCanvas: HTMLCanvasElement | null = null;
|
||
|
|
private beforePosition: { x: number; y: number };
|
||
|
|
private afterCanvas: HTMLCanvasElement | null = null;
|
||
|
|
private afterPosition: { x: number; y: number } | null = null;
|
||
|
|
private transformState: TransformState;
|
||
|
|
private originalBounds: TransformBounds;
|
||
|
|
|
||
|
|
constructor(
|
||
|
|
layer: Layer,
|
||
|
|
transformState: TransformState,
|
||
|
|
originalBounds: TransformBounds
|
||
|
|
) {
|
||
|
|
super('Transform Layer');
|
||
|
|
this.layerId = layer.id;
|
||
|
|
this.transformState = transformState;
|
||
|
|
this.originalBounds = originalBounds;
|
||
|
|
|
||
|
|
// Store before state
|
||
|
|
if (layer.canvas) {
|
||
|
|
this.beforeCanvas = cloneCanvas(layer.canvas);
|
||
|
|
}
|
||
|
|
this.beforePosition = { x: layer.x, y: layer.y };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Capture the state after applying the transform
|
||
|
|
*/
|
||
|
|
captureAfterState(layer: Layer): void {
|
||
|
|
if (layer.canvas) {
|
||
|
|
this.afterCanvas = cloneCanvas(layer.canvas);
|
||
|
|
}
|
||
|
|
this.afterPosition = { x: layer.x, y: layer.y };
|
||
|
|
}
|
||
|
|
|
||
|
|
execute(): void {
|
||
|
|
if (!this.afterCanvas || !this.afterPosition) {
|
||
|
|
// Apply transform for the first time
|
||
|
|
this.applyTransform();
|
||
|
|
} else {
|
||
|
|
// Restore after state
|
||
|
|
const { updateLayer } = useLayerStore.getState();
|
||
|
|
const layer = this.getLayer();
|
||
|
|
if (!layer?.canvas) return;
|
||
|
|
|
||
|
|
const ctx = layer.canvas.getContext('2d');
|
||
|
|
if (ctx) {
|
||
|
|
ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
||
|
|
ctx.drawImage(this.afterCanvas, 0, 0);
|
||
|
|
|
||
|
|
updateLayer(layer.id, {
|
||
|
|
x: this.afterPosition.x,
|
||
|
|
y: this.afterPosition.y,
|
||
|
|
updatedAt: Date.now(),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
undo(): void {
|
||
|
|
if (!this.beforeCanvas) return;
|
||
|
|
|
||
|
|
const { updateLayer } = useLayerStore.getState();
|
||
|
|
const layer = this.getLayer();
|
||
|
|
if (!layer?.canvas) return;
|
||
|
|
|
||
|
|
const ctx = layer.canvas.getContext('2d');
|
||
|
|
if (ctx) {
|
||
|
|
ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
||
|
|
ctx.drawImage(this.beforeCanvas, 0, 0);
|
||
|
|
|
||
|
|
updateLayer(layer.id, {
|
||
|
|
x: this.beforePosition.x,
|
||
|
|
y: this.beforePosition.y,
|
||
|
|
updatedAt: Date.now(),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private applyTransform(): void {
|
||
|
|
const layer = this.getLayer();
|
||
|
|
if (!layer?.canvas || !this.beforeCanvas) return;
|
||
|
|
|
||
|
|
// Apply transform to canvas
|
||
|
|
const transformedCanvas = applyTransformToCanvas(
|
||
|
|
this.beforeCanvas,
|
||
|
|
this.transformState,
|
||
|
|
this.originalBounds
|
||
|
|
);
|
||
|
|
|
||
|
|
// Update layer canvas
|
||
|
|
const ctx = layer.canvas.getContext('2d');
|
||
|
|
if (ctx) {
|
||
|
|
// Resize canvas if needed
|
||
|
|
if (
|
||
|
|
layer.canvas.width !== transformedCanvas.width ||
|
||
|
|
layer.canvas.height !== transformedCanvas.height
|
||
|
|
) {
|
||
|
|
layer.canvas.width = transformedCanvas.width;
|
||
|
|
layer.canvas.height = transformedCanvas.height;
|
||
|
|
}
|
||
|
|
|
||
|
|
ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
||
|
|
ctx.drawImage(transformedCanvas, 0, 0);
|
||
|
|
|
||
|
|
// Update layer position and size
|
||
|
|
const { updateLayer } = useLayerStore.getState();
|
||
|
|
updateLayer(layer.id, {
|
||
|
|
x: this.originalBounds.x + this.transformState.x,
|
||
|
|
y: this.originalBounds.y + this.transformState.y,
|
||
|
|
width: transformedCanvas.width,
|
||
|
|
height: transformedCanvas.height,
|
||
|
|
updatedAt: Date.now(),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
this.captureAfterState(layer);
|
||
|
|
}
|
||
|
|
|
||
|
|
private getLayer(): Layer | undefined {
|
||
|
|
const { layers } = useLayerStore.getState();
|
||
|
|
return layers.find((l) => l.id === this.layerId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Static method to create and execute a transform command
|
||
|
|
*/
|
||
|
|
static applyToLayer(
|
||
|
|
layer: Layer,
|
||
|
|
transformState: TransformState,
|
||
|
|
originalBounds: TransformBounds
|
||
|
|
): TransformCommand {
|
||
|
|
const command = new TransformCommand(layer, transformState, originalBounds);
|
||
|
|
command.execute();
|
||
|
|
return command;
|
||
|
|
}
|
||
|
|
}
|