Skip to content

Commit de11caf

Browse files
refactor(ui): editor (wip)
1 parent 4d9114a commit de11caf

File tree

1 file changed

+58
-84
lines changed
  • invokeai/frontend/web/src/features/editImageModal/lib

1 file changed

+58
-84
lines changed

invokeai/frontend/web/src/features/editImageModal/lib/editor.ts

Lines changed: 58 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export class Editor {
7373
private konva: KonvaObjects | null = null;
7474
private originalImage: HTMLImageElement | null = null;
7575
private isCropping = false;
76-
private appliedCrop: CropBox | null = null;
7776

7877
// Constants
7978
private readonly MIN_CROP_DIMENSION = 64;
@@ -630,52 +629,6 @@ export class Editor {
630629
this.resetView();
631630
};
632631

633-
// Crop Mode
634-
startCrop = (crop?: CropBox) => {
635-
if (!this.konva?.image.image || this.isCropping) {
636-
return;
637-
}
638-
639-
this.unfreezeCropOverlay();
640-
this.isCropping = true;
641-
642-
// Calculate initial crop dimensions
643-
let cropX: number;
644-
let cropY: number;
645-
let cropWidth: number;
646-
let cropHeight: number;
647-
648-
if (crop) {
649-
cropX = crop.x;
650-
cropY = crop.y;
651-
cropWidth = crop.width;
652-
cropHeight = crop.height;
653-
} else if (this.appliedCrop) {
654-
// Use the applied crop as starting point
655-
cropX = this.appliedCrop.x;
656-
cropY = this.appliedCrop.y;
657-
cropWidth = this.appliedCrop.width;
658-
cropHeight = this.appliedCrop.height;
659-
} else {
660-
// Create default crop box (centered, 80% of image)
661-
const imgWidth = this.konva.image.image.width();
662-
const imgHeight = this.konva.image.image.height();
663-
cropWidth = imgWidth * this.DEFAULT_CROP_BOX_SCALE;
664-
cropHeight = imgHeight * this.DEFAULT_CROP_BOX_SCALE;
665-
cropX = (imgWidth - cropWidth) / 2;
666-
cropY = (imgHeight - cropHeight) / 2;
667-
}
668-
669-
this.updateCropBox({
670-
x: cropX,
671-
y: cropY,
672-
width: cropWidth,
673-
height: cropHeight,
674-
});
675-
676-
this.callbacks.onCropStart?.();
677-
};
678-
679632
private resizeCropBox = (handleName: HandleName, handleRect: Konva.Rect) => {
680633
if (!this.konva) {
681634
return;
@@ -972,60 +925,81 @@ export class Editor {
972925
}
973926
};
974927

975-
private freezeCropOverlay = () => {
976-
if (!this.konva) {
928+
// Crop Mode
929+
startCrop = (crop?: CropBox) => {
930+
if (!this.konva?.image.image || this.isCropping) {
977931
return;
978932
}
979933

980-
this.konva.crop.interaction.group.visible(false);
981-
};
934+
// Calculate initial crop dimensions
935+
let cropX: number;
936+
let cropY: number;
937+
let cropWidth: number;
938+
let cropHeight: number;
982939

983-
private unfreezeCropOverlay = () => {
984-
if (!this.konva) {
985-
return;
940+
if (crop) {
941+
cropX = crop.x;
942+
cropY = crop.y;
943+
cropWidth = crop.width;
944+
cropHeight = crop.height;
945+
} else if (this.cropBox) {
946+
// Use the current crop as starting point
947+
cropX = this.cropBox.x;
948+
cropY = this.cropBox.y;
949+
cropWidth = this.cropBox.width;
950+
cropHeight = this.cropBox.height;
951+
} else {
952+
// Create default crop box (centered, 80% of image)
953+
const imgWidth = this.konva.image.image.width();
954+
const imgHeight = this.konva.image.image.height();
955+
cropWidth = imgWidth * this.DEFAULT_CROP_BOX_SCALE;
956+
cropHeight = imgHeight * this.DEFAULT_CROP_BOX_SCALE;
957+
cropX = (imgWidth - cropWidth) / 2;
958+
cropY = (imgHeight - cropHeight) / 2;
986959
}
987960

961+
this.updateCropBox({
962+
x: cropX,
963+
y: cropY,
964+
width: cropWidth,
965+
height: cropHeight,
966+
});
967+
this.isCropping = true;
988968
this.konva.crop.interaction.group.visible(true);
989-
};
990969

991-
resetEphemeralCropState = () => {
992-
this.isCropping = false;
970+
this.callbacks.onCropStart?.();
993971
};
994972

995973
cancelCrop = () => {
996-
if (!this.isCropping || !this.konva?.crop) {
974+
if (!this.isCropping || !this.konva) {
997975
return;
998976
}
999-
this.resetEphemeralCropState();
1000-
977+
this.isCropping = false;
978+
this.konva.crop.interaction.group.visible(false);
1001979
this.callbacks.onCropCancel?.();
1002980
};
1003981

1004982
applyCrop = () => {
1005-
if (!this.isCropping || !this.cropBox) {
983+
if (!this.isCropping || !this.cropBox || !this.konva) {
1006984
return;
1007985
}
1008986

1009-
// Store the crop dimensions
1010-
this.appliedCrop = { ...this.cropBox };
1011-
1012-
// Freeze the crop overlay instead of redisplaying image
1013-
this.freezeCropOverlay();
1014-
1015987
this.isCropping = false;
1016-
this.callbacks.onCropApply?.(this.appliedCrop);
988+
this.konva.crop.interaction.group.visible(false);
989+
this.callbacks.onCropApply?.(this.cropBox);
1017990
};
1018991

1019992
resetCrop = () => {
1020-
this.appliedCrop = null;
1021-
993+
if (this.konva?.image.image) {
994+
this.updateCropBox({
995+
x: 0,
996+
y: 0,
997+
...this.konva.image.image.size(),
998+
});
999+
}
10221000
this.callbacks.onCropReset?.();
10231001
};
10241002

1025-
hasCrop = (): boolean => {
1026-
return !!this.appliedCrop;
1027-
};
1028-
10291003
// Export
10301004
exportImage = <T extends 'canvas' | 'blob' | 'dataURL'>(
10311005
format: T = 'blob' as T
@@ -1045,20 +1019,20 @@ export class Editor {
10451019
}
10461020

10471021
try {
1048-
if (this.appliedCrop) {
1049-
canvas.width = this.appliedCrop.width;
1050-
canvas.height = this.appliedCrop.height;
1022+
if (this.cropBox) {
1023+
canvas.width = this.cropBox.width;
1024+
canvas.height = this.cropBox.height;
10511025

10521026
ctx.drawImage(
10531027
this.originalImage,
1054-
this.appliedCrop.x,
1055-
this.appliedCrop.y,
1056-
this.appliedCrop.width,
1057-
this.appliedCrop.height,
1028+
this.cropBox.x,
1029+
this.cropBox.y,
1030+
this.cropBox.width,
1031+
this.cropBox.height,
10581032
0,
10591033
0,
1060-
this.appliedCrop.width,
1061-
this.appliedCrop.height
1034+
this.cropBox.width,
1035+
this.cropBox.height
10621036
);
10631037
} else {
10641038
canvas.width = this.originalImage.width;
@@ -1321,7 +1295,7 @@ export class Editor {
13211295
// Clear all references
13221296
this.konva = null;
13231297
this.originalImage = null;
1324-
this.appliedCrop = null;
1298+
this.cropBox = null;
13251299
this.callbacks = {};
13261300
};
13271301
}

0 commit comments

Comments
 (0)