mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): render buffer separately from "real" objects
This commit is contained in:
parent
b5aa308593
commit
da7b52d6ba
@ -23,7 +23,7 @@ export class CanvasBrushLineRenderer {
|
||||
};
|
||||
|
||||
constructor(state: CanvasBrushLineState, parent: CanvasObjectRenderer) {
|
||||
const { id, strokeWidth, clip, color, points } = state;
|
||||
const { id, clip } = state;
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
this.manager = parent.manager;
|
||||
@ -42,14 +42,10 @@ export class CanvasBrushLineRenderer {
|
||||
name: `${this.type}:line`,
|
||||
listening: false,
|
||||
shadowForStrokeEnabled: false,
|
||||
strokeWidth,
|
||||
tension: 0.3,
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round',
|
||||
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);
|
||||
@ -59,12 +55,11 @@ export class CanvasBrushLineRenderer {
|
||||
update(state: CanvasBrushLineState, force = false): boolean {
|
||||
if (force || this.state !== state) {
|
||||
this.log.trace({ state }, 'Updating brush line');
|
||||
const { points, color, clip, strokeWidth } = state;
|
||||
const { points, color, strokeWidth } = state;
|
||||
this.konva.line.setAttrs({
|
||||
// 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,
|
||||
stroke: rgbaColorToString(color),
|
||||
clip,
|
||||
strokeWidth,
|
||||
});
|
||||
this.state = state;
|
||||
|
@ -1,10 +1,8 @@
|
||||
import type { JSONObject } from 'common/types';
|
||||
import { rgbaColorToString } from 'common/util/colorCodeTransformers';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||
import type { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer';
|
||||
import type { CanvasEraserLineState } from 'features/controlLayers/store/types';
|
||||
import { RGBA_RED } from 'features/controlLayers/store/types';
|
||||
import Konva from 'konva';
|
||||
import type { Logger } from 'roarr';
|
||||
|
||||
@ -24,7 +22,7 @@ export class CanvasEraserLineRenderer {
|
||||
};
|
||||
|
||||
constructor(state: CanvasEraserLineState, parent: CanvasObjectRenderer) {
|
||||
const { id, strokeWidth, clip, points } = state;
|
||||
const { id, clip } = state;
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
this.manager = parent.manager;
|
||||
@ -43,14 +41,10 @@ export class CanvasEraserLineRenderer {
|
||||
name: `${this.type}:line`,
|
||||
listening: false,
|
||||
shadowForStrokeEnabled: false,
|
||||
strokeWidth,
|
||||
tension: 0.3,
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round',
|
||||
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);
|
||||
@ -60,11 +54,10 @@ export class CanvasEraserLineRenderer {
|
||||
update(state: CanvasEraserLineState, force = false): boolean {
|
||||
if (force || this.state !== state) {
|
||||
this.log.trace({ state }, 'Updating eraser line');
|
||||
const { points, clip, strokeWidth } = state;
|
||||
const { points, strokeWidth } = state;
|
||||
this.konva.line.setAttrs({
|
||||
// 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,
|
||||
clip,
|
||||
strokeWidth,
|
||||
});
|
||||
this.state = state;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import type { JSONObject } from 'common/types';
|
||||
import { rgbColorToString } from 'common/util/colorCodeTransformers';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { CanvasBrushLineRenderer } from 'features/controlLayers/konva/CanvasBrushLine';
|
||||
import { CanvasEraserLineRenderer } from 'features/controlLayers/konva/CanvasEraserLine';
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
@ -82,6 +87,10 @@ export class CanvasObjectRenderer {
|
||||
* A Konva Group that holds all the object renderers.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -113,10 +122,12 @@ export class CanvasObjectRenderer {
|
||||
|
||||
this.konva = {
|
||||
objectGroup: new Konva.Group({ name: `${this.type}:object_group`, listening: false }),
|
||||
bufferGroup: new Konva.Group({ name: `${this.type}:buffer_group`, listening: false }),
|
||||
compositing: null,
|
||||
};
|
||||
|
||||
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') {
|
||||
const rect = new Konva.Rect({
|
||||
@ -148,7 +159,6 @@ export class CanvasObjectRenderer {
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$stageAttrs.listen(() => {
|
||||
if (this.konva.compositing && this.parent.type === 'mask_adapter') {
|
||||
this.updateCompositingRectFill(this.parent.state.fill);
|
||||
this.updateCompositingRectSize();
|
||||
}
|
||||
})
|
||||
@ -166,7 +176,7 @@ export class CanvasObjectRenderer {
|
||||
const objectIds = objectStates.map((objectState) => objectState.id);
|
||||
|
||||
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);
|
||||
renderer.destroy();
|
||||
didRender = true;
|
||||
@ -177,10 +187,6 @@ export class CanvasObjectRenderer {
|
||||
didRender = (await this.renderObject(objectState)) || didRender;
|
||||
}
|
||||
|
||||
if (this.buffer) {
|
||||
didRender = (await this.renderObject(this.buffer)) || didRender;
|
||||
}
|
||||
|
||||
this.syncCache(didRender);
|
||||
|
||||
return didRender;
|
||||
@ -236,6 +242,7 @@ export class CanvasObjectRenderer {
|
||||
this.konva.compositing.group.opacity(opacity);
|
||||
} else {
|
||||
this.konva.objectGroup.opacity(opacity);
|
||||
this.konva.bufferGroup.opacity(opacity);
|
||||
}
|
||||
};
|
||||
|
||||
@ -253,10 +260,10 @@ export class CanvasObjectRenderer {
|
||||
|
||||
let renderer = this.renderers.get(objectState.id);
|
||||
|
||||
const isFirstRender = renderer === undefined;
|
||||
const isFirstRender = !renderer;
|
||||
|
||||
if (objectState.type === 'brush_line') {
|
||||
assert(renderer instanceof CanvasBrushLineRenderer || renderer === undefined);
|
||||
assert(renderer instanceof CanvasBrushLineRenderer || !renderer);
|
||||
|
||||
if (!renderer) {
|
||||
renderer = new CanvasBrushLineRenderer(objectState, this);
|
||||
@ -266,7 +273,7 @@ export class CanvasObjectRenderer {
|
||||
|
||||
didRender = renderer.update(objectState, force || isFirstRender);
|
||||
} else if (objectState.type === 'eraser_line') {
|
||||
assert(renderer instanceof CanvasEraserLineRenderer || renderer === undefined);
|
||||
assert(renderer instanceof CanvasEraserLineRenderer || !renderer);
|
||||
|
||||
if (!renderer) {
|
||||
renderer = new CanvasEraserLineRenderer(objectState, this);
|
||||
@ -276,7 +283,7 @@ export class CanvasObjectRenderer {
|
||||
|
||||
didRender = renderer.update(objectState, force || isFirstRender);
|
||||
} else if (objectState.type === 'rect') {
|
||||
assert(renderer instanceof CanvasRectRenderer || renderer === undefined);
|
||||
assert(renderer instanceof CanvasRectRenderer || !renderer);
|
||||
|
||||
if (!renderer) {
|
||||
renderer = new CanvasRectRenderer(objectState, this);
|
||||
@ -286,7 +293,7 @@ export class CanvasObjectRenderer {
|
||||
|
||||
didRender = renderer.update(objectState, force || isFirstRender);
|
||||
} else if (objectState.type === 'image') {
|
||||
assert(renderer instanceof CanvasImageRenderer || renderer === undefined);
|
||||
assert(renderer instanceof CanvasImageRenderer || !renderer);
|
||||
|
||||
if (!renderer) {
|
||||
renderer = new CanvasImageRenderer(objectState, this);
|
||||
@ -296,6 +303,9 @@ export class CanvasObjectRenderer {
|
||||
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()) {
|
||||
this.konva.objectGroup.clearCache();
|
||||
}
|
||||
@ -303,12 +313,64 @@ export class CanvasObjectRenderer {
|
||||
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.
|
||||
* @returns Whether the renderer has a buffer object to render.
|
||||
*/
|
||||
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> => {
|
||||
this.log.trace('Setting buffer');
|
||||
|
||||
this.buffer = objectState;
|
||||
return await this.renderObject(this.buffer, true);
|
||||
this.bufferState = objectState;
|
||||
return await this.renderBufferObject();
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the buffer object state.
|
||||
*/
|
||||
clearBuffer = () => {
|
||||
this.log.trace('Clearing buffer');
|
||||
|
||||
if (this.buffer) {
|
||||
const renderer = this.renderers.get(this.buffer.id);
|
||||
if (renderer) {
|
||||
this.log.trace('Destroying buffer object renderer');
|
||||
renderer.destroy();
|
||||
this.renderers.delete(renderer.id);
|
||||
}
|
||||
if (this.bufferState || this.bufferRenderer) {
|
||||
this.log.trace('Clearing buffer');
|
||||
this.bufferRenderer?.destroy();
|
||||
this.bufferRenderer = null;
|
||||
this.bufferState = null;
|
||||
}
|
||||
|
||||
this.buffer = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Commits the current buffer object, pushing the buffer object state back to the application state.
|
||||
*/
|
||||
commitBuffer = () => {
|
||||
if (!this.buffer) {
|
||||
if (!this.bufferState) {
|
||||
this.log.trace('No buffer to commit');
|
||||
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
|
||||
// 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({
|
||||
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({
|
||||
entityIdentifier: this.parent.getEntityIdentifier(),
|
||||
eraserLine: this.buffer,
|
||||
eraserLine: this.bufferState,
|
||||
});
|
||||
} else if (this.buffer.type === 'rect') {
|
||||
this.manager.stateApi.addRect({ entityIdentifier: this.parent.getEntityIdentifier(), rect: this.buffer });
|
||||
} else if (this.bufferState.type === 'rect') {
|
||||
this.manager.stateApi.addRect({ entityIdentifier: this.parent.getEntityIdentifier(), rect: this.bufferState });
|
||||
} 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[] = []) => {
|
||||
@ -416,7 +470,7 @@ export class CanvasObjectRenderer {
|
||||
* @returns Whether the renderer has any objects to render.
|
||||
*/
|
||||
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 => {
|
||||
@ -455,7 +509,8 @@ export class CanvasObjectRenderer {
|
||||
imageDTO = await uploadImage(blob, `${this.id}_rasterized.png`, 'other', true);
|
||||
const imageObject = imageDTOToImageObject(imageDTO);
|
||||
if (replaceObjects) {
|
||||
await this.renderObject(imageObject, true);
|
||||
this.bufferState = imageObject;
|
||||
await this.renderBufferObject();
|
||||
}
|
||||
this.manager.stateApi.rasterizeEntity({
|
||||
entityIdentifier: this.parent.getEntityIdentifier(),
|
||||
@ -500,7 +555,7 @@ export class CanvasObjectRenderer {
|
||||
type: this.type,
|
||||
parent: this.parent.id,
|
||||
renderers: Array.from(this.renderers.values()).map((renderer) => renderer.repr()),
|
||||
buffer: deepClone(this.buffer),
|
||||
buffer: this.bufferRenderer?.repr(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,7 @@ export class CanvasRectRenderer {
|
||||
isFirstRender: boolean = false;
|
||||
|
||||
constructor(state: CanvasRectState, parent: CanvasObjectRenderer) {
|
||||
const { id, rect, color } = state;
|
||||
const { id } = state;
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
this.manager = parent.manager;
|
||||
@ -34,12 +34,7 @@ export class CanvasRectRenderer {
|
||||
|
||||
this.konva = {
|
||||
group: new Konva.Group({ name: `${this.type}:group`, listening: false }),
|
||||
rect: new Konva.Rect({
|
||||
name: `${this.type}:rect`,
|
||||
...rect,
|
||||
listening: false,
|
||||
fill: rgbaColorToString(color),
|
||||
}),
|
||||
rect: new Konva.Rect({ name: `${this.type}:rect`, listening: false }),
|
||||
};
|
||||
this.konva.group.add(this.konva.rect);
|
||||
this.state = state;
|
||||
@ -52,7 +47,10 @@ export class CanvasRectRenderer {
|
||||
this.log.trace({ state }, 'Updating rect');
|
||||
const { rect, color } = state;
|
||||
this.konva.rect.setAttrs({
|
||||
...rect,
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
fill: rgbaColorToString(color),
|
||||
});
|
||||
this.state = state;
|
||||
|
@ -5,6 +5,7 @@ import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskA
|
||||
import { getEmptyRect, getPrefixedId } from 'features/controlLayers/konva/util';
|
||||
import type { Coordinate, Rect } from 'features/controlLayers/store/types';
|
||||
import Konva from 'konva';
|
||||
import type { GroupConfig } from 'konva/lib/Group';
|
||||
import { debounce, get } from 'lodash-es';
|
||||
import type { Logger } from 'roarr';
|
||||
|
||||
@ -543,6 +544,7 @@ export class CanvasTransformer {
|
||||
rotation: 0,
|
||||
};
|
||||
this.parent.renderer.konva.objectGroup.setAttrs(attrs);
|
||||
this.parent.renderer.konva.bufferGroup.setAttrs(attrs);
|
||||
this.konva.outlineRect.setAttrs(attrs);
|
||||
this.konva.proxyRect.setAttrs(attrs);
|
||||
};
|
||||
@ -555,12 +557,14 @@ export class CanvasTransformer {
|
||||
this.log.trace('Updating 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,
|
||||
y: position.y + this.pixelRect.y,
|
||||
offsetX: this.pixelRect.x,
|
||||
offsetY: this.pixelRect.y,
|
||||
});
|
||||
};
|
||||
this.parent.renderer.konva.objectGroup.setAttrs(groupAttrs);
|
||||
this.parent.renderer.konva.bufferGroup.setAttrs(groupAttrs);
|
||||
|
||||
this.update(position, this.pixelRect);
|
||||
};
|
||||
@ -609,12 +613,14 @@ export class CanvasTransformer {
|
||||
|
||||
this.syncInteractionState();
|
||||
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,
|
||||
y: this.parent.state.position.y + this.pixelRect.y,
|
||||
offsetX: this.pixelRect.x,
|
||||
offsetY: this.pixelRect.y,
|
||||
});
|
||||
};
|
||||
this.parent.renderer.konva.objectGroup.setAttrs(groupAttrs);
|
||||
this.parent.renderer.konva.bufferGroup.setAttrs(groupAttrs);
|
||||
};
|
||||
|
||||
calculateRect = debounce(() => {
|
||||
|
@ -217,7 +217,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);
|
||||
if (e.evt.shiftKey && lastLinePoint) {
|
||||
// Create a straight line from the last line point
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
clip: getClip(selectedEntity.state),
|
||||
});
|
||||
} else {
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
await selectedEntity.adapter.renderer.setBuffer({
|
||||
@ -256,7 +256,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.eraser.width);
|
||||
if (e.evt.shiftKey && lastLinePoint) {
|
||||
// Create a straight line from the last line point
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
await selectedEntity.adapter.renderer.setBuffer({
|
||||
@ -273,7 +273,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
clip: getClip(selectedEntity.state),
|
||||
});
|
||||
} else {
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
await selectedEntity.adapter.renderer.setBuffer({
|
||||
@ -288,7 +288,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
await selectedEntity.adapter.renderer.setBuffer({
|
||||
@ -312,7 +312,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
const toolState = getToolState();
|
||||
|
||||
if (toolState.selected === 'brush') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'brush_line') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
} else {
|
||||
@ -321,7 +321,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
}
|
||||
|
||||
if (toolState.selected === 'eraser') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'eraser_line') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
} else {
|
||||
@ -330,7 +330,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'rect') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
} else {
|
||||
@ -365,7 +365,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
getIsPrimaryMouseDown(e)
|
||||
) {
|
||||
if (toolState.selected === 'brush') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'brush_line') {
|
||||
const lastPoint = getLastPointOfLine(drawingBuffer.points);
|
||||
@ -384,7 +384,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
selectedEntity.adapter.renderer.clearBuffer();
|
||||
}
|
||||
} else {
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
@ -402,7 +402,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
}
|
||||
|
||||
if (toolState.selected === 'eraser') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'eraser_line') {
|
||||
const lastPoint = getLastPointOfLine(drawingBuffer.points);
|
||||
@ -421,7 +421,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
selectedEntity.adapter.renderer.clearBuffer();
|
||||
}
|
||||
} else {
|
||||
if (selectedEntity.adapter.renderer.buffer) {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
@ -438,7 +438,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'rect') {
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
@ -469,7 +469,7 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => {
|
||||
!$spaceKey.get() &&
|
||||
getIsPrimaryMouseDown(e)
|
||||
) {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.buffer;
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
if (toolState.selected === 'brush' && drawingBuffer?.type === 'brush_line') {
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);
|
||||
|
Loading…
Reference in New Issue
Block a user