mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
tidy(ui): organise files
This commit is contained in:
parent
79287c2d16
commit
73a7a27ea1
@ -1,6 +1,6 @@
|
|||||||
import { enqueueRequested } from 'app/store/actions';
|
import { enqueueRequested } from 'app/store/actions';
|
||||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||||
import { getNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import { getCanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { stagingAreaCanceledStaging, stagingAreaStartedStaging } from 'features/controlLayers/store/canvasV2Slice';
|
import { stagingAreaCanceledStaging, stagingAreaStartedStaging } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
|
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
|
||||||
import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph';
|
import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph';
|
||||||
@ -26,7 +26,7 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
|
|||||||
try {
|
try {
|
||||||
let g;
|
let g;
|
||||||
|
|
||||||
const manager = getNodeManager();
|
const manager = getCanvasManager();
|
||||||
assert(model, 'No model found in state');
|
assert(model, 'No model found in state');
|
||||||
const base = model.base;
|
const base = model.base;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { logger } from 'app/logging/logger';
|
|||||||
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
||||||
import { useAppStore } from 'app/store/storeHooks';
|
import { useAppStore } from 'app/store/storeHooks';
|
||||||
import { HeadsUpDisplay } from 'features/controlLayers/components/HeadsUpDisplay';
|
import { HeadsUpDisplay } from 'features/controlLayers/components/HeadsUpDisplay';
|
||||||
import { KonvaNodeManager, setNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import { CanvasManager, setCanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { memo, useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
import { memo, useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
||||||
import { useDevicePixelRatio } from 'use-device-pixel-ratio';
|
import { useDevicePixelRatio } from 'use-device-pixel-ratio';
|
||||||
@ -35,8 +35,8 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null,
|
|||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = new KonvaNodeManager(stage, container, store, logIfDebugging);
|
const manager = new CanvasManager(stage, container, store, logIfDebugging);
|
||||||
setNodeManager(manager);
|
setCanvasManager(manager);
|
||||||
const cleanup = manager.initialize();
|
const cleanup = manager.initialize();
|
||||||
return cleanup;
|
return cleanup;
|
||||||
}, [asPreview, container, stage, store]);
|
}, [asPreview, container, stage, store]);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
|
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
|
||||||
const baseGridLineColor = getArbitraryBaseColor(27);
|
const baseGridLineColor = getArbitraryBaseColor(27);
|
||||||
@ -31,9 +31,9 @@ const getGridSpacing = (scale: number): number => {
|
|||||||
|
|
||||||
export class CanvasBackground {
|
export class CanvasBackground {
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager) {
|
constructor(manager: CanvasManager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.layer = new Konva.Layer({ listening: false });
|
this.layer = new Konva.Layer({ listening: false });
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { roundToMultiple, roundToMultipleMin } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple, roundToMultipleMin } from 'common/util/roundDownToMultiple';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import {
|
import {
|
||||||
PREVIEW_GENERATION_BBOX_DUMMY_RECT,
|
PREVIEW_GENERATION_BBOX_DUMMY_RECT,
|
||||||
PREVIEW_GENERATION_BBOX_GROUP,
|
PREVIEW_GENERATION_BBOX_GROUP,
|
||||||
@ -14,7 +14,7 @@ export class CanvasBbox {
|
|||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
rect: Konva.Rect;
|
rect: Konva.Rect;
|
||||||
transformer: Konva.Transformer;
|
transformer: Konva.Transformer;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
|
|
||||||
ALL_ANCHORS: string[] = [
|
ALL_ANCHORS: string[] = [
|
||||||
'top-left',
|
'top-left',
|
||||||
@ -29,7 +29,7 @@ export class CanvasBbox {
|
|||||||
CORNER_ANCHORS: string[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
CORNER_ANCHORS: string[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
||||||
NO_ANCHORS: string[] = [];
|
NO_ANCHORS: string[] = [];
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager) {
|
constructor(manager: CanvasManager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
// 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.
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import type { BrushLine } from 'features/controlLayers/store/types';
|
||||||
|
import Konva from 'konva';
|
||||||
|
|
||||||
|
export class CanvasBrushLine {
|
||||||
|
id: string;
|
||||||
|
konvaLineGroup: Konva.Group;
|
||||||
|
konvaLine: Konva.Line;
|
||||||
|
lastBrushLine: BrushLine;
|
||||||
|
|
||||||
|
constructor(brushLine: BrushLine) {
|
||||||
|
const { id, strokeWidth, clip, color, points } = brushLine;
|
||||||
|
this.id = id;
|
||||||
|
this.konvaLineGroup = new Konva.Group({
|
||||||
|
clip,
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
this.konvaLine = new Konva.Line({
|
||||||
|
id,
|
||||||
|
listening: false,
|
||||||
|
shadowForStrokeEnabled: false,
|
||||||
|
strokeWidth,
|
||||||
|
tension: 0,
|
||||||
|
lineCap: 'round',
|
||||||
|
lineJoin: 'round',
|
||||||
|
globalCompositeOperation: 'source-over',
|
||||||
|
stroke: rgbaColorToString(color),
|
||||||
|
points,
|
||||||
|
});
|
||||||
|
this.konvaLineGroup.add(this.konvaLine);
|
||||||
|
this.lastBrushLine = brushLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(brushLine: BrushLine, force?: boolean): boolean {
|
||||||
|
if (this.lastBrushLine !== brushLine || force) {
|
||||||
|
const { points, color, clip, strokeWidth } = brushLine;
|
||||||
|
this.konvaLine.setAttrs({
|
||||||
|
points,
|
||||||
|
stroke: rgbaColorToString(color),
|
||||||
|
clip,
|
||||||
|
strokeWidth,
|
||||||
|
});
|
||||||
|
this.lastBrushLine = brushLine;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.konvaLineGroup.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { CanvasImage } from 'features/controlLayers/konva/CanvasImage';
|
||||||
import { LightnessToAlphaFilter } from 'features/controlLayers/konva/filters';
|
import { LightnessToAlphaFilter } from 'features/controlLayers/konva/filters';
|
||||||
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
||||||
import type { ControlAdapterEntity } from 'features/controlLayers/store/types';
|
import type { ControlAdapterEntity } from 'features/controlLayers/store/types';
|
||||||
@ -5,13 +6,11 @@ import Konva from 'konva';
|
|||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { KonvaImage } from './objects';
|
|
||||||
|
|
||||||
export class CanvasControlAdapter {
|
export class CanvasControlAdapter {
|
||||||
id: string;
|
id: string;
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
image: KonvaImage | null;
|
image: CanvasImage | null;
|
||||||
|
|
||||||
constructor(entity: ControlAdapterEntity) {
|
constructor(entity: ControlAdapterEntity) {
|
||||||
const { id } = entity;
|
const { id } = entity;
|
||||||
@ -43,7 +42,7 @@ export class CanvasControlAdapter {
|
|||||||
const filters = entity.filter === 'LightnessToAlphaFilter' ? [LightnessToAlphaFilter] : [];
|
const filters = entity.filter === 'LightnessToAlphaFilter' ? [LightnessToAlphaFilter] : [];
|
||||||
|
|
||||||
if (!this.image) {
|
if (!this.image) {
|
||||||
this.image = await new KonvaImage(imageObject, {
|
this.image = await new CanvasImage(imageObject, {
|
||||||
onLoad: (konvaImage) => {
|
onLoad: (konvaImage) => {
|
||||||
konvaImage.filters(filters);
|
konvaImage.filters(filters);
|
||||||
konvaImage.cache();
|
konvaImage.cache();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
|
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
|
||||||
import { DOCUMENT_FIT_PADDING_PX } from 'features/controlLayers/konva/constants';
|
import { DOCUMENT_FIT_PADDING_PX } from 'features/controlLayers/konva/constants';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
|
||||||
export class CanvasDocumentSizeOverlay {
|
export class CanvasDocumentSizeOverlay {
|
||||||
@ -8,9 +8,9 @@ export class CanvasDocumentSizeOverlay {
|
|||||||
outerRect: Konva.Rect;
|
outerRect: Konva.Rect;
|
||||||
innerRect: Konva.Rect;
|
innerRect: Konva.Rect;
|
||||||
padding: number;
|
padding: number;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager, padding?: number) {
|
constructor(manager: CanvasManager, padding?: number) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.padding = padding ?? DOCUMENT_FIT_PADDING_PX;
|
this.padding = padding ?? DOCUMENT_FIT_PADDING_PX;
|
||||||
this.group = new Konva.Group({ id: 'document_overlay_group', listening: false });
|
this.group = new Konva.Group({ id: 'document_overlay_group', listening: false });
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import { getLayerBboxId, LAYER_BBOX_NAME } from 'features/controlLayers/konva/naming';
|
||||||
|
import type { CanvasEntity, EraserLine } from 'features/controlLayers/store/types';
|
||||||
|
import { RGBA_RED } from 'features/controlLayers/store/types';
|
||||||
|
import Konva from 'konva';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bounding box rect for a layer.
|
||||||
|
* @param entity The layer state for the layer to create the bounding box for
|
||||||
|
* @param konvaLayer The konva layer to attach the bounding box to
|
||||||
|
*/
|
||||||
|
export const createBboxRect = (entity: CanvasEntity, konvaLayer: Konva.Layer): Konva.Rect => {
|
||||||
|
const rect = new Konva.Rect({
|
||||||
|
id: getLayerBboxId(entity.id),
|
||||||
|
name: LAYER_BBOX_NAME,
|
||||||
|
strokeWidth: 1,
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
konvaLayer.add(rect);
|
||||||
|
return rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CanvasEraserLine {
|
||||||
|
id: string;
|
||||||
|
konvaLineGroup: Konva.Group;
|
||||||
|
konvaLine: Konva.Line;
|
||||||
|
lastEraserLine: EraserLine;
|
||||||
|
|
||||||
|
constructor(eraserLine: EraserLine) {
|
||||||
|
const { id, strokeWidth, clip, points } = eraserLine;
|
||||||
|
this.id = id;
|
||||||
|
this.konvaLineGroup = new Konva.Group({
|
||||||
|
clip,
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
this.konvaLine = new Konva.Line({
|
||||||
|
id,
|
||||||
|
listening: false,
|
||||||
|
shadowForStrokeEnabled: false,
|
||||||
|
strokeWidth,
|
||||||
|
tension: 0,
|
||||||
|
lineCap: 'round',
|
||||||
|
lineJoin: 'round',
|
||||||
|
globalCompositeOperation: 'destination-out',
|
||||||
|
stroke: rgbaColorToString(RGBA_RED),
|
||||||
|
points,
|
||||||
|
});
|
||||||
|
this.konvaLineGroup.add(this.konvaLine);
|
||||||
|
this.lastEraserLine = eraserLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(eraserLine: EraserLine, force?: boolean): boolean {
|
||||||
|
if (this.lastEraserLine !== eraserLine || force) {
|
||||||
|
const { points, clip, strokeWidth } = eraserLine;
|
||||||
|
this.konvaLine.setAttrs({
|
||||||
|
points,
|
||||||
|
clip,
|
||||||
|
strokeWidth,
|
||||||
|
});
|
||||||
|
this.lastEraserLine = eraserLine;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.konvaLineGroup.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,158 @@
|
|||||||
|
import type { ImageObject } from 'features/controlLayers/store/types';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import Konva from 'konva';
|
||||||
|
import { getImageDTO as defaultGetImageDTO } from 'services/api/endpoints/images';
|
||||||
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
|
export class CanvasImage {
|
||||||
|
id: string;
|
||||||
|
konvaImageGroup: Konva.Group;
|
||||||
|
konvaPlaceholderGroup: Konva.Group;
|
||||||
|
konvaPlaceholderRect: Konva.Rect;
|
||||||
|
konvaPlaceholderText: Konva.Text;
|
||||||
|
imageName: string | null;
|
||||||
|
konvaImage: Konva.Image | null; // The image is loaded asynchronously, so it may not be available immediately
|
||||||
|
isLoading: boolean;
|
||||||
|
isError: boolean;
|
||||||
|
getImageDTO: (imageName: string) => Promise<ImageDTO | null>;
|
||||||
|
onLoading: () => void;
|
||||||
|
onLoad: (imageName: string, imageEl: HTMLImageElement) => void;
|
||||||
|
onError: () => void;
|
||||||
|
lastImageObject: ImageObject;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
imageObject: ImageObject,
|
||||||
|
options: {
|
||||||
|
getImageDTO?: (imageName: string) => Promise<ImageDTO | null>;
|
||||||
|
onLoading?: () => void;
|
||||||
|
onLoad?: (konvaImage: Konva.Image) => void;
|
||||||
|
onError?: () => void;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const { getImageDTO, onLoading, onLoad, onError } = options;
|
||||||
|
const { id, width, height, x, y } = imageObject;
|
||||||
|
this.konvaImageGroup = new Konva.Group({ id, listening: false, x, y });
|
||||||
|
this.konvaPlaceholderGroup = new Konva.Group({ listening: false });
|
||||||
|
this.konvaPlaceholderRect = new Konva.Rect({
|
||||||
|
fill: 'hsl(220 12% 45% / 1)', // 'base.500'
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
this.konvaPlaceholderText = new Konva.Text({
|
||||||
|
fill: 'hsl(220 12% 10% / 1)', // 'base.900'
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
align: 'center',
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
fontFamily: '"Inter Variable", sans-serif',
|
||||||
|
fontSize: width / 16,
|
||||||
|
fontStyle: '600',
|
||||||
|
text: t('common.loadingImage', 'Loading Image'),
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.konvaPlaceholderGroup.add(this.konvaPlaceholderRect);
|
||||||
|
this.konvaPlaceholderGroup.add(this.konvaPlaceholderText);
|
||||||
|
this.konvaImageGroup.add(this.konvaPlaceholderGroup);
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.imageName = null;
|
||||||
|
this.konvaImage = null;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.isError = false;
|
||||||
|
this.getImageDTO = getImageDTO ?? defaultGetImageDTO;
|
||||||
|
this.onLoading = function () {
|
||||||
|
this.isLoading = true;
|
||||||
|
if (!this.konvaImage) {
|
||||||
|
this.konvaPlaceholderGroup.visible(true);
|
||||||
|
this.konvaPlaceholderText.text(t('common.loadingImage', 'Loading Image'));
|
||||||
|
}
|
||||||
|
this.konvaImageGroup.visible(true);
|
||||||
|
if (onLoading) {
|
||||||
|
onLoading();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.onLoad = function (imageName: string, imageEl: HTMLImageElement) {
|
||||||
|
if (this.konvaImage) {
|
||||||
|
this.konvaImage.setAttrs({
|
||||||
|
image: imageEl,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.konvaImage = new Konva.Image({
|
||||||
|
id: this.id,
|
||||||
|
listening: false,
|
||||||
|
image: imageEl,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
this.konvaImageGroup.add(this.konvaImage);
|
||||||
|
}
|
||||||
|
this.imageName = imageName;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.isError = false;
|
||||||
|
this.konvaPlaceholderGroup.visible(false);
|
||||||
|
this.konvaImageGroup.visible(true);
|
||||||
|
|
||||||
|
if (onLoad) {
|
||||||
|
onLoad(this.konvaImage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.onError = function () {
|
||||||
|
this.imageName = null;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.isError = true;
|
||||||
|
this.konvaPlaceholderGroup.visible(true);
|
||||||
|
this.konvaPlaceholderText.text(t('common.imageFailedToLoad', 'Image Failed to Load'));
|
||||||
|
this.konvaImageGroup.visible(true);
|
||||||
|
|
||||||
|
if (onError) {
|
||||||
|
onError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.lastImageObject = imageObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateImageSource(imageName: string) {
|
||||||
|
try {
|
||||||
|
this.onLoading();
|
||||||
|
|
||||||
|
const imageDTO = await this.getImageDTO(imageName);
|
||||||
|
if (!imageDTO) {
|
||||||
|
this.onError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const imageEl = new Image();
|
||||||
|
imageEl.onload = () => {
|
||||||
|
this.onLoad(imageName, imageEl);
|
||||||
|
};
|
||||||
|
imageEl.onerror = () => {
|
||||||
|
this.onError();
|
||||||
|
};
|
||||||
|
imageEl.id = imageName;
|
||||||
|
imageEl.src = imageDTO.image_url;
|
||||||
|
} catch {
|
||||||
|
this.onError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(imageObject: ImageObject, force?: boolean): Promise<boolean> {
|
||||||
|
if (this.lastImageObject !== imageObject || force) {
|
||||||
|
const { width, height, x, y, image } = imageObject;
|
||||||
|
if (this.lastImageObject.image.name !== image.name || force) {
|
||||||
|
await this.updateImageSource(image.name);
|
||||||
|
}
|
||||||
|
this.konvaImage?.setAttrs({ x, y, width, height });
|
||||||
|
this.konvaPlaceholderRect.setAttrs({ width, height });
|
||||||
|
this.konvaPlaceholderText.setAttrs({ width, height, fontSize: width / 16 });
|
||||||
|
this.lastImageObject = imageObject;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.konvaImageGroup.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
import { rgbColorToString } from 'common/util/colorCodeTransformers';
|
import { rgbColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import { CanvasBrushLine } from 'features/controlLayers/konva/CanvasBrushLine';
|
||||||
|
import { CanvasEraserLine } from 'features/controlLayers/konva/CanvasEraserLine';
|
||||||
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
|
import { CanvasRect } from 'features/controlLayers/konva/CanvasRect';
|
||||||
import { getNodeBboxFast } from 'features/controlLayers/konva/entityBbox';
|
import { getNodeBboxFast } from 'features/controlLayers/konva/entityBbox';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
|
||||||
import { getObjectGroupId, INPAINT_MASK_LAYER_ID } from 'features/controlLayers/konva/naming';
|
import { getObjectGroupId, INPAINT_MASK_LAYER_ID } from 'features/controlLayers/konva/naming';
|
||||||
import { KonvaBrushLine, KonvaEraserLine, KonvaRect } from 'features/controlLayers/konva/objects';
|
|
||||||
import { mapId } from 'features/controlLayers/konva/util';
|
import { mapId } from 'features/controlLayers/konva/util';
|
||||||
import { type InpaintMaskEntity, isDrawingTool } from 'features/controlLayers/store/types';
|
import { type InpaintMaskEntity, isDrawingTool } from 'features/controlLayers/store/types';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
@ -11,15 +13,15 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
|
|
||||||
export class CanvasInpaintMask {
|
export class CanvasInpaintMask {
|
||||||
id: string;
|
id: string;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
objectsGroup: Konva.Group;
|
objectsGroup: Konva.Group;
|
||||||
compositingRect: Konva.Rect;
|
compositingRect: Konva.Rect;
|
||||||
transformer: Konva.Transformer;
|
transformer: Konva.Transformer;
|
||||||
objects: Map<string, KonvaBrushLine | KonvaEraserLine | KonvaRect>;
|
objects: Map<string, CanvasBrushLine | CanvasEraserLine | CanvasRect>;
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager) {
|
constructor(manager: CanvasManager) {
|
||||||
this.id = INPAINT_MASK_LAYER_ID;
|
this.id = INPAINT_MASK_LAYER_ID;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.layer = new Konva.Layer({ id: INPAINT_MASK_LAYER_ID });
|
this.layer = new Konva.Layer({ id: INPAINT_MASK_LAYER_ID });
|
||||||
@ -84,10 +86,10 @@ export class CanvasInpaintMask {
|
|||||||
for (const obj of inpaintMaskState.objects) {
|
for (const obj of inpaintMaskState.objects) {
|
||||||
if (obj.type === 'brush_line') {
|
if (obj.type === 'brush_line') {
|
||||||
let brushLine = this.objects.get(obj.id);
|
let brushLine = this.objects.get(obj.id);
|
||||||
assert(brushLine instanceof KonvaBrushLine || brushLine === undefined);
|
assert(brushLine instanceof CanvasBrushLine || brushLine === undefined);
|
||||||
|
|
||||||
if (!brushLine) {
|
if (!brushLine) {
|
||||||
brushLine = new KonvaBrushLine(obj);
|
brushLine = new CanvasBrushLine(obj);
|
||||||
this.objects.set(brushLine.id, brushLine);
|
this.objects.set(brushLine.id, brushLine);
|
||||||
this.objectsGroup.add(brushLine.konvaLineGroup);
|
this.objectsGroup.add(brushLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -98,10 +100,10 @@ export class CanvasInpaintMask {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'eraser_line') {
|
} else if (obj.type === 'eraser_line') {
|
||||||
let eraserLine = this.objects.get(obj.id);
|
let eraserLine = this.objects.get(obj.id);
|
||||||
assert(eraserLine instanceof KonvaEraserLine || eraserLine === undefined);
|
assert(eraserLine instanceof CanvasEraserLine || eraserLine === undefined);
|
||||||
|
|
||||||
if (!eraserLine) {
|
if (!eraserLine) {
|
||||||
eraserLine = new KonvaEraserLine(obj);
|
eraserLine = new CanvasEraserLine(obj);
|
||||||
this.objects.set(eraserLine.id, eraserLine);
|
this.objects.set(eraserLine.id, eraserLine);
|
||||||
this.objectsGroup.add(eraserLine.konvaLineGroup);
|
this.objectsGroup.add(eraserLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -112,10 +114,10 @@ export class CanvasInpaintMask {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'rect_shape') {
|
} else if (obj.type === 'rect_shape') {
|
||||||
let rect = this.objects.get(obj.id);
|
let rect = this.objects.get(obj.id);
|
||||||
assert(rect instanceof KonvaRect || rect === undefined);
|
assert(rect instanceof CanvasRect || rect === undefined);
|
||||||
|
|
||||||
if (!rect) {
|
if (!rect) {
|
||||||
rect = new KonvaRect(obj);
|
rect = new CanvasRect(obj);
|
||||||
this.objects.set(rect.id, rect);
|
this.objects.set(rect.id, rect);
|
||||||
this.objectsGroup.add(rect.konvaRect);
|
this.objectsGroup.add(rect.konvaRect);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import { CanvasBrushLine } from 'features/controlLayers/konva/CanvasBrushLine';
|
||||||
|
import { CanvasEraserLine } from 'features/controlLayers/konva/CanvasEraserLine';
|
||||||
|
import { CanvasImage } from 'features/controlLayers/konva/CanvasImage';
|
||||||
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
|
import { CanvasRect } from 'features/controlLayers/konva/CanvasRect';
|
||||||
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
||||||
import { KonvaBrushLine, KonvaEraserLine, KonvaImage, KonvaRect } from 'features/controlLayers/konva/objects';
|
|
||||||
import { mapId } from 'features/controlLayers/konva/util';
|
import { mapId } from 'features/controlLayers/konva/util';
|
||||||
import { isDrawingTool, type LayerEntity } from 'features/controlLayers/store/types';
|
import { isDrawingTool, type LayerEntity } from 'features/controlLayers/store/types';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
@ -9,13 +12,13 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
|
|
||||||
export class CanvasLayer {
|
export class CanvasLayer {
|
||||||
id: string;
|
id: string;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
transformer: Konva.Transformer;
|
transformer: Konva.Transformer;
|
||||||
objects: Map<string, KonvaBrushLine | KonvaEraserLine | KonvaRect | KonvaImage>;
|
objects: Map<string, CanvasBrushLine | CanvasEraserLine | CanvasRect | CanvasImage>;
|
||||||
|
|
||||||
constructor(entity: LayerEntity, manager: KonvaNodeManager) {
|
constructor(entity: LayerEntity, manager: CanvasManager) {
|
||||||
this.id = entity.id;
|
this.id = entity.id;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.layer = new Konva.Layer({
|
this.layer = new Konva.Layer({
|
||||||
@ -79,10 +82,10 @@ export class CanvasLayer {
|
|||||||
for (const obj of layerState.objects) {
|
for (const obj of layerState.objects) {
|
||||||
if (obj.type === 'brush_line') {
|
if (obj.type === 'brush_line') {
|
||||||
let brushLine = this.objects.get(obj.id);
|
let brushLine = this.objects.get(obj.id);
|
||||||
assert(brushLine instanceof KonvaBrushLine || brushLine === undefined);
|
assert(brushLine instanceof CanvasBrushLine || brushLine === undefined);
|
||||||
|
|
||||||
if (!brushLine) {
|
if (!brushLine) {
|
||||||
brushLine = new KonvaBrushLine(obj);
|
brushLine = new CanvasBrushLine(obj);
|
||||||
this.objects.set(brushLine.id, brushLine);
|
this.objects.set(brushLine.id, brushLine);
|
||||||
this.group.add(brushLine.konvaLineGroup);
|
this.group.add(brushLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -93,10 +96,10 @@ export class CanvasLayer {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'eraser_line') {
|
} else if (obj.type === 'eraser_line') {
|
||||||
let eraserLine = this.objects.get(obj.id);
|
let eraserLine = this.objects.get(obj.id);
|
||||||
assert(eraserLine instanceof KonvaEraserLine || eraserLine === undefined);
|
assert(eraserLine instanceof CanvasEraserLine || eraserLine === undefined);
|
||||||
|
|
||||||
if (!eraserLine) {
|
if (!eraserLine) {
|
||||||
eraserLine = new KonvaEraserLine(obj);
|
eraserLine = new CanvasEraserLine(obj);
|
||||||
this.objects.set(eraserLine.id, eraserLine);
|
this.objects.set(eraserLine.id, eraserLine);
|
||||||
this.group.add(eraserLine.konvaLineGroup);
|
this.group.add(eraserLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -107,10 +110,10 @@ export class CanvasLayer {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'rect_shape') {
|
} else if (obj.type === 'rect_shape') {
|
||||||
let rect = this.objects.get(obj.id);
|
let rect = this.objects.get(obj.id);
|
||||||
assert(rect instanceof KonvaRect || rect === undefined);
|
assert(rect instanceof CanvasRect || rect === undefined);
|
||||||
|
|
||||||
if (!rect) {
|
if (!rect) {
|
||||||
rect = new KonvaRect(obj);
|
rect = new CanvasRect(obj);
|
||||||
this.objects.set(rect.id, rect);
|
this.objects.set(rect.id, rect);
|
||||||
this.group.add(rect.konvaRect);
|
this.group.add(rect.konvaRect);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -121,10 +124,10 @@ export class CanvasLayer {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'image') {
|
} else if (obj.type === 'image') {
|
||||||
let image = this.objects.get(obj.id);
|
let image = this.objects.get(obj.id);
|
||||||
assert(image instanceof KonvaImage || image === undefined);
|
assert(image instanceof CanvasImage || image === undefined);
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
image = await new KonvaImage(obj, {
|
image = await new CanvasImage(obj, {
|
||||||
onLoad: () => {
|
onLoad: () => {
|
||||||
this.updateGroup(true);
|
this.updateGroup(true);
|
||||||
},
|
},
|
||||||
|
@ -34,17 +34,17 @@ type Util = {
|
|||||||
) => Promise<ImageDTO>;
|
) => Promise<ImageDTO>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const $nodeManager = atom<KonvaNodeManager | null>(null);
|
const $canvasManager = atom<CanvasManager | null>(null);
|
||||||
export function getNodeManager() {
|
export function getCanvasManager() {
|
||||||
const nodeManager = $nodeManager.get();
|
const nodeManager = $canvasManager.get();
|
||||||
assert(nodeManager !== null, 'Node manager not initialized');
|
assert(nodeManager !== null, 'Node manager not initialized');
|
||||||
return nodeManager;
|
return nodeManager;
|
||||||
}
|
}
|
||||||
export function setNodeManager(nodeManager: KonvaNodeManager) {
|
export function setCanvasManager(nodeManager: CanvasManager) {
|
||||||
$nodeManager.set(nodeManager);
|
$canvasManager.set(nodeManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KonvaNodeManager {
|
export class CanvasManager {
|
||||||
stage: Konva.Stage;
|
stage: Konva.Stage;
|
||||||
container: HTMLDivElement;
|
container: HTMLDivElement;
|
||||||
controlAdapters: Map<string, CanvasControlAdapter>;
|
controlAdapters: Map<string, CanvasControlAdapter>;
|
@ -0,0 +1,60 @@
|
|||||||
|
import Konva from 'konva';
|
||||||
|
|
||||||
|
export class CanvasProgressImage {
|
||||||
|
id: string;
|
||||||
|
progressImageId: string | null;
|
||||||
|
konvaImageGroup: Konva.Group;
|
||||||
|
konvaImage: Konva.Image | null; // The image is loaded asynchronously, so it may not be available immediately
|
||||||
|
isLoading: boolean;
|
||||||
|
isError: boolean;
|
||||||
|
|
||||||
|
constructor(arg: { id: string }) {
|
||||||
|
const { id } = arg;
|
||||||
|
this.konvaImageGroup = new Konva.Group({ id, listening: false });
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.progressImageId = null;
|
||||||
|
this.konvaImage = null;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.isError = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateImageSource(
|
||||||
|
progressImageId: string,
|
||||||
|
dataURL: string,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
) {
|
||||||
|
const imageEl = new Image();
|
||||||
|
imageEl.onload = () => {
|
||||||
|
if (this.konvaImage) {
|
||||||
|
this.konvaImage.setAttrs({
|
||||||
|
image: imageEl,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.konvaImage = new Konva.Image({
|
||||||
|
id: this.id,
|
||||||
|
listening: false,
|
||||||
|
image: imageEl,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
this.konvaImageGroup.add(this.konvaImage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
imageEl.id = progressImageId;
|
||||||
|
imageEl.src = dataURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.konvaImageGroup.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import type { RectShape } from 'features/controlLayers/store/types';
|
||||||
|
import Konva from 'konva';
|
||||||
|
|
||||||
|
export class CanvasRect {
|
||||||
|
id: string;
|
||||||
|
konvaRect: Konva.Rect;
|
||||||
|
lastRectShape: RectShape;
|
||||||
|
|
||||||
|
constructor(rectShape: RectShape) {
|
||||||
|
const { id, x, y, width, height } = rectShape;
|
||||||
|
this.id = id;
|
||||||
|
const konvaRect = new Konva.Rect({
|
||||||
|
id,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
listening: false,
|
||||||
|
fill: rgbaColorToString(rectShape.color),
|
||||||
|
});
|
||||||
|
this.konvaRect = konvaRect;
|
||||||
|
this.lastRectShape = rectShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(rectShape: RectShape, force?: boolean): boolean {
|
||||||
|
if (this.lastRectShape !== rectShape || force) {
|
||||||
|
const { x, y, width, height, color } = rectShape;
|
||||||
|
this.konvaRect.setAttrs({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
fill: rgbaColorToString(color),
|
||||||
|
});
|
||||||
|
this.lastRectShape = rectShape;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.konvaRect.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
import { rgbColorToString } from 'common/util/colorCodeTransformers';
|
import { rgbColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import { CanvasBrushLine } from 'features/controlLayers/konva/CanvasBrushLine';
|
||||||
|
import { CanvasEraserLine } from 'features/controlLayers/konva/CanvasEraserLine';
|
||||||
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
|
import { CanvasRect } from 'features/controlLayers/konva/CanvasRect';
|
||||||
import { getNodeBboxFast } from 'features/controlLayers/konva/entityBbox';
|
import { getNodeBboxFast } from 'features/controlLayers/konva/entityBbox';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
|
||||||
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
||||||
import { KonvaBrushLine, KonvaEraserLine, KonvaRect } from 'features/controlLayers/konva/objects';
|
|
||||||
import { mapId } from 'features/controlLayers/konva/util';
|
import { mapId } from 'features/controlLayers/konva/util';
|
||||||
import { isDrawingTool, type RegionEntity } from 'features/controlLayers/store/types';
|
import { isDrawingTool, type RegionEntity } from 'features/controlLayers/store/types';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
@ -11,15 +13,15 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
|
|
||||||
export class CanvasRegion {
|
export class CanvasRegion {
|
||||||
id: string;
|
id: string;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
objectsGroup: Konva.Group;
|
objectsGroup: Konva.Group;
|
||||||
compositingRect: Konva.Rect;
|
compositingRect: Konva.Rect;
|
||||||
transformer: Konva.Transformer;
|
transformer: Konva.Transformer;
|
||||||
objects: Map<string, KonvaBrushLine | KonvaEraserLine | KonvaRect>;
|
objects: Map<string, CanvasBrushLine | CanvasEraserLine | CanvasRect>;
|
||||||
|
|
||||||
constructor(entity: RegionEntity, manager: KonvaNodeManager) {
|
constructor(entity: RegionEntity, manager: CanvasManager) {
|
||||||
this.id = entity.id;
|
this.id = entity.id;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.layer = new Konva.Layer({ id: entity.id });
|
this.layer = new Konva.Layer({ id: entity.id });
|
||||||
@ -84,10 +86,10 @@ export class CanvasRegion {
|
|||||||
for (const obj of regionState.objects) {
|
for (const obj of regionState.objects) {
|
||||||
if (obj.type === 'brush_line') {
|
if (obj.type === 'brush_line') {
|
||||||
let brushLine = this.objects.get(obj.id);
|
let brushLine = this.objects.get(obj.id);
|
||||||
assert(brushLine instanceof KonvaBrushLine || brushLine === undefined);
|
assert(brushLine instanceof CanvasBrushLine || brushLine === undefined);
|
||||||
|
|
||||||
if (!brushLine) {
|
if (!brushLine) {
|
||||||
brushLine = new KonvaBrushLine(obj);
|
brushLine = new CanvasBrushLine(obj);
|
||||||
this.objects.set(brushLine.id, brushLine);
|
this.objects.set(brushLine.id, brushLine);
|
||||||
this.objectsGroup.add(brushLine.konvaLineGroup);
|
this.objectsGroup.add(brushLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -98,10 +100,10 @@ export class CanvasRegion {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'eraser_line') {
|
} else if (obj.type === 'eraser_line') {
|
||||||
let eraserLine = this.objects.get(obj.id);
|
let eraserLine = this.objects.get(obj.id);
|
||||||
assert(eraserLine instanceof KonvaEraserLine || eraserLine === undefined);
|
assert(eraserLine instanceof CanvasEraserLine || eraserLine === undefined);
|
||||||
|
|
||||||
if (!eraserLine) {
|
if (!eraserLine) {
|
||||||
eraserLine = new KonvaEraserLine(obj);
|
eraserLine = new CanvasEraserLine(obj);
|
||||||
this.objects.set(eraserLine.id, eraserLine);
|
this.objects.set(eraserLine.id, eraserLine);
|
||||||
this.objectsGroup.add(eraserLine.konvaLineGroup);
|
this.objectsGroup.add(eraserLine.konvaLineGroup);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
@ -112,10 +114,10 @@ export class CanvasRegion {
|
|||||||
}
|
}
|
||||||
} else if (obj.type === 'rect_shape') {
|
} else if (obj.type === 'rect_shape') {
|
||||||
let rect = this.objects.get(obj.id);
|
let rect = this.objects.get(obj.id);
|
||||||
assert(rect instanceof KonvaRect || rect === undefined);
|
assert(rect instanceof CanvasRect || rect === undefined);
|
||||||
|
|
||||||
if (!rect) {
|
if (!rect) {
|
||||||
rect = new KonvaRect(obj);
|
rect = new CanvasRect(obj);
|
||||||
this.objects.set(rect.id, rect);
|
this.objects.set(rect.id, rect);
|
||||||
this.objectsGroup.add(rect.konvaRect);
|
this.objectsGroup.add(rect.konvaRect);
|
||||||
didDraw = true;
|
didDraw = true;
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import { CanvasImage } from 'features/controlLayers/konva/CanvasImage';
|
||||||
import { KonvaImage, KonvaProgressImage } from 'features/controlLayers/konva/objects';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
|
import { CanvasProgressImage } from 'features/controlLayers/konva/CanvasProgressImage';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
export class CanvasStagingArea {
|
export class CanvasStagingArea {
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
image: KonvaImage | null;
|
image: CanvasImage | null;
|
||||||
progressImage: KonvaProgressImage | null;
|
progressImage: CanvasProgressImage | null;
|
||||||
imageDTO: ImageDTO | null;
|
imageDTO: ImageDTO | null;
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager) {
|
constructor(manager: CanvasManager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.group = new Konva.Group({ listening: false });
|
this.group = new Konva.Group({ listening: false });
|
||||||
this.image = null;
|
this.image = null;
|
||||||
@ -37,7 +38,7 @@ export class CanvasStagingArea {
|
|||||||
this.progressImage?.konvaImageGroup.visible(false);
|
this.progressImage?.konvaImageGroup.visible(false);
|
||||||
} else {
|
} else {
|
||||||
const { image_name, width, height } = this.imageDTO;
|
const { image_name, width, height } = this.imageDTO;
|
||||||
this.image = new KonvaImage(
|
this.image = new CanvasImage(
|
||||||
{
|
{
|
||||||
id: 'staging-area-image',
|
id: 'staging-area-image',
|
||||||
type: 'image',
|
type: 'image',
|
||||||
@ -85,7 +86,7 @@ export class CanvasStagingArea {
|
|||||||
this.progressImage.konvaImageGroup.visible(true);
|
this.progressImage.konvaImageGroup.visible(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.progressImage = new KonvaProgressImage({ id: 'progress-image' });
|
this.progressImage = new CanvasProgressImage({ id: 'progress-image' });
|
||||||
this.group.add(this.progressImage.konvaImageGroup);
|
this.group.add(this.progressImage.konvaImageGroup);
|
||||||
await this.progressImage.updateImageSource(progressImageId, dataURL, x, y, width, height);
|
await this.progressImage.updateImageSource(progressImageId, dataURL, x, y, width, height);
|
||||||
this.image?.konvaImageGroup.visible(false);
|
this.image?.konvaImageGroup.visible(false);
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||||
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import {
|
import {
|
||||||
BRUSH_BORDER_INNER_COLOR,
|
BRUSH_BORDER_INNER_COLOR,
|
||||||
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 type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
|
||||||
import { PREVIEW_RECT_ID } from 'features/controlLayers/konva/naming';
|
import { PREVIEW_RECT_ID } from 'features/controlLayers/konva/naming';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
|
||||||
export class CanvasTool {
|
export class CanvasTool {
|
||||||
manager: KonvaNodeManager;
|
manager: CanvasManager;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
brush: {
|
brush: {
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
@ -28,7 +28,7 @@ export class CanvasTool {
|
|||||||
fillRect: Konva.Rect;
|
fillRect: Konva.Rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(manager: KonvaNodeManager) {
|
constructor(manager: CanvasManager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.group = new Konva.Group();
|
this.group = new Konva.Group();
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
|
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
|
||||||
import {
|
import {
|
||||||
CA_LAYER_IMAGE_NAME,
|
CA_LAYER_IMAGE_NAME,
|
||||||
|
getLayerBboxId,
|
||||||
LAYER_BBOX_NAME,
|
LAYER_BBOX_NAME,
|
||||||
RASTER_LAYER_OBJECT_GROUP_NAME,
|
RASTER_LAYER_OBJECT_GROUP_NAME,
|
||||||
RG_LAYER_OBJECT_GROUP_NAME,
|
RG_LAYER_OBJECT_GROUP_NAME,
|
||||||
} from 'features/controlLayers/konva/naming';
|
} from 'features/controlLayers/konva/naming';
|
||||||
import { createBboxRect } from 'features/controlLayers/konva/objects';
|
|
||||||
import { imageDataToDataURL } from 'features/controlLayers/konva/util';
|
import { imageDataToDataURL } from 'features/controlLayers/konva/util';
|
||||||
import type {
|
import type {
|
||||||
BboxChangedArg,
|
BboxChangedArg,
|
||||||
@ -18,6 +18,22 @@ import Konva from 'konva';
|
|||||||
import type { IRect } from 'konva/lib/types';
|
import type { IRect } from 'konva/lib/types';
|
||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bounding box rect for a layer.
|
||||||
|
* @param entity The layer state for the layer to create the bounding box for
|
||||||
|
* @param konvaLayer The konva layer to attach the bounding box to
|
||||||
|
*/
|
||||||
|
export const createBboxRect = (entity: CanvasEntity, konvaLayer: Konva.Layer): Konva.Rect => {
|
||||||
|
const rect = new Konva.Rect({
|
||||||
|
id: getLayerBboxId(entity.id),
|
||||||
|
name: LAYER_BBOX_NAME,
|
||||||
|
strokeWidth: 1,
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
konvaLayer.add(rect);
|
||||||
|
return rect;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logic to create and render bounding boxes for layers.
|
* Logic to create and render bounding boxes for layers.
|
||||||
* Some utils are included for calculating bounding boxes.
|
* Some utils are included for calculating bounding boxes.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { getScaledCursorPosition } from 'features/controlLayers/konva/util';
|
import { getScaledCursorPosition } from 'features/controlLayers/konva/util';
|
||||||
import type { CanvasEntity } from 'features/controlLayers/store/types';
|
import type { CanvasEntity } from 'features/controlLayers/store/types';
|
||||||
import type Konva from 'konva';
|
import type Konva from 'konva';
|
||||||
@ -23,7 +23,7 @@ import { PREVIEW_TOOL_GROUP_ID } from './naming';
|
|||||||
*/
|
*/
|
||||||
const updateLastCursorPos = (
|
const updateLastCursorPos = (
|
||||||
stage: Konva.Stage,
|
stage: Konva.Stage,
|
||||||
setLastCursorPos: KonvaNodeManager['stateApi']['setLastCursorPos']
|
setLastCursorPos: CanvasManager['stateApi']['setLastCursorPos']
|
||||||
) => {
|
) => {
|
||||||
const pos = getScaledCursorPosition(stage);
|
const pos = getScaledCursorPosition(stage);
|
||||||
if (!pos) {
|
if (!pos) {
|
||||||
@ -56,10 +56,10 @@ const calculateNewBrushSize = (brushSize: number, delta: number) => {
|
|||||||
const maybeAddNextPoint = (
|
const maybeAddNextPoint = (
|
||||||
selectedEntity: CanvasEntity,
|
selectedEntity: CanvasEntity,
|
||||||
currentPos: Vector2d,
|
currentPos: Vector2d,
|
||||||
getToolState: KonvaNodeManager['stateApi']['getToolState'],
|
getToolState: CanvasManager['stateApi']['getToolState'],
|
||||||
getLastAddedPoint: KonvaNodeManager['stateApi']['getLastAddedPoint'],
|
getLastAddedPoint: CanvasManager['stateApi']['getLastAddedPoint'],
|
||||||
setLastAddedPoint: KonvaNodeManager['stateApi']['setLastAddedPoint'],
|
setLastAddedPoint: CanvasManager['stateApi']['setLastAddedPoint'],
|
||||||
onPointAddedToLine: KonvaNodeManager['stateApi']['onPointAddedToLine']
|
onPointAddedToLine: CanvasManager['stateApi']['onPointAddedToLine']
|
||||||
) => {
|
) => {
|
||||||
const isDrawableEntity =
|
const isDrawableEntity =
|
||||||
selectedEntity?.type === 'regional_guidance' ||
|
selectedEntity?.type === 'regional_guidance' ||
|
||||||
@ -95,7 +95,7 @@ const maybeAddNextPoint = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setStageEventHandlers = (manager: KonvaNodeManager): (() => void) => {
|
export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||||
const { stage, stateApi } = manager;
|
const { stage, stateApi } = manager;
|
||||||
const {
|
const {
|
||||||
getToolState,
|
getToolState,
|
||||||
|
@ -1,378 +0,0 @@
|
|||||||
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
|
||||||
import { getLayerBboxId, LAYER_BBOX_NAME } from 'features/controlLayers/konva/naming';
|
|
||||||
import type { BrushLine, CanvasEntity, EraserLine, ImageObject, RectShape } from 'features/controlLayers/store/types';
|
|
||||||
import { RGBA_RED } from 'features/controlLayers/store/types';
|
|
||||||
import { t } from 'i18next';
|
|
||||||
import Konva from 'konva';
|
|
||||||
import { getImageDTO as defaultGetImageDTO } from 'services/api/endpoints/images';
|
|
||||||
import type { ImageDTO } from 'services/api/types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a bounding box rect for a layer.
|
|
||||||
* @param entity The layer state for the layer to create the bounding box for
|
|
||||||
* @param konvaLayer The konva layer to attach the bounding box to
|
|
||||||
*/
|
|
||||||
export const createBboxRect = (entity: CanvasEntity, konvaLayer: Konva.Layer): Konva.Rect => {
|
|
||||||
const rect = new Konva.Rect({
|
|
||||||
id: getLayerBboxId(entity.id),
|
|
||||||
name: LAYER_BBOX_NAME,
|
|
||||||
strokeWidth: 1,
|
|
||||||
visible: false,
|
|
||||||
});
|
|
||||||
konvaLayer.add(rect);
|
|
||||||
return rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class KonvaBrushLine {
|
|
||||||
id: string;
|
|
||||||
konvaLineGroup: Konva.Group;
|
|
||||||
konvaLine: Konva.Line;
|
|
||||||
lastBrushLine: BrushLine;
|
|
||||||
|
|
||||||
constructor(brushLine: BrushLine) {
|
|
||||||
const { id, strokeWidth, clip, color, points } = brushLine;
|
|
||||||
this.id = id;
|
|
||||||
this.konvaLineGroup = new Konva.Group({
|
|
||||||
clip,
|
|
||||||
listening: false,
|
|
||||||
});
|
|
||||||
this.konvaLine = new Konva.Line({
|
|
||||||
id,
|
|
||||||
listening: false,
|
|
||||||
shadowForStrokeEnabled: false,
|
|
||||||
strokeWidth,
|
|
||||||
tension: 0,
|
|
||||||
lineCap: 'round',
|
|
||||||
lineJoin: 'round',
|
|
||||||
globalCompositeOperation: 'source-over',
|
|
||||||
stroke: rgbaColorToString(color),
|
|
||||||
points,
|
|
||||||
});
|
|
||||||
this.konvaLineGroup.add(this.konvaLine);
|
|
||||||
this.lastBrushLine = brushLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(brushLine: BrushLine, force?: boolean): boolean {
|
|
||||||
if (this.lastBrushLine !== brushLine || force) {
|
|
||||||
const { points, color, clip, strokeWidth } = brushLine;
|
|
||||||
this.konvaLine.setAttrs({
|
|
||||||
points,
|
|
||||||
stroke: rgbaColorToString(color),
|
|
||||||
clip,
|
|
||||||
strokeWidth,
|
|
||||||
});
|
|
||||||
this.lastBrushLine = brushLine;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.konvaLineGroup.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class KonvaEraserLine {
|
|
||||||
id: string;
|
|
||||||
konvaLineGroup: Konva.Group;
|
|
||||||
konvaLine: Konva.Line;
|
|
||||||
lastEraserLine: EraserLine;
|
|
||||||
|
|
||||||
constructor(eraserLine: EraserLine) {
|
|
||||||
const { id, strokeWidth, clip, points } = eraserLine;
|
|
||||||
this.id = id;
|
|
||||||
this.konvaLineGroup = new Konva.Group({
|
|
||||||
clip,
|
|
||||||
listening: false,
|
|
||||||
});
|
|
||||||
this.konvaLine = new Konva.Line({
|
|
||||||
id,
|
|
||||||
listening: false,
|
|
||||||
shadowForStrokeEnabled: false,
|
|
||||||
strokeWidth,
|
|
||||||
tension: 0,
|
|
||||||
lineCap: 'round',
|
|
||||||
lineJoin: 'round',
|
|
||||||
globalCompositeOperation: 'destination-out',
|
|
||||||
stroke: rgbaColorToString(RGBA_RED),
|
|
||||||
points,
|
|
||||||
});
|
|
||||||
this.konvaLineGroup.add(this.konvaLine);
|
|
||||||
this.lastEraserLine = eraserLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(eraserLine: EraserLine, force?: boolean): boolean {
|
|
||||||
if (this.lastEraserLine !== eraserLine || force) {
|
|
||||||
const { points, clip, strokeWidth } = eraserLine;
|
|
||||||
this.konvaLine.setAttrs({
|
|
||||||
points,
|
|
||||||
clip,
|
|
||||||
strokeWidth,
|
|
||||||
});
|
|
||||||
this.lastEraserLine = eraserLine;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.konvaLineGroup.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class KonvaRect {
|
|
||||||
id: string;
|
|
||||||
konvaRect: Konva.Rect;
|
|
||||||
lastRectShape: RectShape;
|
|
||||||
|
|
||||||
constructor(rectShape: RectShape) {
|
|
||||||
const { id, x, y, width, height } = rectShape;
|
|
||||||
this.id = id;
|
|
||||||
const konvaRect = new Konva.Rect({
|
|
||||||
id,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
listening: false,
|
|
||||||
fill: rgbaColorToString(rectShape.color),
|
|
||||||
});
|
|
||||||
this.konvaRect = konvaRect;
|
|
||||||
this.lastRectShape = rectShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(rectShape: RectShape, force?: boolean): boolean {
|
|
||||||
if (this.lastRectShape !== rectShape || force) {
|
|
||||||
const { x, y, width, height, color } = rectShape;
|
|
||||||
this.konvaRect.setAttrs({
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
fill: rgbaColorToString(color),
|
|
||||||
});
|
|
||||||
this.lastRectShape = rectShape;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.konvaRect.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class KonvaImage {
|
|
||||||
id: string;
|
|
||||||
konvaImageGroup: Konva.Group;
|
|
||||||
konvaPlaceholderGroup: Konva.Group;
|
|
||||||
konvaPlaceholderRect: Konva.Rect;
|
|
||||||
konvaPlaceholderText: Konva.Text;
|
|
||||||
imageName: string | null;
|
|
||||||
konvaImage: Konva.Image | null; // The image is loaded asynchronously, so it may not be available immediately
|
|
||||||
isLoading: boolean;
|
|
||||||
isError: boolean;
|
|
||||||
getImageDTO: (imageName: string) => Promise<ImageDTO | null>;
|
|
||||||
onLoading: () => void;
|
|
||||||
onLoad: (imageName: string, imageEl: HTMLImageElement) => void;
|
|
||||||
onError: () => void;
|
|
||||||
lastImageObject: ImageObject;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
imageObject: ImageObject,
|
|
||||||
options: {
|
|
||||||
getImageDTO?: (imageName: string) => Promise<ImageDTO | null>;
|
|
||||||
onLoading?: () => void;
|
|
||||||
onLoad?: (konvaImage: Konva.Image) => void;
|
|
||||||
onError?: () => void;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
const { getImageDTO, onLoading, onLoad, onError } = options;
|
|
||||||
const { id, width, height, x, y } = imageObject;
|
|
||||||
this.konvaImageGroup = new Konva.Group({ id, listening: false, x, y });
|
|
||||||
this.konvaPlaceholderGroup = new Konva.Group({ listening: false });
|
|
||||||
this.konvaPlaceholderRect = new Konva.Rect({
|
|
||||||
fill: 'hsl(220 12% 45% / 1)', // 'base.500'
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
listening: false,
|
|
||||||
});
|
|
||||||
this.konvaPlaceholderText = new Konva.Text({
|
|
||||||
fill: 'hsl(220 12% 10% / 1)', // 'base.900'
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
align: 'center',
|
|
||||||
verticalAlign: 'middle',
|
|
||||||
fontFamily: '"Inter Variable", sans-serif',
|
|
||||||
fontSize: width / 16,
|
|
||||||
fontStyle: '600',
|
|
||||||
text: t('common.loadingImage', 'Loading Image'),
|
|
||||||
listening: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.konvaPlaceholderGroup.add(this.konvaPlaceholderRect);
|
|
||||||
this.konvaPlaceholderGroup.add(this.konvaPlaceholderText);
|
|
||||||
this.konvaImageGroup.add(this.konvaPlaceholderGroup);
|
|
||||||
|
|
||||||
this.id = id;
|
|
||||||
this.imageName = null;
|
|
||||||
this.konvaImage = null;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isError = false;
|
|
||||||
this.getImageDTO = getImageDTO ?? defaultGetImageDTO;
|
|
||||||
this.onLoading = function () {
|
|
||||||
this.isLoading = true;
|
|
||||||
if (!this.konvaImage) {
|
|
||||||
this.konvaPlaceholderGroup.visible(true);
|
|
||||||
this.konvaPlaceholderText.text(t('common.loadingImage', 'Loading Image'));
|
|
||||||
}
|
|
||||||
this.konvaImageGroup.visible(true);
|
|
||||||
if (onLoading) {
|
|
||||||
onLoading();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.onLoad = function (imageName: string, imageEl: HTMLImageElement) {
|
|
||||||
if (this.konvaImage) {
|
|
||||||
this.konvaImage.setAttrs({
|
|
||||||
image: imageEl,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.konvaImage = new Konva.Image({
|
|
||||||
id: this.id,
|
|
||||||
listening: false,
|
|
||||||
image: imageEl,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
this.konvaImageGroup.add(this.konvaImage);
|
|
||||||
}
|
|
||||||
this.imageName = imageName;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isError = false;
|
|
||||||
this.konvaPlaceholderGroup.visible(false);
|
|
||||||
this.konvaImageGroup.visible(true);
|
|
||||||
|
|
||||||
if (onLoad) {
|
|
||||||
onLoad(this.konvaImage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.onError = function () {
|
|
||||||
this.imageName = null;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isError = true;
|
|
||||||
this.konvaPlaceholderGroup.visible(true);
|
|
||||||
this.konvaPlaceholderText.text(t('common.imageFailedToLoad', 'Image Failed to Load'));
|
|
||||||
this.konvaImageGroup.visible(true);
|
|
||||||
|
|
||||||
if (onError) {
|
|
||||||
onError();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.lastImageObject = imageObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateImageSource(imageName: string) {
|
|
||||||
try {
|
|
||||||
this.onLoading();
|
|
||||||
|
|
||||||
const imageDTO = await this.getImageDTO(imageName);
|
|
||||||
if (!imageDTO) {
|
|
||||||
this.onError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const imageEl = new Image();
|
|
||||||
imageEl.onload = () => {
|
|
||||||
this.onLoad(imageName, imageEl);
|
|
||||||
};
|
|
||||||
imageEl.onerror = () => {
|
|
||||||
this.onError();
|
|
||||||
};
|
|
||||||
imageEl.id = imageName;
|
|
||||||
imageEl.src = imageDTO.image_url;
|
|
||||||
} catch {
|
|
||||||
this.onError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async update(imageObject: ImageObject, force?: boolean): Promise<boolean> {
|
|
||||||
if (this.lastImageObject !== imageObject || force) {
|
|
||||||
const { width, height, x, y, image } = imageObject;
|
|
||||||
if (this.lastImageObject.image.name !== image.name || force) {
|
|
||||||
await this.updateImageSource(image.name);
|
|
||||||
}
|
|
||||||
this.konvaImage?.setAttrs({ x, y, width, height });
|
|
||||||
this.konvaPlaceholderRect.setAttrs({ width, height });
|
|
||||||
this.konvaPlaceholderText.setAttrs({ width, height, fontSize: width / 16 });
|
|
||||||
this.lastImageObject = imageObject;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.konvaImageGroup.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class KonvaProgressImage {
|
|
||||||
id: string;
|
|
||||||
progressImageId: string | null;
|
|
||||||
konvaImageGroup: Konva.Group;
|
|
||||||
konvaImage: Konva.Image | null; // The image is loaded asynchronously, so it may not be available immediately
|
|
||||||
isLoading: boolean;
|
|
||||||
isError: boolean;
|
|
||||||
|
|
||||||
constructor(arg: { id: string }) {
|
|
||||||
const { id } = arg;
|
|
||||||
this.konvaImageGroup = new Konva.Group({ id, listening: false });
|
|
||||||
|
|
||||||
this.id = id;
|
|
||||||
this.progressImageId = null;
|
|
||||||
this.konvaImage = null;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isError = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateImageSource(
|
|
||||||
progressImageId: string,
|
|
||||||
dataURL: string,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
width: number,
|
|
||||||
height: number
|
|
||||||
) {
|
|
||||||
const imageEl = new Image();
|
|
||||||
imageEl.onload = () => {
|
|
||||||
if (this.konvaImage) {
|
|
||||||
this.konvaImage.setAttrs({
|
|
||||||
image: imageEl,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.konvaImage = new Konva.Image({
|
|
||||||
id: this.id,
|
|
||||||
listening: false,
|
|
||||||
image: imageEl,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
this.konvaImageGroup.add(this.konvaImage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
imageEl.id = progressImageId;
|
|
||||||
imageEl.src = dataURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.konvaImageGroup.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
||||||
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||||
import { isEqual, pick } from 'lodash-es';
|
import { isEqual, pick } from 'lodash-es';
|
||||||
@ -6,7 +6,7 @@ import type { Invocation } from 'services/api/types';
|
|||||||
|
|
||||||
export const addImageToImage = async (
|
export const addImageToImage = async (
|
||||||
g: Graph,
|
g: Graph,
|
||||||
manager: KonvaNodeManager,
|
manager: CanvasManager,
|
||||||
l2i: Invocation<'l2i'>,
|
l2i: Invocation<'l2i'>,
|
||||||
denoise: Invocation<'denoise_latents'>,
|
denoise: Invocation<'denoise_latents'>,
|
||||||
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
||||||
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||||
import type { ParameterPrecision } from 'features/parameters/types/parameterSchemas';
|
import type { ParameterPrecision } from 'features/parameters/types/parameterSchemas';
|
||||||
@ -7,7 +7,7 @@ import type { Invocation } from 'services/api/types';
|
|||||||
|
|
||||||
export const addInpaint = async (
|
export const addInpaint = async (
|
||||||
g: Graph,
|
g: Graph,
|
||||||
manager: KonvaNodeManager,
|
manager: CanvasManager,
|
||||||
l2i: Invocation<'l2i'>,
|
l2i: Invocation<'l2i'>,
|
||||||
denoise: Invocation<'denoise_latents'>,
|
denoise: Invocation<'denoise_latents'>,
|
||||||
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
import type { CanvasV2State, Size } from 'features/controlLayers/store/types';
|
||||||
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||||
import { getInfill } from 'features/nodes/util/graph/graphBuilderUtils';
|
import { getInfill } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||||
@ -8,7 +8,7 @@ import type { Invocation } from 'services/api/types';
|
|||||||
|
|
||||||
export const addOutpaint = async (
|
export const addOutpaint = async (
|
||||||
g: Graph,
|
g: Graph,
|
||||||
manager: KonvaNodeManager,
|
manager: CanvasManager,
|
||||||
l2i: Invocation<'l2i'>,
|
l2i: Invocation<'l2i'>,
|
||||||
denoise: Invocation<'denoise_latents'>,
|
denoise: Invocation<'denoise_latents'>,
|
||||||
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
vaeSource: Invocation<'main_model_loader' | 'sdxl_model_loader' | 'seamless' | 'vae_loader'>,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { deepClone } from 'common/util/deepClone';
|
import { deepClone } from 'common/util/deepClone';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import type { IPAdapterEntity, Rect, RegionEntity } from 'features/controlLayers/store/types';
|
import type { IPAdapterEntity, Rect, RegionEntity } from 'features/controlLayers/store/types';
|
||||||
import {
|
import {
|
||||||
PROMPT_REGION_INVERT_TENSOR_MASK_PREFIX,
|
PROMPT_REGION_INVERT_TENSOR_MASK_PREFIX,
|
||||||
@ -27,7 +27,7 @@ import { assert } from 'tsafe';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const addRegions = async (
|
export const addRegions = async (
|
||||||
manager: KonvaNodeManager,
|
manager: CanvasManager,
|
||||||
regions: RegionEntity[],
|
regions: RegionEntity[],
|
||||||
g: Graph,
|
g: Graph,
|
||||||
bbox: Rect,
|
bbox: Rect,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
import {
|
import {
|
||||||
LATENTS_TO_IMAGE,
|
LATENTS_TO_IMAGE,
|
||||||
@ -30,7 +30,7 @@ import { addRegions } from './addRegions';
|
|||||||
|
|
||||||
export const buildImageToImageSDXLGraph = async (
|
export const buildImageToImageSDXLGraph = async (
|
||||||
state: RootState,
|
state: RootState,
|
||||||
manager: KonvaNodeManager
|
manager: CanvasManager
|
||||||
): Promise<NonNullableGraph> => {
|
): Promise<NonNullableGraph> => {
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
const {
|
const {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
import {
|
import {
|
||||||
CANVAS_OUTPUT,
|
CANVAS_OUTPUT,
|
||||||
@ -34,7 +34,7 @@ import { assert } from 'tsafe';
|
|||||||
|
|
||||||
import { addRegions } from './addRegions';
|
import { addRegions } from './addRegions';
|
||||||
|
|
||||||
export const buildSD1Graph = async (state: RootState, manager: KonvaNodeManager): Promise<Graph> => {
|
export const buildSD1Graph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
||||||
const generationMode = manager.getGenerationMode();
|
const generationMode = manager.getGenerationMode();
|
||||||
|
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
import {
|
import {
|
||||||
CANVAS_OUTPUT,
|
CANVAS_OUTPUT,
|
||||||
@ -33,7 +33,7 @@ import { assert } from 'tsafe';
|
|||||||
|
|
||||||
import { addRegions } from './addRegions';
|
import { addRegions } from './addRegions';
|
||||||
|
|
||||||
export const buildSDXLGraph = async (state: RootState, manager: KonvaNodeManager): Promise<Graph> => {
|
export const buildSDXLGraph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
||||||
const generationMode = manager.getGenerationMode();
|
const generationMode = manager.getGenerationMode();
|
||||||
|
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { KonvaNodeManager } from 'features/controlLayers/konva/KonvaNodeManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
import {
|
import {
|
||||||
CLIP_SKIP,
|
CLIP_SKIP,
|
||||||
@ -31,7 +31,7 @@ import { assert } from 'tsafe';
|
|||||||
|
|
||||||
import { addRegions } from './addRegions';
|
import { addRegions } from './addRegions';
|
||||||
|
|
||||||
export const buildTextToImageSD1SD2Graph = async (state: RootState, manager: KonvaNodeManager): Promise<GraphType> => {
|
export const buildTextToImageSD1SD2Graph = async (state: RootState, manager: CanvasManager): Promise<GraphType> => {
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
Loading…
Reference in New Issue
Block a user