mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): trying to fix flicker after transform
This commit is contained in:
parent
ea02323095
commit
1ddea87c35
@ -7,15 +7,16 @@ import { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
|||||||
import { CanvasRect } from 'features/controlLayers/konva/CanvasRect';
|
import { CanvasRect } from 'features/controlLayers/konva/CanvasRect';
|
||||||
import { getBrushLineId, getEraserLineId, getRectShapeId } from 'features/controlLayers/konva/naming';
|
import { getBrushLineId, getEraserLineId, getRectShapeId } from 'features/controlLayers/konva/naming';
|
||||||
import { konvaNodeToBlob, mapId, previewBlob } from 'features/controlLayers/konva/util';
|
import { konvaNodeToBlob, mapId, previewBlob } from 'features/controlLayers/konva/util';
|
||||||
import { layerRasterized } from 'features/controlLayers/store/canvasV2Slice';
|
import { layerAllObjectsDeletedExceptOne, layerRasterized } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import type {
|
import {
|
||||||
BrushLine,
|
type BrushLine,
|
||||||
CanvasV2State,
|
type CanvasV2State,
|
||||||
Coordinate,
|
type Coordinate,
|
||||||
EraserLine,
|
type EraserLine,
|
||||||
LayerEntity,
|
imageDTOToImageObject,
|
||||||
Rect,
|
type LayerEntity,
|
||||||
RectShape,
|
type Rect,
|
||||||
|
type RectShape,
|
||||||
} from 'features/controlLayers/store/types';
|
} from 'features/controlLayers/store/types';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { debounce, get } from 'lodash-es';
|
import { debounce, get } from 'lodash-es';
|
||||||
@ -53,6 +54,8 @@ export class CanvasLayer {
|
|||||||
_isFirstRender: boolean;
|
_isFirstRender: boolean;
|
||||||
|
|
||||||
isTransforming: boolean;
|
isTransforming: boolean;
|
||||||
|
isPendingBboxCalculation: boolean;
|
||||||
|
rasterizedObjectId: string | null;
|
||||||
|
|
||||||
rect: Rect;
|
rect: Rect;
|
||||||
bbox: Rect;
|
bbox: Rect;
|
||||||
@ -188,6 +191,8 @@ export class CanvasLayer {
|
|||||||
this._bboxNeedsUpdate = true;
|
this._bboxNeedsUpdate = true;
|
||||||
this.isTransforming = false;
|
this.isTransforming = false;
|
||||||
this._isFirstRender = true;
|
this._isFirstRender = true;
|
||||||
|
this.rasterizedObjectId = null;
|
||||||
|
this.isPendingBboxCalculation = false;
|
||||||
this._log = this.manager.getLogger(`layer_${this.id}`);
|
this._log = this.manager.getLogger(`layer_${this.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +331,12 @@ export class CanvasLayer {
|
|||||||
if (didUpdate) {
|
if (didUpdate) {
|
||||||
this.calculateBbox();
|
this.calculateBbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isTransforming && this.rasterizedObjectId) {
|
||||||
|
this.manager._store.dispatch(layerAllObjectsDeletedExceptOne({ id: this.id, objectId: this.rasterizedObjectId }));
|
||||||
|
this.isTransforming = false;
|
||||||
|
this.rasterizedObjectId = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOpacity(arg?: { opacity: number }) {
|
async updateOpacity(arg?: { opacity: number }) {
|
||||||
@ -388,6 +399,10 @@ export class CanvasLayer {
|
|||||||
async updateBbox() {
|
async updateBbox() {
|
||||||
this._log.trace('Updating bbox');
|
this._log.trace('Updating bbox');
|
||||||
|
|
||||||
|
if (this.isPendingBboxCalculation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If the bbox has no width or height, that means the layer is fully transparent. This can happen if it is only
|
// If the bbox has no width or height, that means the layer is fully transparent. This can happen if it is only
|
||||||
// eraser lines, fully clipped brush lines or if it has been fully erased.
|
// eraser lines, fully clipped brush lines or if it has been fully erased.
|
||||||
if (this.bbox.width === 0 || this.bbox.height === 0) {
|
if (this.bbox.width === 0 || this.bbox.height === 0) {
|
||||||
@ -547,11 +562,16 @@ export class CanvasLayer {
|
|||||||
}
|
}
|
||||||
const imageDTO = await uploadImage(blob, `${this.id}_transform.png`, 'other', true);
|
const imageDTO = await uploadImage(blob, `${this.id}_transform.png`, 'other', true);
|
||||||
const { dispatch } = getStore();
|
const { dispatch } = getStore();
|
||||||
dispatch(layerRasterized({ id: this.id, imageDTO, position: { x: rect.x, y: rect.y } }));
|
const imageObject = imageDTOToImageObject(this.id, uuidv4(), imageDTO);
|
||||||
this.isTransforming = false;
|
dispatch(layerRasterized({ id: this.id, imageObject, position: { x: rect.x, y: rect.y } }));
|
||||||
|
this.rasterizedObjectId = imageObject.id;
|
||||||
this.resetScale();
|
this.resetScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async finalizeTransform() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
async cancelTransform() {
|
async cancelTransform() {
|
||||||
this._log.debug('Canceling transform');
|
this._log.debug('Canceling transform');
|
||||||
|
|
||||||
@ -572,9 +592,12 @@ export class CanvasLayer {
|
|||||||
calculateBbox = debounce(() => {
|
calculateBbox = debounce(() => {
|
||||||
this._log.debug('Calculating bbox');
|
this._log.debug('Calculating bbox');
|
||||||
|
|
||||||
|
this.isPendingBboxCalculation = true;
|
||||||
|
|
||||||
if (this.objects.size === 0) {
|
if (this.objects.size === 0) {
|
||||||
this.rect = this.getDefaultRect();
|
this.rect = this.getDefaultRect();
|
||||||
this.bbox = this.getDefaultRect();
|
this.bbox = this.getDefaultRect();
|
||||||
|
this.isPendingBboxCalculation = false;
|
||||||
this.updateBbox();
|
this.updateBbox();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -607,6 +630,7 @@ export class CanvasLayer {
|
|||||||
if (!needsPixelBbox) {
|
if (!needsPixelBbox) {
|
||||||
this.rect = deepClone(rect);
|
this.rect = deepClone(rect);
|
||||||
this.bbox = deepClone(rect);
|
this.bbox = deepClone(rect);
|
||||||
|
this.isPendingBboxCalculation = false;
|
||||||
this._log.trace({ bbox: this.bbox, rect: this.rect }, 'Got bbox from client rect');
|
this._log.trace({ bbox: this.bbox, rect: this.rect }, 'Got bbox from client rect');
|
||||||
this.updateBbox();
|
this.updateBbox();
|
||||||
return;
|
return;
|
||||||
@ -636,6 +660,7 @@ export class CanvasLayer {
|
|||||||
} else {
|
} else {
|
||||||
this.bbox = deepClone(rect);
|
this.bbox = deepClone(rect);
|
||||||
}
|
}
|
||||||
|
this.isPendingBboxCalculation = false;
|
||||||
this._log.trace({ bbox: this.bbox, rect: this.rect, extents }, `Got bbox from worker`);
|
this._log.trace({ bbox: this.bbox, rect: this.rect, extents }, `Got bbox from worker`);
|
||||||
this.updateBbox();
|
this.updateBbox();
|
||||||
clone.destroy();
|
clone.destroy();
|
||||||
|
@ -329,7 +329,7 @@ export class CanvasManager {
|
|||||||
for (const canvasLayer of this.layers.values()) {
|
for (const canvasLayer of this.layers.values()) {
|
||||||
if (!state.layers.entities.find((l) => l.id === canvasLayer.id)) {
|
if (!state.layers.entities.find((l) => l.id === canvasLayer.id)) {
|
||||||
this.log.debug(`Destroying deleted layer ${canvasLayer.id}`);
|
this.log.debug(`Destroying deleted layer ${canvasLayer.id}`);
|
||||||
canvasLayer.destroy();
|
await canvasLayer.destroy();
|
||||||
this.layers.delete(canvasLayer.id);
|
this.layers.delete(canvasLayer.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,7 @@ export const {
|
|||||||
layerTranslated,
|
layerTranslated,
|
||||||
layerBboxChanged,
|
layerBboxChanged,
|
||||||
layerImageAdded,
|
layerImageAdded,
|
||||||
|
layerAllObjectsDeletedExceptOne,
|
||||||
layerAllDeleted,
|
layerAllDeleted,
|
||||||
layerImageCacheChanged,
|
layerImageCacheChanged,
|
||||||
layerScaled,
|
layerScaled,
|
||||||
|
@ -10,6 +10,7 @@ import type {
|
|||||||
CanvasV2State,
|
CanvasV2State,
|
||||||
Coordinate,
|
Coordinate,
|
||||||
EraserLine,
|
EraserLine,
|
||||||
|
ImageObject,
|
||||||
ImageObjectAddedArg,
|
ImageObjectAddedArg,
|
||||||
LayerEntity,
|
LayerEntity,
|
||||||
PositionChangedArg,
|
PositionChangedArg,
|
||||||
@ -252,16 +253,25 @@ export const layersReducers = {
|
|||||||
const { imageDTO } = action.payload;
|
const { imageDTO } = action.payload;
|
||||||
state.layers.imageCache = imageDTO ? imageDTOToImageWithDims(imageDTO) : null;
|
state.layers.imageCache = imageDTO ? imageDTOToImageWithDims(imageDTO) : null;
|
||||||
},
|
},
|
||||||
layerRasterized: (state, action: PayloadAction<{ id: string; imageDTO: ImageDTO; position: Coordinate }>) => {
|
layerRasterized: (state, action: PayloadAction<{ id: string; imageObject: ImageObject; position: Coordinate }>) => {
|
||||||
const { id, imageDTO, position } = action.payload;
|
const { id, imageObject, position } = action.payload;
|
||||||
const layer = selectLayer(state, id);
|
const layer = selectLayer(state, id);
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
layer.objects = [imageDTOToImageObject(id, uuidv4(), imageDTO)];
|
layer.objects.push(imageObject);
|
||||||
layer.position = position;
|
layer.position = position;
|
||||||
state.layers.imageCache = null;
|
state.layers.imageCache = null;
|
||||||
},
|
},
|
||||||
|
layerAllObjectsDeletedExceptOne: (state, action: PayloadAction<{ id: string; objectId: string }>) => {
|
||||||
|
const { id, objectId } = action.payload;
|
||||||
|
const layer = selectLayer(state, id);
|
||||||
|
if (!layer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layer.objects = layer.objects.filter((obj) => obj.id === objectId);
|
||||||
|
state.layers.imageCache = null;
|
||||||
|
},
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
|
||||||
const scalePoints = (points: number[], scaleX: number, scaleY: number) => {
|
const scalePoints = (points: number[], scaleX: number, scaleY: number) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user