feat(ui): more better logging & naming

This commit is contained in:
psychedelicious 2024-08-12 22:02:46 +10:00
parent b1cb018695
commit 388c97bff0
15 changed files with 126 additions and 136 deletions

View File

@ -1,8 +1,8 @@
import { Flex } from '@invoke-ai/ui-library'; import { Flex } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
import { useEntitySelectionColor } from 'features/controlLayers/hooks/useEntitySelectionColor';
import { useEntityIsSelected } from 'features/controlLayers/hooks/useEntityIsSelected'; import { useEntityIsSelected } from 'features/controlLayers/hooks/useEntityIsSelected';
import { useEntitySelectionColor } from 'features/controlLayers/hooks/useEntitySelectionColor';
import { entitySelected } from 'features/controlLayers/store/canvasV2Slice'; import { entitySelected } from 'features/controlLayers/store/canvasV2Slice';
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';

View File

@ -1,13 +1,15 @@
import { getArbitraryBaseColor } from '@invoke-ai/ui-library'; import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import Konva from 'konva'; import Konva from 'konva';
export class CanvasBackground { export class CanvasBackground {
static BASE_NAME = 'background'; readonly type = 'background_grid';
static LAYER_NAME = `${CanvasBackground.BASE_NAME}_layer`;
static GRID_LINE_COLOR_COARSE = getArbitraryBaseColor(27); static GRID_LINE_COLOR_COARSE = getArbitraryBaseColor(27);
static GRID_LINE_COLOR_FINE = getArbitraryBaseColor(18); static GRID_LINE_COLOR_FINE = getArbitraryBaseColor(18);
id: string;
manager: CanvasManager; manager: CanvasManager;
konva: { konva: {
@ -20,8 +22,10 @@ export class CanvasBackground {
subscriptions: Set<() => void> = new Set(); subscriptions: Set<() => void> = new Set();
constructor(manager: CanvasManager) { constructor(manager: CanvasManager) {
this.id = getPrefixedId(this.type);
this.manager = manager; this.manager = manager;
this.konva = { layer: new Konva.Layer({ name: CanvasBackground.LAYER_NAME, listening: false }) }; this.konva = { layer: new Konva.Layer({ name: `${this.type}:layer`, listening: false }) };
this.subscriptions.add( this.subscriptions.add(
this.manager.stateApi.$stageAttrs.listen(() => { this.manager.stateApi.$stageAttrs.listen(() => {
this.render(); this.render();

View File

@ -1,31 +1,35 @@
import type { JSONObject } from 'common/types';
import { roundToMultiple, roundToMultipleMin } from 'common/util/roundDownToMultiple'; import { roundToMultiple, roundToMultipleMin } from 'common/util/roundDownToMultiple';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview'; import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import type { Rect } from 'features/controlLayers/store/types'; import type { Rect } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import { atom } from 'nanostores'; import { atom } from 'nanostores';
import type { Logger } from 'roarr';
import { assert } from 'tsafe'; import { assert } from 'tsafe';
export class CanvasBbox { const ALL_ANCHORS: string[] = [
static BASE_NAME = 'bbox'; 'top-left',
static GROUP_NAME = `${CanvasBbox.BASE_NAME}_group`; 'top-center',
static RECT_NAME = `${CanvasBbox.BASE_NAME}_rect`; 'top-right',
static TRANSFORMER_NAME = `${CanvasBbox.BASE_NAME}_transformer`; 'middle-right',
static ALL_ANCHORS: string[] = [ 'middle-left',
'top-left', 'bottom-left',
'top-center', 'bottom-center',
'top-right', 'bottom-right',
'middle-right', ];
'middle-left', const CORNER_ANCHORS: string[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
'bottom-left', const NO_ANCHORS: string[] = [];
'bottom-center',
'bottom-right',
];
static CORNER_ANCHORS: string[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
static NO_ANCHORS: string[] = [];
export class CanvasBbox {
readonly type = 'generation_bbox';
id: string;
path: string[];
parent: CanvasPreview; parent: CanvasPreview;
manager: CanvasManager; manager: CanvasManager;
log: Logger;
konva: { konva: {
group: Konva.Group; group: Konva.Group;
@ -34,19 +38,25 @@ export class CanvasBbox {
}; };
constructor(parent: CanvasPreview) { constructor(parent: CanvasPreview) {
this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.manager = this.parent.manager; this.manager = this.parent.manager;
this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.trace('Creating bbox');
// Create a stash to hold onto the last aspect ratio of the bbox - this allows for locking the aspect ratio when // Create a stash to hold onto the last aspect ratio of the bbox - this allows for locking the aspect ratio when
// transforming the bbox. // transforming the bbox.
const bbox = this.manager.stateApi.getBbox(); const bbox = this.manager.stateApi.getBbox();
const $aspectRatioBuffer = atom(bbox.rect.width / bbox.rect.height); const $aspectRatioBuffer = atom(bbox.rect.width / bbox.rect.height);
this.konva = { this.konva = {
group: new Konva.Group({ name: CanvasBbox.GROUP_NAME, listening: false }), group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
// Use a transformer for the generation bbox. Transformers need some shape to transform, we will use a fully // Use a transformer for the generation bbox. Transformers need some shape to transform, we will use a fully
// transparent rect for this purpose. // transparent rect for this purpose.
rect: new Konva.Rect({ rect: new Konva.Rect({
name: CanvasBbox.RECT_NAME, name: `${this.type}:rect`,
listening: false, listening: false,
strokeEnabled: false, strokeEnabled: false,
draggable: true, draggable: true,
@ -56,7 +66,7 @@ export class CanvasBbox {
height: bbox.rect.height, height: bbox.rect.height,
}), }),
transformer: new Konva.Transformer({ transformer: new Konva.Transformer({
name: CanvasBbox.TRANSFORMER_NAME, name: `${this.type}:transformer`,
borderDash: [5, 5], borderDash: [5, 5],
borderStroke: 'rgba(212,216,234,1)', borderStroke: 'rgba(212,216,234,1)',
borderEnabled: true, borderEnabled: true,
@ -160,7 +170,7 @@ export class CanvasBbox {
// If shift is held and we are resizing from a corner, retain aspect ratio - needs special handling. We skip this // If shift is held and we are resizing from a corner, retain aspect ratio - needs special handling. We skip this
// if alt/opt is held - this requires math too big for my brain. // if alt/opt is held - this requires math too big for my brain.
if (shift && CanvasBbox.CORNER_ANCHORS.includes(anchor) && !alt) { if (shift && CORNER_ANCHORS.includes(anchor) && !alt) {
// Fit the bbox to the last aspect ratio // Fit the bbox to the last aspect ratio
let fittedWidth = Math.sqrt(width * height * $aspectRatioBuffer.get()); let fittedWidth = Math.sqrt(width * height * $aspectRatioBuffer.get());
let fittedHeight = fittedWidth / $aspectRatioBuffer.get(); let fittedHeight = fittedWidth / $aspectRatioBuffer.get();
@ -237,7 +247,11 @@ export class CanvasBbox {
}); });
this.konva.transformer.setAttrs({ this.konva.transformer.setAttrs({
listening: toolState.selected === 'bbox', listening: toolState.selected === 'bbox',
enabledAnchors: toolState.selected === 'bbox' ? CanvasBbox.ALL_ANCHORS : CanvasBbox.NO_ANCHORS, enabledAnchors: toolState.selected === 'bbox' ? ALL_ANCHORS : NO_ANCHORS,
}); });
} }
getLoggingContext = (): JSONObject => {
return { ...this.manager.getLoggingContext(), path: this.path.join('.') };
};
} }

View File

@ -7,13 +7,8 @@ import type { CanvasBrushLineState } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
const TYPE = 'brush_line';
export class CanvasBrushLineRenderer { export class CanvasBrushLineRenderer {
static GROUP_NAME = `${TYPE}_group`; readonly type = 'brush_line_renderer';
static LINE_NAME = `${TYPE}_line`;
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
@ -33,19 +28,18 @@ export class CanvasBrushLineRenderer {
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
this.path = this.parent.path.concat(this.id); this.path = this.parent.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext); this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.trace({ state }, 'Creating brush line'); this.log.trace({ state }, 'Creating brush line');
this.konva = { this.konva = {
group: new Konva.Group({ group: new Konva.Group({
name: CanvasBrushLineRenderer.GROUP_NAME, name: `${this.type}:group`,
clip, clip,
listening: false, listening: false,
}), }),
line: new Konva.Line({ line: new Konva.Line({
name: CanvasBrushLineRenderer.LINE_NAME, name: `${this.type}:line`,
listening: false, listening: false,
shadowForStrokeEnabled: false, shadowForStrokeEnabled: false,
strokeWidth, strokeWidth,

View File

@ -8,13 +8,8 @@ import { RGBA_RED } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
const TYPE = 'eraser_line';
export class CanvasEraserLineRenderer { export class CanvasEraserLineRenderer {
static GROUP_NAME = `${TYPE}_group`; readonly type = 'eraser_line_renderer';
static LINE_NAME = `${TYPE}_line`;
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
@ -40,12 +35,12 @@ export class CanvasEraserLineRenderer {
this.konva = { this.konva = {
group: new Konva.Group({ group: new Konva.Group({
name: CanvasEraserLineRenderer.GROUP_NAME, name: `${this.type}:group`,
clip, clip,
listening: false, listening: false,
}), }),
line: new Konva.Line({ line: new Konva.Line({
name: CanvasEraserLineRenderer.LINE_NAME, name: `${this.type}:line`,
listening: false, listening: false,
shadowForStrokeEnabled: false, shadowForStrokeEnabled: false,
strokeWidth, strokeWidth,

View File

@ -1,6 +1,7 @@
import { Mutex } from 'async-mutex'; import { Mutex } from 'async-mutex';
import type { JSONObject } from 'common/types'; import type { JSONObject } from 'common/types';
import { deepClone } from 'common/util/deepClone'; import { deepClone } from 'common/util/deepClone';
import type { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer'; import type { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer';
import type { CanvasStagingArea } from 'features/controlLayers/konva/CanvasStagingArea'; import type { CanvasStagingArea } from 'features/controlLayers/konva/CanvasStagingArea';
@ -12,20 +13,12 @@ import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
import { getImageDTO } from 'services/api/endpoints/images'; import { getImageDTO } from 'services/api/endpoints/images';
const TYPE = 'image';
export class CanvasImageRenderer { export class CanvasImageRenderer {
static GROUP_NAME = `${TYPE}_group`; readonly type = 'image_renderer';
static IMAGE_NAME = `${TYPE}_image`;
static PLACEHOLDER_GROUP_NAME = `${TYPE}_placeholder-group`;
static PLACEHOLDER_RECT_NAME = `${TYPE}_placeholder-rect`;
static PLACEHOLDER_TEXT_NAME = `${TYPE}_placeholder-text`;
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
parent: CanvasObjectRenderer | CanvasStagingArea; parent: CanvasObjectRenderer | CanvasStagingArea | CanvasFilter;
manager: CanvasManager; manager: CanvasManager;
log: Logger; log: Logger;
@ -40,7 +33,7 @@ export class CanvasImageRenderer {
isError: boolean = false; isError: boolean = false;
mutex = new Mutex(); mutex = new Mutex();
constructor(state: CanvasImageState, parent: CanvasObjectRenderer | CanvasStagingArea) { constructor(state: CanvasImageState, parent: CanvasObjectRenderer | CanvasStagingArea | CanvasFilter) {
const { id, image } = state; const { id, image } = state;
const { width, height } = image; const { width, height } = image;
this.id = id; this.id = id;
@ -52,18 +45,18 @@ export class CanvasImageRenderer {
this.log.trace({ state }, 'Creating image'); this.log.trace({ state }, 'Creating image');
this.konva = { this.konva = {
group: new Konva.Group({ name: CanvasImageRenderer.GROUP_NAME, listening: false }), group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
placeholder: { placeholder: {
group: new Konva.Group({ name: CanvasImageRenderer.PLACEHOLDER_GROUP_NAME, listening: false }), group: new Konva.Group({ name: `${this.type}:placeholder_group`, listening: false }),
rect: new Konva.Rect({ rect: new Konva.Rect({
name: CanvasImageRenderer.PLACEHOLDER_RECT_NAME, name: `${this.type}:placeholder_rect`,
fill: 'hsl(220 12% 45% / 1)', // 'base.500' fill: 'hsl(220 12% 45% / 1)', // 'base.500'
width, width,
height, height,
listening: false, listening: false,
}), }),
text: new Konva.Text({ text: new Konva.Text({
name: CanvasImageRenderer.PLACEHOLDER_TEXT_NAME, name: `${this.type}:placeholder_text`,
fill: 'hsl(220 12% 10% / 1)', // 'base.900' fill: 'hsl(220 12% 10% / 1)', // 'base.900'
width, width,
height, height,
@ -135,7 +128,7 @@ export class CanvasImageRenderer {
} else { } else {
this.log.trace('Creating new Konva image'); this.log.trace('Creating new Konva image');
this.konva.image = new Konva.Image({ this.konva.image = new Konva.Image({
name: CanvasImageRenderer.IMAGE_NAME, name: `${this.type}:image`,
listening: false, listening: false,
image: this.imageElement, image: this.imageElement,
width, width,

View File

@ -8,10 +8,8 @@ import Konva from 'konva';
import { get } from 'lodash-es'; import { get } from 'lodash-es';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
const TYPE = 'layer';
export class CanvasLayerAdapter { export class CanvasLayerAdapter {
readonly type = TYPE; readonly type = 'layer_adapter';
id: string; id: string;
path: string[]; path: string[];
@ -34,6 +32,7 @@ export class CanvasLayerAdapter {
this.path = this.manager.path.concat(this.id); this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext); this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.debug({ state }, 'Creating layer'); this.log.debug({ state }, 'Creating layer');
this.state = state;
this.konva = { this.konva = {
layer: new Konva.Layer({ layer: new Konva.Layer({
@ -48,15 +47,13 @@ export class CanvasLayerAdapter {
this.renderer = new CanvasObjectRenderer(this); this.renderer = new CanvasObjectRenderer(this);
this.transformer = new CanvasTransformer(this); this.transformer = new CanvasTransformer(this);
this.state = state;
} }
/** /**
* Get this entity's entity identifier * Get this entity's entity identifier
*/ */
getEntityIdentifier = (): CanvasEntityIdentifier => { getEntityIdentifier = (): CanvasEntityIdentifier => {
return { id: this.id, type: this.type }; return { id: this.id, type: this.state.type };
}; };
destroy = (): void => { destroy = (): void => {

View File

@ -14,9 +14,10 @@ import { get } from 'lodash-es';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
export class CanvasMaskAdapter { export class CanvasMaskAdapter {
readonly type = 'mask_adapter';
id: string; id: string;
path: string[]; path: string[];
type: CanvasInpaintMaskState['type'] | CanvasRegionalGuidanceState['type'];
manager: CanvasManager; manager: CanvasManager;
log: Logger; log: Logger;
@ -34,11 +35,11 @@ export class CanvasMaskAdapter {
constructor(state: CanvasMaskAdapter['state'], manager: CanvasMaskAdapter['manager']) { constructor(state: CanvasMaskAdapter['state'], manager: CanvasMaskAdapter['manager']) {
this.id = state.id; this.id = state.id;
this.type = state.type;
this.manager = manager; this.manager = manager;
this.path = this.manager.path.concat(this.id); this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext); this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.debug({ state }, 'Creating mask'); this.log.debug({ state }, 'Creating mask');
this.state = state;
this.konva = { this.konva = {
layer: new Konva.Layer({ layer: new Konva.Layer({
@ -54,7 +55,6 @@ export class CanvasMaskAdapter {
this.renderer = new CanvasObjectRenderer(this); this.renderer = new CanvasObjectRenderer(this);
this.transformer = new CanvasTransformer(this); this.transformer = new CanvasTransformer(this);
this.state = state;
this.maskOpacity = this.manager.stateApi.getMaskOpacity(); this.maskOpacity = this.manager.stateApi.getMaskOpacity();
} }
@ -62,7 +62,7 @@ export class CanvasMaskAdapter {
* Get this entity's entity identifier * Get this entity's entity identifier
*/ */
getEntityIdentifier = (): CanvasEntityIdentifier => { getEntityIdentifier = (): CanvasEntityIdentifier => {
return { id: this.id, type: this.type }; return { id: this.id, type: this.state.type };
}; };
destroy = (): void => { destroy = (): void => {

View File

@ -33,16 +33,11 @@ type AnyObjectRenderer = CanvasBrushLineRenderer | CanvasEraserLineRenderer | Ca
*/ */
type AnyObjectState = CanvasBrushLineState | CanvasEraserLineState | CanvasImageState | CanvasRectState; type AnyObjectState = CanvasBrushLineState | CanvasEraserLineState | CanvasImageState | CanvasRectState;
const TYPE = 'object_renderer';
/** /**
* Handles rendering of objects for a canvas entity. * Handles rendering of objects for a canvas entity.
*/ */
export class CanvasObjectRenderer { export class CanvasObjectRenderer {
static KONVA_OBJECT_GROUP_NAME = `${TYPE}:object_group`; readonly type = 'object_renderer';
static KONVA_COMPOSITING_RECT_NAME = `${TYPE}:compositing_rect`;
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
@ -93,7 +88,7 @@ export class CanvasObjectRenderer {
}; };
constructor(parent: CanvasLayerAdapter | CanvasMaskAdapter) { constructor(parent: CanvasLayerAdapter | CanvasMaskAdapter) {
this.id = getPrefixedId(TYPE); this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.path = this.parent.path.concat(this.id); this.path = this.parent.path.concat(this.id);
this.manager = parent.manager; this.manager = parent.manager;
@ -101,15 +96,15 @@ export class CanvasObjectRenderer {
this.log.trace('Creating object renderer'); this.log.trace('Creating object renderer');
this.konva = { this.konva = {
objectGroup: new Konva.Group({ name: CanvasObjectRenderer.KONVA_OBJECT_GROUP_NAME, listening: false }), objectGroup: new Konva.Group({ name: `${this.type}:object_group`, listening: false }),
compositingRect: null, compositingRect: null,
}; };
this.parent.konva.layer.add(this.konva.objectGroup); this.parent.konva.layer.add(this.konva.objectGroup);
if (this.parent.type === 'inpaint_mask' || this.parent.type === 'regional_guidance') { if (this.parent.state.type === 'inpaint_mask' || this.parent.state.type === 'regional_guidance') {
this.konva.compositingRect = new Konva.Rect({ this.konva.compositingRect = new Konva.Rect({
name: CanvasObjectRenderer.KONVA_COMPOSITING_RECT_NAME, name: `${this.type}:compositing_rect`,
globalCompositeOperation: 'source-in', globalCompositeOperation: 'source-in',
listening: false, listening: false,
strokeEnabled: false, strokeEnabled: false,

View File

@ -1,18 +1,20 @@
import { Mutex } from 'async-mutex'; import { Mutex } from 'async-mutex';
import type { JSONObject } from 'common/types';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview'; import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview';
import { getPrefixedId, loadImage } from 'features/controlLayers/konva/util'; import { getPrefixedId, loadImage } from 'features/controlLayers/konva/util';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr';
import type { InvocationDenoiseProgressEvent } from 'services/events/types'; import type { InvocationDenoiseProgressEvent } from 'services/events/types';
export class CanvasProgressImage { export class CanvasProgressImage {
static NAME_PREFIX = 'progress-image'; readonly type = 'progress_image';
static GROUP_NAME = `${CanvasProgressImage.NAME_PREFIX}_group`;
static IMAGE_NAME = `${CanvasProgressImage.NAME_PREFIX}_image`;
id: string; id: string;
path: string[];
parent: CanvasPreview; parent: CanvasPreview;
manager: CanvasManager; manager: CanvasManager;
log: Logger;
/** /**
* A set of subscriptions that should be cleaned up when the transformer is destroyed. * A set of subscriptions that should be cleaned up when the transformer is destroyed.
@ -33,11 +35,16 @@ export class CanvasProgressImage {
mutex: Mutex = new Mutex(); mutex: Mutex = new Mutex();
constructor(parent: CanvasPreview) { constructor(parent: CanvasPreview) {
this.id = getPrefixedId(CanvasProgressImage.NAME_PREFIX); this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.trace('Creating progress image');
this.konva = { this.konva = {
group: new Konva.Group({ name: CanvasProgressImage.GROUP_NAME, listening: false }), group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
image: null, image: null,
}; };
@ -86,7 +93,7 @@ export class CanvasProgressImage {
}); });
} else { } else {
this.konva.image = new Konva.Image({ this.konva.image = new Konva.Image({
name: CanvasProgressImage.IMAGE_NAME, name: `${this.type}:image`,
listening: false, listening: false,
image: this.imageElement, image: this.imageElement,
x, x,
@ -106,9 +113,14 @@ export class CanvasProgressImage {
}; };
destroy = () => { destroy = () => {
this.log.trace('Destroying progress image');
for (const unsubscribe of this.subscriptions) { for (const unsubscribe of this.subscriptions) {
unsubscribe(); unsubscribe();
} }
this.konva.group.destroy(); this.konva.group.destroy();
}; };
getLoggingContext = (): JSONObject => {
return { ...this.manager.getLoggingContext(), path: this.path.join('.') };
};
} }

View File

@ -7,13 +7,8 @@ import type { CanvasRectState } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
const TYPE = 'rect';
export class CanvasRectRenderer { export class CanvasRectRenderer {
static GROUP_NAME = `${TYPE}_group`; readonly type = 'rect_renderer';
static RECT_NAME = `${TYPE}_rect`;
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
@ -38,9 +33,9 @@ export class CanvasRectRenderer {
this.log.trace({ state }, 'Creating rect'); this.log.trace({ state }, 'Creating rect');
this.konva = { this.konva = {
group: new Konva.Group({ name: CanvasRectRenderer.GROUP_NAME, listening: false }), group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
rect: new Konva.Rect({ rect: new Konva.Rect({
name: CanvasRectRenderer.RECT_NAME, name: `${this.type}:rect`,
...rect, ...rect,
listening: false, listening: false,
fill: rgbaColorToString(color), fill: rgbaColorToString(color),

View File

@ -7,12 +7,8 @@ import type { StagingAreaImage } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
const TYPE = 'staging_area';
export class CanvasStagingArea { export class CanvasStagingArea {
static GROUP_NAME = `${TYPE}_group`; readonly type = 'staging_area';
readonly type = TYPE;
id: string; id: string;
path: string[]; path: string[];
@ -31,14 +27,14 @@ export class CanvasStagingArea {
subscriptions: Set<() => void> = new Set(); subscriptions: Set<() => void> = new Set();
constructor(parent: CanvasPreview) { constructor(parent: CanvasPreview) {
this.id = getPrefixedId(TYPE); this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.manager = this.parent.manager; this.manager = this.parent.manager;
this.path = this.manager.path.concat(this.id); this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext); this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.debug('Creating staging area'); this.log.debug('Creating staging area');
this.konva = { group: new Konva.Group({ name: CanvasStagingArea.GROUP_NAME, listening: false }) }; this.konva = { group: new Konva.Group({ name: `${this.type}:group`, listening: false }) };
this.image = null; this.image = null;
this.selectedImage = null; this.selectedImage = null;

View File

@ -209,7 +209,7 @@ export class CanvasStateApi {
entityAdapter = this.manager.inpaintMask; entityAdapter = this.manager.inpaintMask;
} }
if (entityState && entityAdapter && entityState.type === entityAdapter.type) { if (entityState && entityAdapter) {
return { return {
id: entityState.id, id: entityState.id,
type: entityState.type, type: entityState.type,

View File

@ -1,3 +1,4 @@
import type { JSONObject } from 'common/types';
import { rgbaColorToString } from 'common/util/colorCodeTransformers'; import { rgbaColorToString } from 'common/util/colorCodeTransformers';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview'; import type { CanvasPreview } from 'features/controlLayers/konva/CanvasPreview';
@ -6,28 +7,19 @@ import {
BRUSH_BORDER_OUTER_COLOR, BRUSH_BORDER_OUTER_COLOR,
BRUSH_ERASER_BORDER_WIDTH, BRUSH_ERASER_BORDER_WIDTH,
} from 'features/controlLayers/konva/constants'; } from 'features/controlLayers/konva/constants';
import { alignCoordForTool } from 'features/controlLayers/konva/util'; import { alignCoordForTool, getPrefixedId } from 'features/controlLayers/konva/util';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr';
export class CanvasTool { export class CanvasTool {
static NAME_PREFIX = 'tool'; readonly type = 'tool_preview';
static GROUP_NAME = `${CanvasTool.NAME_PREFIX}_group`;
static BRUSH_NAME_PREFIX = `${CanvasTool.NAME_PREFIX}_brush`;
static BRUSH_GROUP_NAME = `${CanvasTool.BRUSH_NAME_PREFIX}_group`;
static BRUSH_FILL_CIRCLE_NAME = `${CanvasTool.BRUSH_NAME_PREFIX}_fill-circle`;
static BRUSH_INNER_BORDER_CIRCLE_NAME = `${CanvasTool.BRUSH_NAME_PREFIX}_inner-border-circle`;
static BRUSH_OUTER_BORDER_CIRCLE_NAME = `${CanvasTool.BRUSH_NAME_PREFIX}_outer-border-circle`;
static ERASER_NAME_PREFIX = `${CanvasTool.NAME_PREFIX}_eraser`;
static ERASER_GROUP_NAME = `${CanvasTool.ERASER_NAME_PREFIX}_group`;
static ERASER_FILL_CIRCLE_NAME = `${CanvasTool.ERASER_NAME_PREFIX}_fill-circle`;
static ERASER_INNER_BORDER_CIRCLE_NAME = `${CanvasTool.ERASER_NAME_PREFIX}_inner-border-circle`;
static ERASER_OUTER_BORDER_CIRCLE_NAME = `${CanvasTool.ERASER_NAME_PREFIX}_outer-border-circle`;
id: string;
path: string[];
parent: CanvasPreview; parent: CanvasPreview;
manager: CanvasManager; manager: CanvasManager;
log: Logger;
konva: { konva: {
group: Konva.Group; group: Konva.Group;
brush: { brush: {
@ -50,26 +42,29 @@ export class CanvasTool {
subscriptions: Set<() => void> = new Set(); subscriptions: Set<() => void> = new Set();
constructor(parent: CanvasPreview) { constructor(parent: CanvasPreview) {
this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.manager = this.parent.manager; this.manager = this.parent.manager;
this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext);
this.konva = { this.konva = {
group: new Konva.Group({ name: CanvasTool.GROUP_NAME }), group: new Konva.Group({ name: `${this.type}:group` }),
brush: { brush: {
group: new Konva.Group({ name: CanvasTool.BRUSH_GROUP_NAME }), group: new Konva.Group({ name: `${this.type}:brush_group` }),
fillCircle: new Konva.Circle({ fillCircle: new Konva.Circle({
name: CanvasTool.BRUSH_FILL_CIRCLE_NAME, name: `${this.type}:brush_fill_circle`,
listening: false, listening: false,
strokeEnabled: false, strokeEnabled: false,
}), }),
innerBorderCircle: new Konva.Circle({ innerBorderCircle: new Konva.Circle({
name: CanvasTool.BRUSH_INNER_BORDER_CIRCLE_NAME, name: `${this.type}:brush_inner_border_circle`,
listening: false, listening: false,
stroke: BRUSH_BORDER_INNER_COLOR, stroke: BRUSH_BORDER_INNER_COLOR,
strokeWidth: BRUSH_ERASER_BORDER_WIDTH, strokeWidth: BRUSH_ERASER_BORDER_WIDTH,
strokeEnabled: true, strokeEnabled: true,
}), }),
outerBorderCircle: new Konva.Circle({ outerBorderCircle: new Konva.Circle({
name: CanvasTool.BRUSH_OUTER_BORDER_CIRCLE_NAME, name: `${this.type}:brush_outer_border_circle`,
listening: false, listening: false,
stroke: BRUSH_BORDER_OUTER_COLOR, stroke: BRUSH_BORDER_OUTER_COLOR,
strokeWidth: BRUSH_ERASER_BORDER_WIDTH, strokeWidth: BRUSH_ERASER_BORDER_WIDTH,
@ -77,23 +72,23 @@ export class CanvasTool {
}), }),
}, },
eraser: { eraser: {
group: new Konva.Group({ name: CanvasTool.ERASER_GROUP_NAME }), group: new Konva.Group({ name: `${this.type}:eraser_group` }),
fillCircle: new Konva.Circle({ fillCircle: new Konva.Circle({
name: CanvasTool.ERASER_FILL_CIRCLE_NAME, name: `${this.type}:eraser_fill_circle`,
listening: false, listening: false,
strokeEnabled: false, strokeEnabled: false,
fill: 'white', fill: 'white',
globalCompositeOperation: 'destination-out', globalCompositeOperation: 'destination-out',
}), }),
innerBorderCircle: new Konva.Circle({ innerBorderCircle: new Konva.Circle({
name: CanvasTool.ERASER_INNER_BORDER_CIRCLE_NAME, name: `${this.type}:eraser_inner_border_circle`,
listening: false, listening: false,
stroke: BRUSH_BORDER_INNER_COLOR, stroke: BRUSH_BORDER_INNER_COLOR,
strokeWidth: BRUSH_ERASER_BORDER_WIDTH, strokeWidth: BRUSH_ERASER_BORDER_WIDTH,
strokeEnabled: true, strokeEnabled: true,
}), }),
outerBorderCircle: new Konva.Circle({ outerBorderCircle: new Konva.Circle({
name: CanvasTool.ERASER_OUTER_BORDER_CIRCLE_NAME, name: `${this.type}:eraser_outer_border_circle`,
listening: false, listening: false,
stroke: BRUSH_BORDER_OUTER_COLOR, stroke: BRUSH_BORDER_OUTER_COLOR,
strokeWidth: BRUSH_ERASER_BORDER_WIDTH, strokeWidth: BRUSH_ERASER_BORDER_WIDTH,
@ -160,6 +155,7 @@ export class CanvasTool {
const isMouseDown = this.manager.stateApi.$isMouseDown.get(); const isMouseDown = this.manager.stateApi.$isMouseDown.get();
const tool = toolState.selected; const tool = toolState.selected;
console.log(selectedEntity);
const isDrawableEntity = const isDrawableEntity =
selectedEntity?.state.type === 'regional_guidance' || selectedEntity?.state.type === 'regional_guidance' ||
selectedEntity?.state.type === 'layer' || selectedEntity?.state.type === 'layer' ||
@ -258,4 +254,8 @@ export class CanvasTool {
} }
} }
} }
getLoggingContext = (): JSONObject => {
return { ...this.manager.getLoggingContext(), path: this.path.join('.') };
};
} }

View File

@ -17,10 +17,7 @@ import type { Logger } from 'roarr';
* It renders an outline when dragging and resizing the entity, with transform anchors for resizing and rotation. * It renders an outline when dragging and resizing the entity, with transform anchors for resizing and rotation.
*/ */
export class CanvasTransformer { export class CanvasTransformer {
static TYPE = 'entity_transformer'; readonly type = 'entity_transformer';
static KONVA_TRANSFORMER_NAME = `${CanvasTransformer.TYPE}:transformer`;
static KONVA_PROXY_RECT_NAME = `${CanvasTransformer.TYPE}:proxy_rect`;
static KONVA_OUTLINE_RECT_NAME = `${CanvasTransformer.TYPE}:outline_rect`;
static RECT_CALC_DEBOUNCE_MS = 300; static RECT_CALC_DEBOUNCE_MS = 300;
static OUTLINE_PADDING = 0; static OUTLINE_PADDING = 0;
@ -38,8 +35,6 @@ export class CanvasTransformer {
static ROTATE_ANCHOR_STROKE_COLOR = 'hsl(200 76% 40% / 1)'; // invokeBlue.700 static ROTATE_ANCHOR_STROKE_COLOR = 'hsl(200 76% 40% / 1)'; // invokeBlue.700
static ROTATE_ANCHOR_SIZE = 12; static ROTATE_ANCHOR_SIZE = 12;
readonly type = CanvasTransformer.TYPE;
id: string; id: string;
path: string[]; path: string[];
parent: CanvasLayerAdapter | CanvasMaskAdapter; parent: CanvasLayerAdapter | CanvasMaskAdapter;
@ -100,7 +95,7 @@ export class CanvasTransformer {
}; };
constructor(parent: CanvasLayerAdapter | CanvasMaskAdapter) { constructor(parent: CanvasLayerAdapter | CanvasMaskAdapter) {
this.id = getPrefixedId(CanvasTransformer.TYPE); this.id = getPrefixedId(this.type);
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
this.path = this.parent.path.concat(this.id); this.path = this.parent.path.concat(this.id);
@ -110,13 +105,13 @@ export class CanvasTransformer {
outlineRect: new Konva.Rect({ outlineRect: new Konva.Rect({
listening: false, listening: false,
draggable: false, draggable: false,
name: CanvasTransformer.KONVA_OUTLINE_RECT_NAME, name: `${this.type}:outline_rect`,
stroke: CanvasTransformer.OUTLINE_COLOR, stroke: CanvasTransformer.OUTLINE_COLOR,
perfectDrawEnabled: false, perfectDrawEnabled: false,
strokeHitEnabled: false, strokeHitEnabled: false,
}), }),
transformer: new Konva.Transformer({ transformer: new Konva.Transformer({
name: CanvasTransformer.KONVA_TRANSFORMER_NAME, name: `${this.type}:transformer`,
// Visibility and listening are managed via activate() and deactivate() // Visibility and listening are managed via activate() and deactivate()
visible: false, visible: false,
listening: false, listening: false,
@ -235,7 +230,7 @@ export class CanvasTransformer {
}, },
}), }),
proxyRect: new Konva.Rect({ proxyRect: new Konva.Rect({
name: CanvasTransformer.KONVA_PROXY_RECT_NAME, name: `${this.type}:proxy_rect`,
listening: false, listening: false,
draggable: true, draggable: true,
}), }),