fix(ui): fix layer arrangement

This commit is contained in:
psychedelicious 2024-04-24 16:32:04 +10:00
parent af25d00964
commit af3e910ad3
2 changed files with 41 additions and 36 deletions

View File

@ -15,7 +15,7 @@ import {
layerTranslated,
selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
import { debouncedRenderers, renderers } from 'features/regionalPrompts/util/renderers';
import { debouncedRenderers, renderers as normalRenderers } from 'features/regionalPrompts/util/renderers';
import Konva from 'konva';
import type { IRect } from 'konva/lib/types';
import type { MutableRefObject } from 'react';
@ -52,20 +52,8 @@ const useStageRenderer = (
const lastMouseDownPos = useStore($lastMouseDownPos);
const isMouseOver = useStore($isMouseOver);
const selectedLayerIdColor = useAppSelector(selectSelectedLayerColor);
const renderLayers = useMemo(
() => (asPreview ? debouncedRenderers.renderLayers : renderers.renderLayers),
[asPreview]
);
const renderToolPreview = useMemo(
() => (asPreview ? debouncedRenderers.renderToolPreview : renderers.renderToolPreview),
[asPreview]
);
const renderBbox = useMemo(() => (asPreview ? debouncedRenderers.renderBbox : renderers.renderBbox), [asPreview]);
const renderBackground = useMemo(
() => (asPreview ? debouncedRenderers.renderBackground : renderers.renderBackground),
[asPreview]
);
const layerIds = useMemo(() => state.layers.map((l) => l.id), [state.layers]);
const renderers = useMemo(() => (asPreview ? debouncedRenderers : normalRenderers), [asPreview]);
const onLayerPosChanged = useCallback(
(layerId: string, x: number, y: number) => {
@ -152,11 +140,12 @@ const useStageRenderer = (
}, [stageRef, width, height, wrapper]);
useLayoutEffect(() => {
log.trace('Rendering brush preview');
log.trace('Rendering tool preview');
if (asPreview) {
// Preview should not display tool
return;
}
renderToolPreview(
renderers.renderToolPreview(
stageRef.current,
tool,
selectedLayerIdColor,
@ -176,29 +165,36 @@ const useStageRenderer = (
lastMouseDownPos,
isMouseOver,
state.brushSize,
renderToolPreview,
renderers,
]);
useLayoutEffect(() => {
log.trace('Rendering layers');
renderLayers(stageRef.current, state.layers, state.globalMaskLayerOpacity, tool, onLayerPosChanged);
}, [stageRef, state.layers, state.globalMaskLayerOpacity, tool, onLayerPosChanged, renderLayers]);
renderers.renderLayers(stageRef.current, state.layers, state.globalMaskLayerOpacity, tool, onLayerPosChanged);
}, [stageRef, state.layers, state.globalMaskLayerOpacity, tool, onLayerPosChanged, renderers]);
useLayoutEffect(() => {
log.trace('Rendering bbox');
if (asPreview) {
// Preview should not display bboxes
return;
}
renderBbox(stageRef.current, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown);
}, [stageRef, asPreview, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown, renderBbox]);
renderers.renderBbox(stageRef.current, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown);
}, [stageRef, asPreview, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown, renderers]);
useLayoutEffect(() => {
log.trace('Rendering background');
if (asPreview) {
// The preview should not have a background
return;
}
renderBackground(stageRef.current, width, height);
}, [stageRef, asPreview, width, height, renderBackground]);
renderers.renderBackground(stageRef.current, width, height);
}, [stageRef, asPreview, width, height, renderers]);
useLayoutEffect(() => {
log.trace('Arranging layers');
renderers.arrangeLayers(stageRef.current, layerIds);
}, [stageRef, layerIds, renderers]);
};
type Props = {

View File

@ -267,9 +267,6 @@ const createVectorMaskLayer = (
stage.add(konvaLayer);
// When a layer is added, it ends up on top of the brush preview - we need to move the preview back to the top.
stage.findOne<Konva.Layer>(`#${TOOL_PREVIEW_LAYER_ID}`)?.moveToTop();
return konvaLayer;
};
@ -326,7 +323,6 @@ const createVectorMaskRect = (reduxObject: VectorMaskRect, konvaGroup: Konva.Gro
const renderVectorMaskLayer = (
stage: Konva.Stage,
reduxLayer: VectorMaskLayer,
reduxLayerIndex: number,
globalMaskLayerOpacity: number,
tool: Tool,
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
@ -339,10 +335,6 @@ const renderVectorMaskLayer = (
listening: tool === 'move', // The layer only listens when using the move tool - otherwise the stage is handling mouse events
x: Math.floor(reduxLayer.x),
y: Math.floor(reduxLayer.y),
// We have a konva layer for each redux layer, plus a brush preview layer, which should always be on top. We can
// therefore use the index of the redux layer as the zIndex for konva layers. If more layers are added to the
// stage, this may no longer be work.
zIndex: reduxLayerIndex,
});
// Convert the color to a string, stripping the alpha - the object group will handle opacity.
@ -433,11 +425,9 @@ const renderLayers = (
}
}
for (let layerIndex = 0; layerIndex < reduxLayers.length; layerIndex++) {
const reduxLayer = reduxLayers[layerIndex];
assert(reduxLayer, `Layer at index ${layerIndex} is undefined`);
for (const reduxLayer of reduxLayers) {
if (isVectorMaskLayer(reduxLayer)) {
renderVectorMaskLayer(stage, reduxLayer, layerIndex, globalMaskLayerOpacity, tool, onLayerPosChanged);
renderVectorMaskLayer(stage, reduxLayer, globalMaskLayerOpacity, tool, onLayerPosChanged);
}
}
};
@ -593,11 +583,29 @@ const renderBackground = (stage: Konva.Stage, width: number, height: number) =>
background.fillPatternOffset(stagePos);
};
/**
* Arranges all layers in the z-axis by updating their z-indices.
* @param stage The konva stage
* @param layerIds An array of redux layer ids, in their z-index order
*/
export const arrangeLayers = (stage: Konva.Stage, layerIds: string[]): void => {
let nextZIndex = 0;
// Background is the first layer
stage.findOne<Konva.Layer>(`#${BACKGROUND_LAYER_ID}`)?.zIndex(nextZIndex++);
// Then arrange the redux layers in order
for (const layerId of layerIds) {
stage.findOne<Konva.Layer>(`#${layerId}`)?.zIndex(nextZIndex++);
}
// Finally, the tool preview layer is always on top
stage.findOne<Konva.Layer>(`#${TOOL_PREVIEW_LAYER_ID}`)?.zIndex(nextZIndex++);
};
export const renderers = {
renderToolPreview,
renderLayers,
renderBbox,
renderBackground,
arrangeLayers,
};
const DEBOUNCE_MS = 300;
@ -607,4 +615,5 @@ export const debouncedRenderers = {
renderLayers: debounce(renderLayers, DEBOUNCE_MS),
renderBbox: debounce(renderBbox, DEBOUNCE_MS),
renderBackground: debounce(renderBackground, DEBOUNCE_MS),
arrangeLayers: debounce(arrangeLayers, DEBOUNCE_MS),
};