feat(ui): render buffer separately from "real" objects

This commit is contained in:
psychedelicious 2024-08-20 10:18:16 +10:00
parent 7f05af4a68
commit 5720ed4d64
6 changed files with 130 additions and 83 deletions

View File

@ -23,7 +23,7 @@ export class CanvasBrushLineRenderer {
}; };
constructor(state: CanvasBrushLineState, parent: CanvasObjectRenderer) { constructor(state: CanvasBrushLineState, parent: CanvasObjectRenderer) {
const { id, strokeWidth, clip, color, points } = state; const { id, clip } = state;
this.id = id; this.id = id;
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
@ -42,14 +42,10 @@ export class CanvasBrushLineRenderer {
name: `${this.type}:line`, name: `${this.type}:line`,
listening: false, listening: false,
shadowForStrokeEnabled: false, shadowForStrokeEnabled: false,
strokeWidth,
tension: 0.3, tension: 0.3,
lineCap: 'round', lineCap: 'round',
lineJoin: 'round', lineJoin: 'round',
globalCompositeOperation: 'source-over', globalCompositeOperation: 'source-over',
stroke: rgbaColorToString(color),
// A line with only one point will not be rendered, so we duplicate the points to make it visible
points: points.length === 2 ? [...points, ...points] : points,
}), }),
}; };
this.konva.group.add(this.konva.line); this.konva.group.add(this.konva.line);
@ -59,12 +55,11 @@ export class CanvasBrushLineRenderer {
update(state: CanvasBrushLineState, force = false): boolean { update(state: CanvasBrushLineState, force = false): boolean {
if (force || this.state !== state) { if (force || this.state !== state) {
this.log.trace({ state }, 'Updating brush line'); this.log.trace({ state }, 'Updating brush line');
const { points, color, clip, strokeWidth } = state; const { points, color, strokeWidth } = state;
this.konva.line.setAttrs({ this.konva.line.setAttrs({
// A line with only one point will not be rendered, so we duplicate the points to make it visible // A line with only one point will not be rendered, so we duplicate the points to make it visible
points: points.length === 2 ? [...points, ...points] : points, points: points.length === 2 ? [...points, ...points] : points,
stroke: rgbaColorToString(color), stroke: rgbaColorToString(color),
clip,
strokeWidth, strokeWidth,
}); });
this.state = state; this.state = state;

View File

@ -1,10 +1,8 @@
import type { JSONObject } from 'common/types'; import type { JSONObject } from 'common/types';
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
import { deepClone } from 'common/util/deepClone'; import { deepClone } from 'common/util/deepClone';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer'; import type { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer';
import type { CanvasEraserLineState } from 'features/controlLayers/store/types'; import type { CanvasEraserLineState } from 'features/controlLayers/store/types';
import { RGBA_RED } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
@ -24,7 +22,7 @@ export class CanvasEraserLineRenderer {
}; };
constructor(state: CanvasEraserLineState, parent: CanvasObjectRenderer) { constructor(state: CanvasEraserLineState, parent: CanvasObjectRenderer) {
const { id, strokeWidth, clip, points } = state; const { id, clip } = state;
this.id = id; this.id = id;
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
@ -43,14 +41,10 @@ export class CanvasEraserLineRenderer {
name: `${this.type}:line`, name: `${this.type}:line`,
listening: false, listening: false,
shadowForStrokeEnabled: false, shadowForStrokeEnabled: false,
strokeWidth,
tension: 0.3, tension: 0.3,
lineCap: 'round', lineCap: 'round',
lineJoin: 'round', lineJoin: 'round',
globalCompositeOperation: 'destination-out', globalCompositeOperation: 'destination-out',
stroke: rgbaColorToString(RGBA_RED),
// A line with only one point will not be rendered, so we duplicate the points to make it visible
points: points.length === 2 ? [...points, ...points] : points,
}), }),
}; };
this.konva.group.add(this.konva.line); this.konva.group.add(this.konva.line);
@ -60,11 +54,10 @@ export class CanvasEraserLineRenderer {
update(state: CanvasEraserLineState, force = false): boolean { update(state: CanvasEraserLineState, force = false): boolean {
if (force || this.state !== state) { if (force || this.state !== state) {
this.log.trace({ state }, 'Updating eraser line'); this.log.trace({ state }, 'Updating eraser line');
const { points, clip, strokeWidth } = state; const { points, strokeWidth } = state;
this.konva.line.setAttrs({ this.konva.line.setAttrs({
// A line with only one point will not be rendered, so we duplicate the points to make it visible // A line with only one point will not be rendered, so we duplicate the points to make it visible
points: points.length === 2 ? [...points, ...points] : points, points: points.length === 2 ? [...points, ...points] : points,
clip,
strokeWidth, strokeWidth,
}); });
this.state = state; this.state = state;

View File

@ -1,6 +1,5 @@
import type { JSONObject } from 'common/types'; import type { JSONObject } from 'common/types';
import { rgbColorToString } from 'common/util/colorCodeTransformers'; import { rgbColorToString } from 'common/util/colorCodeTransformers';
import { deepClone } from 'common/util/deepClone';
import { CanvasBrushLineRenderer } from 'features/controlLayers/konva/CanvasBrushLine'; import { CanvasBrushLineRenderer } from 'features/controlLayers/konva/CanvasBrushLine';
import { CanvasEraserLineRenderer } from 'features/controlLayers/konva/CanvasEraserLine'; import { CanvasEraserLineRenderer } from 'features/controlLayers/konva/CanvasEraserLine';
import { CanvasImageRenderer } from 'features/controlLayers/konva/CanvasImage'; import { CanvasImageRenderer } from 'features/controlLayers/konva/CanvasImage';
@ -67,8 +66,14 @@ export class CanvasObjectRenderer {
* drawn in real-time, such as brush lines. The buffer object state only exists in this renderer and is not part of * drawn in real-time, such as brush lines. The buffer object state only exists in this renderer and is not part of
* the application state until it is committed. * the application state until it is committed.
*/ */
buffer: AnyObjectState | null = null; bufferState: AnyObjectState | null = null;
/**
* The object renderer for the buffer object state. It is created when the buffer object state is set and destroyed
* when the buffer object state is cleared. This is separate from the other object renderers to allow the buffer to
* be rendered separately.
*/
bufferRenderer: AnyObjectRenderer | null = null;
/** /**
* A map of object renderers, keyed by their ID. * A map of object renderers, keyed by their ID.
*/ */
@ -82,6 +87,10 @@ export class CanvasObjectRenderer {
* A Konva Group that holds all the object renderers. * A Konva Group that holds all the object renderers.
*/ */
objectGroup: Konva.Group; objectGroup: Konva.Group;
/**
* A Konva Group that holds the buffer object renderer.
*/
bufferGroup: Konva.Group;
/** /**
* The compositing rect is used to draw the inpaint mask as a single shape with a given opacity. * The compositing rect is used to draw the inpaint mask as a single shape with a given opacity.
* *
@ -113,10 +122,12 @@ export class CanvasObjectRenderer {
this.konva = { this.konva = {
objectGroup: new Konva.Group({ name: `${this.type}:object_group`, listening: false }), objectGroup: new Konva.Group({ name: `${this.type}:object_group`, listening: false }),
bufferGroup: new Konva.Group({ name: `${this.type}:buffer_group`, listening: false }),
compositing: null, compositing: null,
}; };
this.parent.konva.layer.add(this.konva.objectGroup); this.parent.konva.layer.add(this.konva.objectGroup);
this.parent.konva.layer.add(this.konva.bufferGroup);
if (this.parent.state.type === 'inpaint_mask' || this.parent.state.type === 'regional_guidance') { if (this.parent.state.type === 'inpaint_mask' || this.parent.state.type === 'regional_guidance') {
const rect = new Konva.Rect({ const rect = new Konva.Rect({
@ -148,7 +159,6 @@ export class CanvasObjectRenderer {
this.subscriptions.add( this.subscriptions.add(
this.manager.stateApi.$stageAttrs.listen(() => { this.manager.stateApi.$stageAttrs.listen(() => {
if (this.konva.compositing && this.parent.type === 'mask_adapter') { if (this.konva.compositing && this.parent.type === 'mask_adapter') {
this.updateCompositingRectFill(this.parent.state.fill);
this.updateCompositingRectSize(); this.updateCompositingRectSize();
} }
}) })
@ -166,7 +176,7 @@ export class CanvasObjectRenderer {
const objectIds = objectStates.map((objectState) => objectState.id); const objectIds = objectStates.map((objectState) => objectState.id);
for (const renderer of this.renderers.values()) { for (const renderer of this.renderers.values()) {
if (!objectIds.includes(renderer.id) && renderer.id !== this.buffer?.id) { if (!objectIds.includes(renderer.id)) {
this.renderers.delete(renderer.id); this.renderers.delete(renderer.id);
renderer.destroy(); renderer.destroy();
didRender = true; didRender = true;
@ -177,10 +187,6 @@ export class CanvasObjectRenderer {
didRender = (await this.renderObject(objectState)) || didRender; didRender = (await this.renderObject(objectState)) || didRender;
} }
if (this.buffer) {
didRender = (await this.renderObject(this.buffer)) || didRender;
}
this.syncCache(didRender); this.syncCache(didRender);
return didRender; return didRender;
@ -236,6 +242,7 @@ export class CanvasObjectRenderer {
this.konva.compositing.group.opacity(opacity); this.konva.compositing.group.opacity(opacity);
} else { } else {
this.konva.objectGroup.opacity(opacity); this.konva.objectGroup.opacity(opacity);
this.konva.bufferGroup.opacity(opacity);
} }
}; };
@ -253,10 +260,10 @@ export class CanvasObjectRenderer {
let renderer = this.renderers.get(objectState.id); let renderer = this.renderers.get(objectState.id);
const isFirstRender = renderer === undefined; const isFirstRender = !renderer;
if (objectState.type === 'brush_line') { if (objectState.type === 'brush_line') {
assert(renderer instanceof CanvasBrushLineRenderer || renderer === undefined); assert(renderer instanceof CanvasBrushLineRenderer || !renderer);
if (!renderer) { if (!renderer) {
renderer = new CanvasBrushLineRenderer(objectState, this); renderer = new CanvasBrushLineRenderer(objectState, this);
@ -266,7 +273,7 @@ export class CanvasObjectRenderer {
didRender = renderer.update(objectState, force || isFirstRender); didRender = renderer.update(objectState, force || isFirstRender);
} else if (objectState.type === 'eraser_line') { } else if (objectState.type === 'eraser_line') {
assert(renderer instanceof CanvasEraserLineRenderer || renderer === undefined); assert(renderer instanceof CanvasEraserLineRenderer || !renderer);
if (!renderer) { if (!renderer) {
renderer = new CanvasEraserLineRenderer(objectState, this); renderer = new CanvasEraserLineRenderer(objectState, this);
@ -276,7 +283,7 @@ export class CanvasObjectRenderer {
didRender = renderer.update(objectState, force || isFirstRender); didRender = renderer.update(objectState, force || isFirstRender);
} else if (objectState.type === 'rect') { } else if (objectState.type === 'rect') {
assert(renderer instanceof CanvasRectRenderer || renderer === undefined); assert(renderer instanceof CanvasRectRenderer || !renderer);
if (!renderer) { if (!renderer) {
renderer = new CanvasRectRenderer(objectState, this); renderer = new CanvasRectRenderer(objectState, this);
@ -286,7 +293,7 @@ export class CanvasObjectRenderer {
didRender = renderer.update(objectState, force || isFirstRender); didRender = renderer.update(objectState, force || isFirstRender);
} else if (objectState.type === 'image') { } else if (objectState.type === 'image') {
assert(renderer instanceof CanvasImageRenderer || renderer === undefined); assert(renderer instanceof CanvasImageRenderer || !renderer);
if (!renderer) { if (!renderer) {
renderer = new CanvasImageRenderer(objectState, this); renderer = new CanvasImageRenderer(objectState, this);
@ -296,6 +303,9 @@ export class CanvasObjectRenderer {
didRender = await renderer.update(objectState, force || isFirstRender); didRender = await renderer.update(objectState, force || isFirstRender);
} }
// We should always clear the buffer when rendering a "real" object
this.clearBuffer();
if (didRender && this.konva.objectGroup.isCached()) { if (didRender && this.konva.objectGroup.isCached()) {
this.konva.objectGroup.clearCache(); this.konva.objectGroup.clearCache();
} }
@ -303,12 +313,64 @@ export class CanvasObjectRenderer {
return didRender; return didRender;
}; };
/**
* Renders the buffer object. If the buffer renderer does not exist, it will be created and its Konva group added to the
* parent entity's buffer object group.
* @returns A promise that resolves to a boolean, indicating if the object was rendered.
*/
renderBufferObject = async (): Promise<boolean> => {
let didRender = false;
if (!this.bufferState) {
return false;
}
if (this.bufferState.type === 'brush_line') {
assert(this.bufferRenderer instanceof CanvasBrushLineRenderer || !this.bufferRenderer);
if (!this.bufferRenderer) {
this.bufferRenderer = new CanvasBrushLineRenderer(this.bufferState, this);
this.konva.bufferGroup.add(this.bufferRenderer.konva.group);
}
didRender = this.bufferRenderer.update(this.bufferState, true);
} else if (this.bufferState.type === 'eraser_line') {
assert(this.bufferRenderer instanceof CanvasEraserLineRenderer || !this.bufferRenderer);
if (!this.bufferRenderer) {
this.bufferRenderer = new CanvasEraserLineRenderer(this.bufferState, this);
this.konva.bufferGroup.add(this.bufferRenderer.konva.group);
}
didRender = this.bufferRenderer.update(this.bufferState, true);
} else if (this.bufferState.type === 'rect') {
assert(this.bufferRenderer instanceof CanvasRectRenderer || !this.bufferRenderer);
if (!this.bufferRenderer) {
this.bufferRenderer = new CanvasRectRenderer(this.bufferState, this);
this.konva.bufferGroup.add(this.bufferRenderer.konva.group);
}
didRender = this.bufferRenderer.update(this.bufferState, true);
} else if (this.bufferState.type === 'image') {
assert(this.bufferRenderer instanceof CanvasImageRenderer || !this.bufferRenderer);
if (!this.bufferRenderer) {
this.bufferRenderer = new CanvasImageRenderer(this.bufferState, this);
this.konva.bufferGroup.add(this.bufferRenderer.konva.group);
}
didRender = await this.bufferRenderer.update(this.bufferState, true);
}
return didRender;
};
/** /**
* Determines if the renderer has a buffer object to render. * Determines if the renderer has a buffer object to render.
* @returns Whether the renderer has a buffer object to render. * @returns Whether the renderer has a buffer object to render.
*/ */
hasBuffer = (): boolean => { hasBuffer = (): boolean => {
return this.buffer !== null; return this.bufferState !== null || this.bufferRenderer !== null;
}; };
/** /**
@ -319,33 +381,27 @@ export class CanvasObjectRenderer {
setBuffer = async (objectState: AnyObjectState): Promise<boolean> => { setBuffer = async (objectState: AnyObjectState): Promise<boolean> => {
this.log.trace('Setting buffer'); this.log.trace('Setting buffer');
this.buffer = objectState; this.bufferState = objectState;
return await this.renderObject(this.buffer, true); return await this.renderBufferObject();
}; };
/** /**
* Clears the buffer object state. * Clears the buffer object state.
*/ */
clearBuffer = () => { clearBuffer = () => {
this.log.trace('Clearing buffer'); if (this.bufferState || this.bufferRenderer) {
this.log.trace('Clearing buffer');
if (this.buffer) { this.bufferRenderer?.destroy();
const renderer = this.renderers.get(this.buffer.id); this.bufferRenderer = null;
if (renderer) { this.bufferState = null;
this.log.trace('Destroying buffer object renderer');
renderer.destroy();
this.renderers.delete(renderer.id);
}
} }
this.buffer = null;
}; };
/** /**
* Commits the current buffer object, pushing the buffer object state back to the application state. * Commits the current buffer object, pushing the buffer object state back to the application state.
*/ */
commitBuffer = () => { commitBuffer = () => {
if (!this.buffer) { if (!this.bufferState) {
this.log.trace('No buffer to commit'); this.log.trace('No buffer to commit');
return; return;
} }
@ -354,25 +410,23 @@ export class CanvasObjectRenderer {
// We need to give the objects a fresh ID else they will be considered the same object when they are re-rendered as // We need to give the objects a fresh ID else they will be considered the same object when they are re-rendered as
// a non-buffer object, and we won't trigger things like bbox calculation // a non-buffer object, and we won't trigger things like bbox calculation
this.buffer.id = getPrefixedId(this.buffer.type); this.bufferState.id = getPrefixedId(this.bufferState.type);
if (this.buffer.type === 'brush_line') { if (this.bufferState.type === 'brush_line') {
this.manager.stateApi.addBrushLine({ this.manager.stateApi.addBrushLine({
entityIdentifier: this.parent.getEntityIdentifier(), entityIdentifier: this.parent.getEntityIdentifier(),
brushLine: this.buffer, brushLine: this.bufferState,
}); });
} else if (this.buffer.type === 'eraser_line') { } else if (this.bufferState.type === 'eraser_line') {
this.manager.stateApi.addEraserLine({ this.manager.stateApi.addEraserLine({
entityIdentifier: this.parent.getEntityIdentifier(), entityIdentifier: this.parent.getEntityIdentifier(),
eraserLine: this.buffer, eraserLine: this.bufferState,
}); });
} else if (this.buffer.type === 'rect') { } else if (this.bufferState.type === 'rect') {
this.manager.stateApi.addRect({ entityIdentifier: this.parent.getEntityIdentifier(), rect: this.buffer }); this.manager.stateApi.addRect({ entityIdentifier: this.parent.getEntityIdentifier(), rect: this.bufferState });
} else { } else {
this.log.warn({ buffer: this.buffer }, 'Invalid buffer object type'); this.log.warn({ buffer: this.bufferState }, 'Invalid buffer object type');
} }
this.buffer = null;
}; };
hideObjects = (except: string[] = []) => { hideObjects = (except: string[] = []) => {
@ -416,7 +470,7 @@ export class CanvasObjectRenderer {
* @returns Whether the renderer has any objects to render. * @returns Whether the renderer has any objects to render.
*/ */
hasObjects = (): boolean => { hasObjects = (): boolean => {
return this.renderers.size > 0 || this.buffer !== null; return this.renderers.size > 0 || this.bufferState !== null || this.bufferRenderer !== null;
}; };
getRasterizedImageCache = (rect: Rect): ImageCache | null => { getRasterizedImageCache = (rect: Rect): ImageCache | null => {
@ -455,7 +509,8 @@ export class CanvasObjectRenderer {
imageDTO = await uploadImage(blob, `${this.id}_rasterized.png`, 'other', true); imageDTO = await uploadImage(blob, `${this.id}_rasterized.png`, 'other', true);
const imageObject = imageDTOToImageObject(imageDTO); const imageObject = imageDTOToImageObject(imageDTO);
if (replaceObjects) { if (replaceObjects) {
await this.renderObject(imageObject, true); this.bufferState = imageObject;
await this.renderBufferObject();
} }
this.manager.stateApi.rasterizeEntity({ this.manager.stateApi.rasterizeEntity({
entityIdentifier: this.parent.getEntityIdentifier(), entityIdentifier: this.parent.getEntityIdentifier(),
@ -500,7 +555,7 @@ export class CanvasObjectRenderer {
type: this.type, type: this.type,
parent: this.parent.id, parent: this.parent.id,
renderers: Array.from(this.renderers.values()).map((renderer) => renderer.repr()), renderers: Array.from(this.renderers.values()).map((renderer) => renderer.repr()),
buffer: deepClone(this.buffer), buffer: this.bufferRenderer?.repr(),
}; };
}; };

View File

@ -24,7 +24,7 @@ export class CanvasRectRenderer {
isFirstRender: boolean = false; isFirstRender: boolean = false;
constructor(state: CanvasRectState, parent: CanvasObjectRenderer) { constructor(state: CanvasRectState, parent: CanvasObjectRenderer) {
const { id, rect, color } = state; const { id } = state;
this.id = id; this.id = id;
this.parent = parent; this.parent = parent;
this.manager = parent.manager; this.manager = parent.manager;
@ -34,12 +34,7 @@ export class CanvasRectRenderer {
this.konva = { this.konva = {
group: new Konva.Group({ name: `${this.type}:group`, listening: false }), group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
rect: new Konva.Rect({ rect: new Konva.Rect({ name: `${this.type}:rect`, listening: false }),
name: `${this.type}:rect`,
...rect,
listening: false,
fill: rgbaColorToString(color),
}),
}; };
this.konva.group.add(this.konva.rect); this.konva.group.add(this.konva.rect);
this.state = state; this.state = state;
@ -52,7 +47,10 @@ export class CanvasRectRenderer {
this.log.trace({ state }, 'Updating rect'); this.log.trace({ state }, 'Updating rect');
const { rect, color } = state; const { rect, color } = state;
this.konva.rect.setAttrs({ this.konva.rect.setAttrs({
...rect, x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
fill: rgbaColorToString(color), fill: rgbaColorToString(color),
}); });
this.state = state; this.state = state;

View File

@ -5,6 +5,7 @@ import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskA
import { getEmptyRect, getPrefixedId } from 'features/controlLayers/konva/util'; import { getEmptyRect, getPrefixedId } from 'features/controlLayers/konva/util';
import type { Coordinate, Rect } from 'features/controlLayers/store/types'; import type { Coordinate, Rect } from 'features/controlLayers/store/types';
import Konva from 'konva'; import Konva from 'konva';
import type { GroupConfig } from 'konva/lib/Group';
import { debounce, get } from 'lodash-es'; import { debounce, get } from 'lodash-es';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
@ -543,6 +544,7 @@ export class CanvasTransformer {
rotation: 0, rotation: 0,
}; };
this.parent.renderer.konva.objectGroup.setAttrs(attrs); this.parent.renderer.konva.objectGroup.setAttrs(attrs);
this.parent.renderer.konva.bufferGroup.setAttrs(attrs);
this.konva.outlineRect.setAttrs(attrs); this.konva.outlineRect.setAttrs(attrs);
this.konva.proxyRect.setAttrs(attrs); this.konva.proxyRect.setAttrs(attrs);
}; };
@ -555,12 +557,14 @@ export class CanvasTransformer {
this.log.trace('Updating position'); this.log.trace('Updating position');
const position = get(arg, 'position', this.parent.state.position); const position = get(arg, 'position', this.parent.state.position);
this.parent.renderer.konva.objectGroup.setAttrs({ const groupAttrs: Partial<GroupConfig> = {
x: position.x + this.pixelRect.x, x: position.x + this.pixelRect.x,
y: position.y + this.pixelRect.y, y: position.y + this.pixelRect.y,
offsetX: this.pixelRect.x, offsetX: this.pixelRect.x,
offsetY: this.pixelRect.y, offsetY: this.pixelRect.y,
}); };
this.parent.renderer.konva.objectGroup.setAttrs(groupAttrs);
this.parent.renderer.konva.bufferGroup.setAttrs(groupAttrs);
this.update(position, this.pixelRect); this.update(position, this.pixelRect);
}; };
@ -609,12 +613,14 @@ export class CanvasTransformer {
this.syncInteractionState(); this.syncInteractionState();
this.update(this.parent.state.position, this.pixelRect); this.update(this.parent.state.position, this.pixelRect);
this.parent.renderer.konva.objectGroup.setAttrs({ const groupAttrs: Partial<GroupConfig> = {
x: this.parent.state.position.x + this.pixelRect.x, x: this.parent.state.position.x + this.pixelRect.x,
y: this.parent.state.position.y + this.pixelRect.y, y: this.parent.state.position.y + this.pixelRect.y,
offsetX: this.pixelRect.x, offsetX: this.pixelRect.x,
offsetY: this.pixelRect.y, offsetY: this.pixelRect.y,
}); };
this.parent.renderer.konva.objectGroup.setAttrs(groupAttrs);
this.parent.renderer.konva.bufferGroup.setAttrs(groupAttrs);
}; };
calculateRect = debounce(() => { calculateRect = debounce(() => {

View File

@ -217,7 +217,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width); const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);
if (e.evt.shiftKey && lastLinePoint) { if (e.evt.shiftKey && lastLinePoint) {
// Create a straight line from the last line point // Create a straight line from the last line point
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
@ -236,7 +236,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
clip: getClip(selectedEntity.state), clip: getClip(selectedEntity.state),
}); });
} else { } else {
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
await selectedEntity.adapter.renderer.setBuffer({ await selectedEntity.adapter.renderer.setBuffer({
@ -256,7 +256,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.eraser.width); const alignedPoint = alignCoordForTool(normalizedPoint, toolState.eraser.width);
if (e.evt.shiftKey && lastLinePoint) { if (e.evt.shiftKey && lastLinePoint) {
// Create a straight line from the last line point // Create a straight line from the last line point
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
await selectedEntity.adapter.renderer.setBuffer({ await selectedEntity.adapter.renderer.setBuffer({
@ -273,7 +273,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
clip: getClip(selectedEntity.state), clip: getClip(selectedEntity.state),
}); });
} else { } else {
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
await selectedEntity.adapter.renderer.setBuffer({ await selectedEntity.adapter.renderer.setBuffer({
@ -288,7 +288,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
} }
if (toolState.selected === 'rect') { if (toolState.selected === 'rect') {
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
await selectedEntity.adapter.renderer.setBuffer({ await selectedEntity.adapter.renderer.setBuffer({
@ -312,7 +312,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
const toolState = getToolState(); const toolState = getToolState();
if (toolState.selected === 'brush') { if (toolState.selected === 'brush') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer?.type === 'brush_line') { if (drawingBuffer?.type === 'brush_line') {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} else { } else {
@ -321,7 +321,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
} }
if (toolState.selected === 'eraser') { if (toolState.selected === 'eraser') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer?.type === 'eraser_line') { if (drawingBuffer?.type === 'eraser_line') {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} else { } else {
@ -330,7 +330,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
} }
if (toolState.selected === 'rect') { if (toolState.selected === 'rect') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer?.type === 'rect') { if (drawingBuffer?.type === 'rect') {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} else { } else {
@ -365,7 +365,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
getIsPrimaryMouseDown(e) getIsPrimaryMouseDown(e)
) { ) {
if (toolState.selected === 'brush') { if (toolState.selected === 'brush') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer) { if (drawingBuffer) {
if (drawingBuffer.type === 'brush_line') { if (drawingBuffer.type === 'brush_line') {
const lastPoint = getLastPointOfLine(drawingBuffer.points); const lastPoint = getLastPointOfLine(drawingBuffer.points);
@ -384,7 +384,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
selectedEntity.adapter.renderer.clearBuffer(); selectedEntity.adapter.renderer.clearBuffer();
} }
} else { } else {
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position); const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
@ -402,7 +402,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
} }
if (toolState.selected === 'eraser') { if (toolState.selected === 'eraser') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer) { if (drawingBuffer) {
if (drawingBuffer.type === 'eraser_line') { if (drawingBuffer.type === 'eraser_line') {
const lastPoint = getLastPointOfLine(drawingBuffer.points); const lastPoint = getLastPointOfLine(drawingBuffer.points);
@ -421,7 +421,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
selectedEntity.adapter.renderer.clearBuffer(); selectedEntity.adapter.renderer.clearBuffer();
} }
} else { } else {
if (selectedEntity.adapter.renderer.buffer) { if (selectedEntity.adapter.renderer.bufferState) {
selectedEntity.adapter.renderer.commitBuffer(); selectedEntity.adapter.renderer.commitBuffer();
} }
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position); const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
@ -438,7 +438,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
} }
if (toolState.selected === 'rect') { if (toolState.selected === 'rect') {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
if (drawingBuffer) { if (drawingBuffer) {
if (drawingBuffer.type === 'rect') { if (drawingBuffer.type === 'rect') {
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position); const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
@ -469,7 +469,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
!$spaceKey.get() && !$spaceKey.get() &&
getIsPrimaryMouseDown(e) getIsPrimaryMouseDown(e)
) { ) {
const drawingBuffer = selectedEntity.adapter.renderer.buffer; const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position); const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
if (toolState.selected === 'brush' && drawingBuffer?.type === 'brush_line') { if (toolState.selected === 'brush' && drawingBuffer?.type === 'brush_line') {
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width); const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);