diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/konvaMap.ts b/invokeai/frontend/web/src/features/controlLayers/konva/entityToKonvaMap.ts similarity index 100% rename from invokeai/frontend/web/src/features/controlLayers/konva/konvaMap.ts rename to invokeai/frontend/web/src/features/controlLayers/konva/entityToKonvaMap.ts diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/events.ts b/invokeai/frontend/web/src/features/controlLayers/konva/events.ts index 19178a6651..0892d3da09 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/events.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/events.ts @@ -3,7 +3,7 @@ import { renderDocumentBoundsOverlay, renderToolPreview, scaleToolPreview, -} from 'features/controlLayers/konva/renderers/previewLayer'; +} from 'features/controlLayers/konva/renderers/preview'; import { fitDocumentToStage } from 'features/controlLayers/konva/renderers/stage'; import { getScaledFlooredCursorPosition } from 'features/controlLayers/konva/util'; import type { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/arrange.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/arrange.ts new file mode 100644 index 0000000000..d0b148da4d --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/arrange.ts @@ -0,0 +1,23 @@ +import { BACKGROUND_LAYER_ID, PREVIEW_LAYER_ID } from 'features/controlLayers/konva/naming'; +import type { ControlAdapterEntity, LayerEntity, RegionEntity } from 'features/controlLayers/store/types'; +import type Konva from 'konva'; + +export const arrangeEntities = ( + stage: Konva.Stage, + layers: LayerEntity[], + controlAdapters: ControlAdapterEntity[], + regions: RegionEntity[] +): void => { + let zIndex = 0; + stage.findOne(`#${BACKGROUND_LAYER_ID}`)?.zIndex(++zIndex); + for (const layer of layers) { + stage.findOne(`#${layer.id}`)?.zIndex(++zIndex); + } + for (const ca of controlAdapters) { + stage.findOne(`#${ca.id}`)?.zIndex(++zIndex); + } + for (const rg of regions) { + stage.findOne(`#${rg.id}`)?.zIndex(++zIndex); + } + stage.findOne(`#${PREVIEW_LAYER_ID}`)?.zIndex(++zIndex); +}; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/caLayer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/controlAdapters.ts similarity index 91% rename from invokeai/frontend/web/src/features/controlLayers/konva/renderers/caLayer.ts rename to invokeai/frontend/web/src/features/controlLayers/konva/renderers/controlAdapters.ts index 71ed5623f4..c69957e2c2 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/caLayer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/controlAdapters.ts @@ -1,5 +1,5 @@ +import type { EntityToKonvaMap } from 'features/controlLayers/konva/entityToKonvaMap'; import { LightnessToAlphaFilter } from 'features/controlLayers/konva/filters'; -import type { EntityToKonvaMap } from 'features/controlLayers/konva/konvaMap'; import { CA_LAYER_IMAGE_NAME, CA_LAYER_NAME, getCAImageId } from 'features/controlLayers/konva/naming'; import type { ControlAdapterEntity } from 'features/controlLayers/store/types'; import Konva from 'konva'; @@ -49,7 +49,7 @@ const createCALayerImage = (konvaLayer: Konva.Layer, imageEl: HTMLImageElement): * @param ca The control adapter layer state * @param getImageDTO A function to retrieve an image DTO from the server, used to update the image source */ -const updateCALayerImageSource = async ( +const updateControlAdapterImageSource = async ( stage: Konva.Stage, konvaLayer: Konva.Layer, ca: ControlAdapterEntity, @@ -74,7 +74,7 @@ const updateCALayerImageSource = async ( id: imageId, image: imageEl, }); - updateCALayerImageAttrs(stage, konvaImage, ca); + updateControlAdapterImageAttrs(stage, konvaImage, ca); // Must cache after this to apply the filters konvaImage.cache(); imageEl.id = imageId; @@ -92,7 +92,7 @@ const updateCALayerImageSource = async ( * @param ca The control adapter layer state */ -const updateCALayerImageAttrs = (stage: Konva.Stage, konvaImage: Konva.Image, ca: ControlAdapterEntity): void => { +const updateControlAdapterImageAttrs = (stage: Konva.Stage, konvaImage: Konva.Image, ca: ControlAdapterEntity): void => { let needsCache = false; // TODO(psyche): `node.filters()` returns null if no filters; report upstream const filters = konvaImage.filters() ?? []; @@ -128,7 +128,7 @@ const updateCALayerImageAttrs = (stage: Konva.Stage, konvaImage: Konva.Image, ca * @param ca The control adapter layer state * @param getImageDTO A function to retrieve an image DTO from the server, used to update the image source */ -export const renderCALayer = ( +export const renderControlAdapter = ( stage: Konva.Stage, controlAdapterMap: EntityToKonvaMap, ca: ControlAdapterEntity, @@ -152,9 +152,9 @@ export const renderCALayer = ( } if (imageSourceNeedsUpdate) { - updateCALayerImageSource(stage, konvaLayer, ca, getImageDTO); + updateControlAdapterImageSource(stage, konvaLayer, ca, getImageDTO); } else if (konvaImage) { - updateCALayerImageAttrs(stage, konvaImage, ca); + updateControlAdapterImageAttrs(stage, konvaImage, ca); } }; @@ -171,6 +171,6 @@ export const renderControlAdapters = ( } } for (const ca of controlAdapters) { - renderCALayer(stage, controlAdapterMap, ca, getImageDTO); + renderControlAdapter(stage, controlAdapterMap, ca, getImageDTO); } }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/layers.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/layers.ts index d0b148da4d..29b2e96842 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/layers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/layers.ts @@ -1,23 +1,157 @@ -import { BACKGROUND_LAYER_ID, PREVIEW_LAYER_ID } from 'features/controlLayers/konva/naming'; -import type { ControlAdapterEntity, LayerEntity, RegionEntity } from 'features/controlLayers/store/types'; -import type Konva from 'konva'; +import type { EntityToKonvaMap, EntityToKonvaMapping } from 'features/controlLayers/konva/entityToKonvaMap'; +import { + RASTER_LAYER_BRUSH_LINE_NAME, + RASTER_LAYER_ERASER_LINE_NAME, + RASTER_LAYER_IMAGE_NAME, + RASTER_LAYER_NAME, + RASTER_LAYER_OBJECT_GROUP_NAME, + RASTER_LAYER_RECT_SHAPE_NAME, +} from 'features/controlLayers/konva/naming'; +import { + createImageObjectGroup, + createObjectGroup, + getBrushLine, + getEraserLine, + getRectShape, +} from 'features/controlLayers/konva/renderers/objects'; +import { mapId } from 'features/controlLayers/konva/util'; +import type { CanvasEntity, LayerEntity, PosChangedArg, Tool } from 'features/controlLayers/store/types'; +import Konva from 'konva'; -export const arrangeEntities = ( +/** + * Logic for creating and rendering raster layers. + */ + +/** + * Creates a raster layer. + * @param stage The konva stage + * @param layerState The raster layer state + * @param onPosChanged Callback for when the layer's position changes + */ +const getLayer = ( stage: Konva.Stage, - layers: LayerEntity[], - controlAdapters: ControlAdapterEntity[], - regions: RegionEntity[] -): void => { - let zIndex = 0; - stage.findOne(`#${BACKGROUND_LAYER_ID}`)?.zIndex(++zIndex); - for (const layer of layers) { - stage.findOne(`#${layer.id}`)?.zIndex(++zIndex); + layerMap: EntityToKonvaMap, + layerState: LayerEntity, + onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void +): EntityToKonvaMapping => { + let mapping = layerMap.getMapping(layerState.id); + if (mapping) { + return mapping; } - for (const ca of controlAdapters) { - stage.findOne(`#${ca.id}`)?.zIndex(++zIndex); + // This layer hasn't been added to the konva state yet + const konvaLayer = new Konva.Layer({ + id: layerState.id, + name: RASTER_LAYER_NAME, + draggable: true, + dragDistance: 0, + }); + + // When a drag on the layer finishes, update the layer's position in state. During the drag, konva handles changing + // the position - we do not need to call this on the `dragmove` event. + if (onPosChanged) { + konvaLayer.on('dragend', function (e) { + onPosChanged({ id: layerState.id, x: Math.floor(e.target.x()), y: Math.floor(e.target.y()) }, 'layer'); + }); + } + + const konvaObjectGroup = createObjectGroup(konvaLayer, RASTER_LAYER_OBJECT_GROUP_NAME); + konvaLayer.add(konvaObjectGroup); + stage.add(konvaLayer); + mapping = layerMap.addMapping(layerState.id, konvaLayer, konvaObjectGroup); + return mapping; +}; + +/** + * Renders a regional guidance layer. + * @param stage The konva stage + * @param layerState The regional guidance layer state + * @param tool The current tool + * @param onPosChanged Callback for when the layer's position changes + */ +export const renderLayer = async ( + stage: Konva.Stage, + layerMap: EntityToKonvaMap, + layerState: LayerEntity, + tool: Tool, + onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void +) => { + const mapping = getLayer(stage, layerMap, layerState, onPosChanged); + + // Update the layer's position and listening state + mapping.konvaLayer.setAttrs({ + listening: tool === 'move', // The layer only listens when using the move tool - otherwise the stage is handling mouse events + x: Math.floor(layerState.x), + y: Math.floor(layerState.y), + }); + + const objectIds = layerState.objects.map(mapId); + // Destroy any objects that are no longer in state + for (const entry of mapping.getEntries()) { + if (!objectIds.includes(entry.id)) { + mapping.destroyEntry(entry.id); + } + } + + for (const obj of layerState.objects) { + if (obj.type === 'brush_line') { + const entry = getBrushLine(mapping, obj, RASTER_LAYER_BRUSH_LINE_NAME); + // Only update the points if they have changed. + if (entry.konvaLine.points().length !== obj.points.length) { + entry.konvaLine.points(obj.points); + } + } else if (obj.type === 'eraser_line') { + const entry = getEraserLine(mapping, obj, RASTER_LAYER_ERASER_LINE_NAME); + // Only update the points if they have changed. + if (entry.konvaLine.points().length !== obj.points.length) { + entry.konvaLine.points(obj.points); + } + } else if (obj.type === 'rect_shape') { + getRectShape(mapping, obj, RASTER_LAYER_RECT_SHAPE_NAME); + } else if (obj.type === 'image') { + createImageObjectGroup(mapping, obj, RASTER_LAYER_IMAGE_NAME); + } + } + + // Only update layer visibility if it has changed. + if (mapping.konvaLayer.visible() !== layerState.isEnabled) { + mapping.konvaLayer.visible(layerState.isEnabled); + } + + // const bboxRect = konvaLayer.findOne(`.${LAYER_BBOX_NAME}`) ?? createBboxRect(layerState, konvaLayer); + + // if (layerState.bbox) { + // const active = !layerState.bboxNeedsUpdate && layerState.isSelected && tool === 'move'; + // bboxRect.setAttrs({ + // visible: active, + // listening: active, + // x: layerState.bbox.x, + // y: layerState.bbox.y, + // width: layerState.bbox.width, + // height: layerState.bbox.height, + // stroke: layerState.isSelected ? BBOX_SELECTED_STROKE : '', + // strokeWidth: 1 / stage.scaleX(), + // }); + // } else { + // bboxRect.visible(false); + // } + + mapping.konvaObjectGroup.opacity(layerState.opacity); +}; + +export const renderLayers = ( + stage: Konva.Stage, + layerMap: EntityToKonvaMap, + layers: LayerEntity[], + tool: Tool, + onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void +): void => { + // Destroy nonexistent layers + for (const mapping of layerMap.getMappings()) { + if (!layers.find((l) => l.id === mapping.id)) { + layerMap.destroyMapping(mapping.id); + } + } + for (const layer of layers) { + renderLayer(stage, layerMap, layer, tool, onPosChanged); } - for (const rg of regions) { - stage.findOne(`#${rg.id}`)?.zIndex(++zIndex); - } - stage.findOne(`#${PREVIEW_LAYER_ID}`)?.zIndex(++zIndex); }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/objects.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/objects.ts index 2c21aeb120..c96fbda9af 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/objects.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/objects.ts @@ -5,7 +5,7 @@ import type { EraserLineEntry, ImageEntry, RectShapeEntry, -} from 'features/controlLayers/konva/konvaMap'; +} from 'features/controlLayers/konva/entityToKonvaMap'; import { getLayerBboxId, getObjectGroupId, diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/previewLayer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/preview.ts similarity index 100% rename from invokeai/frontend/web/src/features/controlLayers/konva/renderers/previewLayer.ts rename to invokeai/frontend/web/src/features/controlLayers/konva/renderers/preview.ts diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/rasterLayer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/rasterLayer.ts deleted file mode 100644 index 13829d4dae..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/rasterLayer.ts +++ /dev/null @@ -1,157 +0,0 @@ -import type { EntityToKonvaMap, EntityToKonvaMapping } from 'features/controlLayers/konva/konvaMap'; -import { - RASTER_LAYER_BRUSH_LINE_NAME, - RASTER_LAYER_ERASER_LINE_NAME, - RASTER_LAYER_IMAGE_NAME, - RASTER_LAYER_NAME, - RASTER_LAYER_OBJECT_GROUP_NAME, - RASTER_LAYER_RECT_SHAPE_NAME, -} from 'features/controlLayers/konva/naming'; -import { - createImageObjectGroup, - createObjectGroup, - getBrushLine, - getEraserLine, - getRectShape, -} from 'features/controlLayers/konva/renderers/objects'; -import { mapId } from 'features/controlLayers/konva/util'; -import type { CanvasEntity, LayerEntity, PosChangedArg, Tool } from 'features/controlLayers/store/types'; -import Konva from 'konva'; - -/** - * Logic for creating and rendering raster layers. - */ - -/** - * Creates a raster layer. - * @param stage The konva stage - * @param layerState The raster layer state - * @param onPosChanged Callback for when the layer's position changes - */ -const getLayer = ( - stage: Konva.Stage, - layerMap: EntityToKonvaMap, - layerState: LayerEntity, - onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void -): EntityToKonvaMapping => { - let mapping = layerMap.getMapping(layerState.id); - if (mapping) { - return mapping; - } - // This layer hasn't been added to the konva state yet - const konvaLayer = new Konva.Layer({ - id: layerState.id, - name: RASTER_LAYER_NAME, - draggable: true, - dragDistance: 0, - }); - - // When a drag on the layer finishes, update the layer's position in state. During the drag, konva handles changing - // the position - we do not need to call this on the `dragmove` event. - if (onPosChanged) { - konvaLayer.on('dragend', function (e) { - onPosChanged({ id: layerState.id, x: Math.floor(e.target.x()), y: Math.floor(e.target.y()) }, 'layer'); - }); - } - - const konvaObjectGroup = createObjectGroup(konvaLayer, RASTER_LAYER_OBJECT_GROUP_NAME); - konvaLayer.add(konvaObjectGroup); - stage.add(konvaLayer); - mapping = layerMap.addMapping(layerState.id, konvaLayer, konvaObjectGroup); - return mapping; -}; - -/** - * Renders a regional guidance layer. - * @param stage The konva stage - * @param layerState The regional guidance layer state - * @param tool The current tool - * @param onPosChanged Callback for when the layer's position changes - */ -export const renderRasterLayer = async ( - stage: Konva.Stage, - layerMap: EntityToKonvaMap, - layerState: LayerEntity, - tool: Tool, - onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void -) => { - const mapping = getLayer(stage, layerMap, layerState, onPosChanged); - - // Update the layer's position and listening state - mapping.konvaLayer.setAttrs({ - listening: tool === 'move', // The layer only listens when using the move tool - otherwise the stage is handling mouse events - x: Math.floor(layerState.x), - y: Math.floor(layerState.y), - }); - - const objectIds = layerState.objects.map(mapId); - // Destroy any objects that are no longer in state - for (const entry of mapping.getEntries()) { - if (!objectIds.includes(entry.id)) { - mapping.destroyEntry(entry.id); - } - } - - for (const obj of layerState.objects) { - if (obj.type === 'brush_line') { - const entry = getBrushLine(mapping, obj, RASTER_LAYER_BRUSH_LINE_NAME); - // Only update the points if they have changed. - if (entry.konvaLine.points().length !== obj.points.length) { - entry.konvaLine.points(obj.points); - } - } else if (obj.type === 'eraser_line') { - const entry = getEraserLine(mapping, obj, RASTER_LAYER_ERASER_LINE_NAME); - // Only update the points if they have changed. - if (entry.konvaLine.points().length !== obj.points.length) { - entry.konvaLine.points(obj.points); - } - } else if (obj.type === 'rect_shape') { - getRectShape(mapping, obj, RASTER_LAYER_RECT_SHAPE_NAME); - } else if (obj.type === 'image') { - createImageObjectGroup(mapping, obj, RASTER_LAYER_IMAGE_NAME); - } - } - - // Only update layer visibility if it has changed. - if (mapping.konvaLayer.visible() !== layerState.isEnabled) { - mapping.konvaLayer.visible(layerState.isEnabled); - } - - // const bboxRect = konvaLayer.findOne(`.${LAYER_BBOX_NAME}`) ?? createBboxRect(layerState, konvaLayer); - - // if (layerState.bbox) { - // const active = !layerState.bboxNeedsUpdate && layerState.isSelected && tool === 'move'; - // bboxRect.setAttrs({ - // visible: active, - // listening: active, - // x: layerState.bbox.x, - // y: layerState.bbox.y, - // width: layerState.bbox.width, - // height: layerState.bbox.height, - // stroke: layerState.isSelected ? BBOX_SELECTED_STROKE : '', - // strokeWidth: 1 / stage.scaleX(), - // }); - // } else { - // bboxRect.visible(false); - // } - - mapping.konvaObjectGroup.opacity(layerState.opacity); -}; - -export const renderLayers = ( - stage: Konva.Stage, - layerMap: EntityToKonvaMap, - layers: LayerEntity[], - tool: Tool, - onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void -): void => { - // Destroy nonexistent layers - for (const mapping of layerMap.getMappings()) { - if (!layers.find((l) => l.id === mapping.id)) { - layerMap.destroyMapping(mapping.id); - } - } - for (const layer of layers) { - renderRasterLayer(stage, layerMap, layer, tool, onPosChanged); - } -}; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/rgLayer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/regions.ts similarity index 98% rename from invokeai/frontend/web/src/features/controlLayers/konva/renderers/rgLayer.ts rename to invokeai/frontend/web/src/features/controlLayers/konva/renderers/regions.ts index c25e0e6486..eaa46f42c9 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/rgLayer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/regions.ts @@ -1,5 +1,5 @@ import { rgbColorToString } from 'common/util/colorCodeTransformers'; -import type { EntityToKonvaMap, EntityToKonvaMapping } from 'features/controlLayers/konva/konvaMap'; +import type { EntityToKonvaMap, EntityToKonvaMapping } from 'features/controlLayers/konva/entityToKonvaMap'; import { COMPOSITING_RECT_NAME, RG_LAYER_BRUSH_LINE_NAME, @@ -90,7 +90,7 @@ const getRegion = ( * @param tool The current tool * @param onPosChanged Callback for when the layer's position changes */ -export const renderRGLayer = ( +export const renderRegion = ( stage: Konva.Stage, regionMap: EntityToKonvaMap, region: RegionEntity, @@ -255,6 +255,6 @@ export const renderRegions = ( } } for (const rg of regions) { - renderRGLayer(stage, regionMap, rg, maskOpacity, tool, selectedEntityIdentifier, onPosChanged); + renderRegion(stage, regionMap, rg, maskOpacity, tool, selectedEntityIdentifier, onPosChanged); } }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/renderer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/renderer.ts index 1fb844dcc6..7912f4cc51 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/renderers/renderer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/renderers/renderer.ts @@ -3,19 +3,19 @@ import type { Store } from '@reduxjs/toolkit'; import { logger } from 'app/logging/logger'; import { $isDebugging } from 'app/store/nanostores/isDebugging'; import type { RootState } from 'app/store/store'; +import { EntityToKonvaMap } from 'features/controlLayers/konva/entityToKonvaMap'; import { setStageEventHandlers } from 'features/controlLayers/konva/events'; -import { EntityToKonvaMap } from 'features/controlLayers/konva/konvaMap'; +import { arrangeEntities } from 'features/controlLayers/konva/renderers/arrange'; import { renderBackgroundLayer } from 'features/controlLayers/konva/renderers/background'; import { updateBboxes } from 'features/controlLayers/konva/renderers/bbox'; -import { renderControlAdapters } from 'features/controlLayers/konva/renderers/caLayer'; -import { arrangeEntities } from 'features/controlLayers/konva/renderers/layers'; +import { renderControlAdapters } from 'features/controlLayers/konva/renderers/controlAdapters'; +import { renderLayers } from 'features/controlLayers/konva/renderers/layers'; import { renderBboxPreview, renderDocumentBoundsOverlay, scaleToolPreview, -} from 'features/controlLayers/konva/renderers/previewLayer'; -import { renderLayers } from 'features/controlLayers/konva/renderers/rasterLayer'; -import { renderRegions } from 'features/controlLayers/konva/renderers/rgLayer'; +} from 'features/controlLayers/konva/renderers/preview'; +import { renderRegions } from 'features/controlLayers/konva/renderers/regions'; import { fitDocumentToStage } from 'features/controlLayers/konva/renderers/stage'; import { $stageAttrs, @@ -55,6 +55,7 @@ import type { IRect, Vector2d } from 'konva/lib/types'; import { debounce } from 'lodash-es'; import type { RgbaColor } from 'react-colorful'; import { getImageDTO } from 'services/api/endpoints/images'; + /** * Initializes the canvas renderer. It subscribes to the redux store and listens for changes directly, bypassing the * react rendering cycle entirely, improving canvas performance. diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addRegions.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addRegions.ts index 168c941033..9792ac1fa8 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addRegions.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addRegions.ts @@ -2,7 +2,7 @@ import { getStore } from 'app/store/nanostores/store'; import { deepClone } from 'common/util/deepClone'; import openBase64ImageInTab from 'common/util/openBase64ImageInTab'; import { RG_LAYER_NAME } from 'features/controlLayers/konva/naming'; -import { renderRegions } from 'features/controlLayers/konva/renderers/rgLayer'; +import { renderRegions } from 'features/controlLayers/konva/renderers/regions'; import { blobToDataURL } from 'features/controlLayers/konva/util'; import { rgMaskImageUploaded } from 'features/controlLayers/store/canvasV2Slice'; import type { Dimensions, IPAdapterEntity, RegionEntity } from 'features/controlLayers/store/types';