feat(ui): create new line when mouse held down, leaves canvas and comes back over

This commit is contained in:
psychedelicious
2024-04-24 12:02:06 +10:00
parent bd8a33e824
commit d4a30d08ef

View File

@ -15,6 +15,7 @@ import {
} from 'features/regionalPrompts/store/regionalPromptsSlice'; } from 'features/regionalPrompts/store/regionalPromptsSlice';
import type Konva from 'konva'; import type Konva from 'konva';
import type { KonvaEventObject } from 'konva/lib/Node'; import type { KonvaEventObject } from 'konva/lib/Node';
import type { Vector2d } from 'konva/lib/types';
import { useCallback, useRef } from 'react'; import { useCallback, useRef } from 'react';
const getIsFocused = (stage: Konva.Stage) => { const getIsFocused = (stage: Konva.Stage) => {
@ -23,21 +24,26 @@ const getIsFocused = (stage: Konva.Stage) => {
export const getScaledFlooredCursorPosition = (stage: Konva.Stage) => { export const getScaledFlooredCursorPosition = (stage: Konva.Stage) => {
const pointerPosition = stage.getPointerPosition(); const pointerPosition = stage.getPointerPosition();
const stageTransform = stage.getAbsoluteTransform().copy(); const stageTransform = stage.getAbsoluteTransform().copy();
if (!pointerPosition || !stageTransform) { if (!pointerPosition || !stageTransform) {
return; return;
} }
const scaledCursorPosition = stageTransform.invert().point(pointerPosition); const scaledCursorPosition = stageTransform.invert().point(pointerPosition);
return { return {
x: Math.floor(scaledCursorPosition.x), x: Math.floor(scaledCursorPosition.x),
y: Math.floor(scaledCursorPosition.y), y: Math.floor(scaledCursorPosition.y),
}; };
}; };
const syncCursorPos = (stage: Konva.Stage): Vector2d | null => {
const pos = getScaledFlooredCursorPosition(stage);
if (!pos) {
return null;
}
$cursorPosition.set(pos);
return pos;
};
export const useMouseEvents = () => { export const useMouseEvents = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selectedLayerId = useAppSelector((s) => s.regionalPrompts.present.selectedLayerId); const selectedLayerId = useAppSelector((s) => s.regionalPrompts.present.selectedLayerId);
@ -52,7 +58,7 @@ export const useMouseEvents = () => {
if (!stage) { if (!stage) {
return; return;
} }
const pos = $cursorPosition.get(); const pos = syncCursorPos(stage);
if (!pos) { if (!pos) {
return; return;
} }
@ -66,7 +72,7 @@ export const useMouseEvents = () => {
dispatch( dispatch(
maskLayerLineAdded({ maskLayerLineAdded({
layerId: selectedLayerId, layerId: selectedLayerId,
points: [Math.floor(pos.x), Math.floor(pos.y), Math.floor(pos.x), Math.floor(pos.y)], points: [pos.x, pos.y, pos.x, pos.y],
tool, tool,
}) })
); );
@ -109,33 +115,46 @@ export const useMouseEvents = () => {
if (!stage) { if (!stage) {
return; return;
} }
const pos = getScaledFlooredCursorPosition(stage); const pos = syncCursorPos(stage);
if (!pos || !selectedLayerId) { if (!pos || !selectedLayerId) {
return; return;
} }
$cursorPosition.set(pos);
if (getIsFocused(stage) && $isMouseOver.get() && $isMouseDown.get() && (tool === 'brush' || tool === 'eraser')) { if (getIsFocused(stage) && $isMouseOver.get() && $isMouseDown.get() && (tool === 'brush' || tool === 'eraser')) {
if (lastCursorPosRef.current) { if (lastCursorPosRef.current) {
if (Math.hypot(lastCursorPosRef.current[0] - pos.x, lastCursorPosRef.current[1] - pos.y) < 20) { if (Math.hypot(lastCursorPosRef.current[0] - pos.x, lastCursorPosRef.current[1] - pos.y) < 20) {
return; return;
} }
} }
lastCursorPosRef.current = [Math.floor(pos.x), Math.floor(pos.y)]; lastCursorPosRef.current = [pos.x, pos.y];
dispatch(maskLayerPointsAdded({ layerId: selectedLayerId, point: lastCursorPosRef.current })); dispatch(maskLayerPointsAdded({ layerId: selectedLayerId, point: lastCursorPosRef.current }));
} }
}, },
[dispatch, selectedLayerId, tool] [dispatch, selectedLayerId, tool]
); );
const onMouseLeave = useCallback((e: KonvaEventObject<MouseEvent | TouchEvent>) => { const onMouseLeave = useCallback(
const stage = e.target.getStage(); (e: KonvaEventObject<MouseEvent | TouchEvent>) => {
if (!stage) { const stage = e.target.getStage();
return; if (!stage) {
} return;
$isMouseOver.set(false); }
$isMouseDown.set(false); const pos = syncCursorPos(stage);
$cursorPosition.set(null); if (
}, []); pos &&
selectedLayerId &&
getIsFocused(stage) &&
$isMouseOver.get() &&
$isMouseDown.get() &&
(tool === 'brush' || tool === 'eraser')
) {
dispatch(maskLayerPointsAdded({ layerId: selectedLayerId, point: [pos.x, pos.y] }));
}
$isMouseOver.set(false);
$isMouseDown.set(false);
$cursorPosition.set(null);
},
[selectedLayerId, tool, dispatch]
);
const onMouseEnter = useCallback( const onMouseEnter = useCallback(
(e: KonvaEventObject<MouseEvent>) => { (e: KonvaEventObject<MouseEvent>) => {
@ -144,7 +163,7 @@ export const useMouseEvents = () => {
return; return;
} }
$isMouseOver.set(true); $isMouseOver.set(true);
const pos = $cursorPosition.get(); const pos = syncCursorPos(stage);
if (!pos) { if (!pos) {
return; return;
} }
@ -162,7 +181,7 @@ export const useMouseEvents = () => {
dispatch( dispatch(
maskLayerLineAdded({ maskLayerLineAdded({
layerId: selectedLayerId, layerId: selectedLayerId,
points: [Math.floor(pos.x), Math.floor(pos.y), Math.floor(pos.x), Math.floor(pos.y)], points: [pos.x, pos.y, pos.x, pos.y],
tool, tool,
}) })
); );