diff --git a/src/components/RoiList.tsx b/src/components/RoiList.tsx index fcd0fe1..5676c2d 100644 --- a/src/components/RoiList.tsx +++ b/src/components/RoiList.tsx @@ -51,7 +51,7 @@ export interface RoiListProps { getReadOnly?: GetReadOnlyCallback; renderLabel?: RenderLabelCallback; getOverlayOpacity?: GetOverlayOpacity; - allowRotate?: boolean; + displayRotationHandle?: boolean; showGrid?: boolean; /** * Spacing (in device pixels) between vertical grid lines along the horizontal axis. @@ -83,7 +83,7 @@ export function RoiList(props: RoiListProps) { getReadOnly = () => false, getOverlayOpacity = () => 0, renderLabel = defaultRenderLabel, - allowRotate = false, + displayRotationHandle = false, showGrid = false, gridHorizontalLineCount = 2, gridVerticalLineCount = 2, @@ -122,7 +122,7 @@ export function RoiList(props: RoiListProps) { renderLabel={renderLabel as RenderLabelCallback} getReadOnly={getReadOnly as GetReadOnlyCallback} getOverlayOpacity={getOverlayOpacity as GetOverlayOpacity} - allowRotate={allowRotate} + displayRotationHandle={displayRotationHandle} isSelected={roi.id === selectedRoi} showGrid={showGrid} gridOptions={gridOptions} diff --git a/src/components/box/BoxSvg.tsx b/src/components/box/BoxSvg.tsx index 3c290b7..6e85867 100644 --- a/src/components/box/BoxSvg.tsx +++ b/src/components/box/BoxSvg.tsx @@ -4,7 +4,12 @@ import { useIsKeyDown } from '../../hooks/useIsKeyDown.js'; import { useLockContext } from '../../hooks/useLockContext.js'; import { usePanZoom } from '../../hooks/usePanZoom.js'; import { useRoiDispatch } from '../../hooks/useRoiDispatch.js'; -import type { GetStyleCallback, ReactRoiAction, RoiMode } from '../../index.js'; +import type { + GetStyleCallback, + ReactRoiAction, + RoiMode, + RoiState, +} from '../../index.js'; import { useRoiState } from '../../index.js'; import type { Roi } from '../../types/Roi.js'; import type { Box } from '../../utilities/box.js'; @@ -26,7 +31,7 @@ export interface BoxAnnotationProps { className?: string; isReadOnly: boolean; getStyle: GetStyleCallback; - allowRotate: boolean; + displayRotationHandle: boolean; showGrid: boolean; gridOptions: GetGridLinesOptions; } @@ -38,7 +43,7 @@ export function BoxSvg({ isReadOnly, getStyle, box, - allowRotate, + displayRotationHandle, showGrid, gridOptions, }: BoxAnnotationProps) { @@ -70,7 +75,7 @@ export function BoxSvg({ width: box.width, height: box.height, cursor: getCursor( - roiState.mode, + roiState, isReadOnly, isAltKeyDown, roiState.action, @@ -103,7 +108,7 @@ export function BoxSvg({ }); } else { roiDispatch({ - type: 'SELECT_BOX_AND_START_MOVE', + type: 'SELECT_BOX_AND_START_ACTION', payload: { id: roi.id, }, @@ -145,6 +150,7 @@ export function BoxSvg({ sizes={handlerSizes} handlerColor={styles.resizeHandlerColor} edge={edge} + disabled={isResizableMode(roiState.mode)} gridLineOpacity={styles.gridLineOpacity} /> ))} @@ -153,6 +159,7 @@ export function BoxSvg({ getAllCorners(box, roi.box.angle).map((corner) => ( )} @@ -170,17 +177,23 @@ export function BoxSvg({ } function getCursor( - mode: RoiMode, + state: RoiState, readOnly: boolean, isAltKeyDown: boolean, action: ReactRoiAction, lockPan: boolean, ): CSSProperties['cursor'] { + const { mode, selectedRoi } = state; + if (mode === 'rotate_selected' && selectedRoi) { + return 'ew-resize'; + } if (action !== 'idle') { if (action === 'drawing') { return 'crosshair'; } else if (action === 'moving') { return 'move'; + } else if (action === 'rotating') { + return 'ew-resize'; } else if (action === 'panning') { return 'grab'; } @@ -200,5 +213,15 @@ function getCursor( } } - return mode === 'draw' ? 'crosshair' : 'move'; + // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check + switch (mode) { + case 'draw': + return 'crosshair'; + default: + return 'move'; + } +} + +function isResizableMode(mode: RoiMode) { + return mode === 'select' || mode === 'hybrid'; } diff --git a/src/components/box/RoiBox.tsx b/src/components/box/RoiBox.tsx index 7075d7f..6758764 100644 --- a/src/components/box/RoiBox.tsx +++ b/src/components/box/RoiBox.tsx @@ -23,7 +23,7 @@ interface RoiBoxProps { getStyle: GetStyleCallback; getReadOnly: GetReadOnlyCallback; renderLabel: RenderLabelCallback; - allowRotate: boolean; + displayRotationHandle: boolean; getOverlayOpacity: GetOverlayOpacity; showGrid: boolean; gridOptions: GetGridLinesOptions; @@ -37,7 +37,7 @@ function RoiBoxInternal(props: RoiBoxProps): JSX.Element { isSelected, renderLabel, getOverlayOpacity, - allowRotate, + displayRotationHandle, showGrid, gridOptions, } = props; @@ -88,7 +88,7 @@ function RoiBoxInternal(props: RoiBoxProps): JSX.Element { box={box} isReadOnly={isReadOnly} getStyle={getStyle} - allowRotate={allowRotate} + displayRotationHandle={displayRotationHandle} showGrid={showGrid} gridOptions={gridOptions} /> diff --git a/src/components/box/RoiBoxCorner.tsx b/src/components/box/RoiBoxCorner.tsx index d4c0f84..ed42c57 100644 --- a/src/components/box/RoiBoxCorner.tsx +++ b/src/components/box/RoiBoxCorner.tsx @@ -11,22 +11,31 @@ import { getCursor } from './utils.js'; type PointerDownCallback = PointerEventHandler; +interface RoiBoxCornerProps { + corner: CornerData; + roiId: string; + sizes: HandlerSizeOptions; + handlerColor?: CSSProperties['color']; + disabled: boolean; +} + export function RoiBoxCorner({ corner, roiId, sizes, handlerColor, -}: { - corner: CornerData; - roiId: string; - sizes: HandlerSizeOptions; - handlerColor?: CSSProperties['color']; -}) { + disabled, +}: RoiBoxCornerProps) { const roiDispatch = useRoiDispatch(); const roiState = useRoiState(); const onPointerDown: PointerDownCallback = useCallback( (event) => { - if (event.altKey || event.button !== 0 || roiState.mode === 'draw') { + if ( + event.altKey || + event.button !== 0 || + roiState.mode === 'draw' || + disabled + ) { return; } event.stopPropagation(); @@ -39,7 +48,7 @@ export function RoiBoxCorner({ }, }); }, - [roiDispatch, corner, roiId, roiState], + [roiDispatch, corner, roiId, roiState, disabled], ); if (corner.xPosition === 'center' || corner.yPosition === 'center') { return ( @@ -48,6 +57,7 @@ export function RoiBoxCorner({ onPointerDown={onPointerDown} scaledSizes={sizes} handlerColor={handlerColor} + disabled={disabled} /> ); } @@ -56,6 +66,7 @@ export function RoiBoxCorner({ corner={corner} onPointerDown={onPointerDown} scaledSizes={sizes} + disabled={disabled} handlerColor={handlerColor} /> ); @@ -65,11 +76,13 @@ function SideHandler({ corner, onPointerDown, scaledSizes, + disabled, handlerColor = defaultHandlerColor, }: { corner: CornerData; onPointerDown: PointerDownCallback; scaledSizes: HandlerSizeOptions; + disabled: boolean; handlerColor: CSSProperties['color'] | undefined; }) { const roiState = useRoiState(); @@ -87,7 +100,7 @@ function SideHandler({ /> { - if (event.altKey || event.button !== 0 || roiState.mode === 'draw') { + if ( + event.altKey || + event.button !== 0 || + roiState.mode === 'draw' || + disabled + ) { return; } event.stopPropagation(); @@ -54,7 +61,7 @@ export function RoiBoxEdge(props: RoiBoxEdgeProps) { }, }); }, - [roiDispatch, edge, roiId, roiState], + [roiDispatch, edge, roiId, roiState, disabled], ); return ( @@ -68,7 +75,7 @@ export function RoiBoxEdge(props: RoiBoxEdgeProps) { diff --git a/src/components/box/utils.ts b/src/components/box/utils.ts index 02e1020..e0fd5c5 100644 --- a/src/components/box/utils.ts +++ b/src/components/box/utils.ts @@ -5,7 +5,11 @@ import type { RoiState } from '../../types/state.js'; export function getCursor( roiState: RoiState, cursor: CSSProperties['cursor'], + disabled: boolean, ): CSSProperties['cursor'] { + if (disabled) { + return undefined; + } if (roiState.mode === 'draw') { return 'crosshair'; } diff --git a/src/components/container/ContainerComponent.tsx b/src/components/container/ContainerComponent.tsx index 5e29905..3c0ca18 100644 --- a/src/components/container/ContainerComponent.tsx +++ b/src/components/container/ContainerComponent.tsx @@ -19,7 +19,7 @@ import { useIsKeyDown } from '../../hooks/useIsKeyDown.js'; import { usePanZoomTransform } from '../../hooks/usePanZoom.js'; import { useRoiContainerRef } from '../../hooks/useRoiContainerRef.js'; import { useRoiDispatch } from '../../hooks/useRoiDispatch.js'; -import type { Actions, ReactRoiAction, RoiMode } from '../../index.js'; +import type { Actions, ReactRoiAction, RoiState } from '../../index.js'; import { useActions, useRoiState } from '../../index.js'; import { assert, assertUnreachable } from '../../utilities/assert.js'; import { roiHasChanged } from '../../utilities/rois.js'; @@ -195,12 +195,7 @@ export function ContainerComponent( overflow: 'hidden', margin: 0, padding: 0, - cursor: getCursor( - roiState.mode, - isAltKeyDown, - roiState.action, - lockPan, - ), + cursor: getCursor(roiState, isAltKeyDown, roiState.action, lockPan), userSelect: 'none', WebkitUserSelect: 'none', touchAction: 'none', @@ -268,11 +263,15 @@ export function ContainerComponent( } function getCursor( - mode: RoiMode, + state: RoiState, altKey: boolean, action: ReactRoiAction, lockPan: boolean, ): CSSProperties['cursor'] { + const { mode, selectedRoi } = state; + if (mode === 'rotate_selected' && selectedRoi) { + return 'ew-resize'; + } if (action !== 'idle') { if (action === 'drawing') { return 'crosshair'; @@ -333,7 +332,10 @@ function callPointerMoveActionHooks( callbacks.onChange({ roi: newRoi ?? null, actions, - actionType: selectedRoi.action.type, + actionType: + selectedRoi.action.type === 'rotating_free' + ? 'rotating' + : selectedRoi.action.type, roisBeforeCommit: state.committedRois, }); } diff --git a/src/context/RoiProvider.tsx b/src/context/RoiProvider.tsx index 5f71e87..ce61c97 100644 --- a/src/context/RoiProvider.tsx +++ b/src/context/RoiProvider.tsx @@ -68,6 +68,12 @@ export interface RoiProviderInitialConfig { commitRoiBoxStrategy?: CommitBoxStrategy; rois?: Array>; selectedRoiId?: string; + /** + * When in select_rotate mode, this defines how much the mouse movement transnlates to a rotation angle. + * It is expressed in number of pixels for a full 360 degree rotation. + * @default 1200 + */ + rotationResolution?: number; } interface RoiProviderProps { @@ -115,6 +121,7 @@ function createInitialState( translation: [0, 0], }, zoomDomain: initialConfig.zoom, + rotationResolution: initialConfig.rotationResolution, }; } @@ -133,6 +140,7 @@ export function RoiProvider(props: RoiProviderProps) { selectedRoiId, resizeStrategy = 'contain', commitRoiBoxStrategy = 'round', + rotationResolution = 1200, } = initialConfig; const [state, dispatch] = useReducer(roiReducer, null, () => @@ -151,6 +159,7 @@ export function RoiProvider(props: RoiProviderProps) { resizeStrategy, commitRoiBoxStrategy, selectedRoiId, + rotationResolution, }), ); const stateRef = useRef(state); diff --git a/src/context/roiReducer.tsx b/src/context/roiReducer.tsx index b1cb7e6..eeda131 100644 --- a/src/context/roiReducer.tsx +++ b/src/context/roiReducer.tsx @@ -29,7 +29,10 @@ import { endAction } from './updaters/endAction.js'; import { updateInitialPanZoom } from './updaters/initialPanZoom.js'; import { pointerMove } from './updaters/pointerMove.js'; import { sanitizeRois } from './updaters/sanitizeRois.js'; -import { selectBoxAndStartAction } from './updaters/selectBoxAndStartAction.js'; +import { + prepareSelectedBoxForAction, + selectBoxAndStartAction, +} from './updaters/selectBoxAndStartAction.js'; import { startDraw } from './updaters/startDraw.js'; import { startPan } from './updaters/startPan.js'; import { resetZoomAction, zoomAction, zoomIntoROI } from './updaters/zoom.js'; @@ -57,6 +60,13 @@ export interface ReactRoiState { */ commitRoiBoxStrategy: CommitBoxStrategy; + /** + * When in select_rotate mode, this defines how much the mouse movement transnlates to a rotation angle. + * It is expressed in number of pixels for a full 360 degree rotation. + * @default 1200 + */ + rotationResolution: number; + /** * Identification of the selected object */ @@ -171,7 +181,7 @@ export interface CancelActionPayload { noUnselection: boolean; } -export interface SelectBoxAndStartMovePayload { +export interface SelectBoxAndStartActionPayload { id: string; } @@ -179,6 +189,11 @@ export interface SelectBoxAndStartRotatePayload { id: string; } +export interface SelectBoxAndStartRotateFreePayload { + id: string; + rotationResolution: number; +} + export type RoiReducerAction = | { type: 'SET_MODE'; payload: RoiMode } | { @@ -217,8 +232,8 @@ export type RoiReducerAction = | { type: 'CANCEL_ACTION'; payload: CancelActionPayload } | { type: 'START_PAN' } | { - type: 'SELECT_BOX_AND_START_MOVE'; - payload: SelectBoxAndStartMovePayload; + type: 'SELECT_BOX_AND_START_ACTION'; + payload: SelectBoxAndStartActionPayload; } | { type: 'SELECT_BOX_AND_START_ROTATE'; @@ -371,13 +386,30 @@ export function roiReducer( startPan(draft); break; } - case 'SELECT_BOX_AND_START_MOVE': { - selectBoxAndStartAction(draft, action.payload.id, 'moving'); + case 'SELECT_BOX_AND_START_ACTION': { + switch (draft.mode) { + case 'select': + case 'hybrid': { + selectBoxAndStartAction(draft, action.payload.id, { + type: 'moving', + }); + break; + } + case 'rotate_selected': { + prepareSelectedBoxForAction(draft, { type: 'rotating_free' }); + break; + } + case 'draw': + default: { + // The draw action does not select the box + break; + } + } break; } case 'SELECT_BOX_AND_START_ROTATE': { - selectBoxAndStartAction(draft, action.payload.id, 'rotating'); + selectBoxAndStartAction(draft, action.payload.id, { type: 'rotating' }); break; } diff --git a/src/context/updaters/pointerMove.ts b/src/context/updaters/pointerMove.ts index 97b7c4e..aaa9e2b 100644 --- a/src/context/updaters/pointerMove.ts +++ b/src/context/updaters/pointerMove.ts @@ -72,6 +72,18 @@ export function updateRoiBox( roi.box.angle = computeAngleFromMousePosition({ x, y }, roi.box); break; } + case 'rotating_free': { + const angleDelta = (movement.x / draft.rotationResolution) * 2 * Math.PI; + roi.box.angle += angleDelta; + if (roi.box.angle > Math.PI) { + roi.box.angle -= + 2 * Math.PI * Math.floor(roi.box.angle / (2 * Math.PI) + 1); + } else if (roi.box.angle < -Math.PI) { + roi.box.angle += + 2 * Math.PI * Math.floor(-roi.box.angle / (2 * Math.PI) + 1); + } + break; + } case 'resizing': { resize(draft, roi, movement); break; diff --git a/src/context/updaters/roi.ts b/src/context/updaters/roi.ts index 3543e53..2f777e0 100644 --- a/src/context/updaters/roi.ts +++ b/src/context/updaters/roi.ts @@ -91,6 +91,8 @@ const boundingStrategyMap: Record = { moving: 'move', // If rotating, use move since it does not change the overall size of the ROI rotating: 'move', + // eslint-disable-next-line camelcase + rotating_free: 'move', external: 'none', }; diff --git a/src/context/updaters/selectBoxAndStartAction.ts b/src/context/updaters/selectBoxAndStartAction.ts index 08dd04e..2a825fd 100644 --- a/src/context/updaters/selectBoxAndStartAction.ts +++ b/src/context/updaters/selectBoxAndStartAction.ts @@ -1,5 +1,10 @@ import type { Draft } from 'immer'; +import type { + MoveAction, + RotateAction, + RotateFreeAction, +} from '../../types/Roi.ts'; import { assert } from '../../utilities/assert.js'; import { changeBoxRotationCenter } from '../../utilities/box.js'; import type { ReactRoiState } from '../roiReducer.js'; @@ -7,21 +12,28 @@ import type { ReactRoiState } from '../roiReducer.js'; export function selectBoxAndStartAction( draft: Draft, id: string, - action: 'rotating' | 'moving', + action: RotateFreeAction | RotateAction | MoveAction, ) { if (draft.mode === 'draw') { draft.selectedRoi = undefined; return; } - const { rois } = draft; draft.selectedRoi = id; - const roi = rois.find((roi) => roi.id === id); + prepareSelectedBoxForAction(draft, action); +} + +export function prepareSelectedBoxForAction( + draft: Draft, + action: RotateFreeAction | RotateAction | MoveAction, +) { + if (!draft.selectedRoi) { + return; + } + const roi = draft.rois.find((roi) => roi.id === draft.selectedRoi); assert(roi, 'ROI not found'); - draft.action = action; + draft.action = action.type === 'rotating_free' ? 'rotating' : action.type; - roi.action = { - type: action, - }; + roi.action = action; roi.box = changeBoxRotationCenter(roi.box, { xRotationCenter: 'center', yRotationCenter: 'center', diff --git a/src/context/updaters/startDraw.ts b/src/context/updaters/startDraw.ts index 8479881..23567c6 100644 --- a/src/context/updaters/startDraw.ts +++ b/src/context/updaters/startDraw.ts @@ -8,6 +8,8 @@ import { import { createRoi } from '../../utilities/rois.js'; import type { ReactRoiState, StartDrawPayload } from '../roiReducer.js'; +import { prepareSelectedBoxForAction } from './selectBoxAndStartAction.ts'; + /** * The draw action is executed when the user starts interacting with the container */ @@ -60,6 +62,10 @@ export function startDraw(draft: ReactRoiState, payload: StartDrawPayload) { draft.action = 'drawing'; break; } + case 'rotate_selected': { + prepareSelectedBoxForAction(draft, { type: 'rotating_free' }); + break; + } case 'select': { if (!noUnselection) { draft.selectedRoi = undefined; @@ -68,7 +74,6 @@ export function startDraw(draft: ReactRoiState, payload: StartDrawPayload) { if (!lockPan) { draft.action = 'panning'; } - break; } default: diff --git a/src/types/Roi.ts b/src/types/Roi.ts index c3145be..65ebccc 100644 --- a/src/types/Roi.ts +++ b/src/types/Roi.ts @@ -32,11 +32,21 @@ export interface MoveAction { export interface RotateAction { /** - * Action of rotating an existing ROI + * Action of rotating an existing ROI, by using the ROI's rotation handle. + * The rotation is computed such that the line between the rotation center + * and the pointer is a line parallel to the rectangle's sides. */ type: 'rotating'; } +export interface RotateFreeAction { + /** + * Action of rotating the ROI by computing the angle only from the pointer's + * movement on the X axis. + */ + type: 'rotating_free'; +} + export interface IdleAction { /** * No action is being performed @@ -61,6 +71,7 @@ export type RoiAction = | DrawAction | MoveAction | RotateAction + | RotateFreeAction | ResizeAction | ExternalAction; diff --git a/src/types/utils.ts b/src/types/utils.ts index 5ea1af6..7c49485 100644 --- a/src/types/utils.ts +++ b/src/types/utils.ts @@ -16,6 +16,6 @@ export interface PanZoom { translation: [number, number]; } -export type RoiMode = 'select' | 'draw' | 'hybrid'; +export type RoiMode = 'select' | 'draw' | 'hybrid' | 'rotate_selected'; export type ResizeStrategy = 'cover' | 'contain' | 'center' | 'none'; diff --git a/src/utilities/box.ts b/src/utilities/box.ts index ac2204d..5b8eb3c 100644 --- a/src/utilities/box.ts +++ b/src/utilities/box.ts @@ -200,6 +200,7 @@ function commitRound(roi: CommittedBox, action: RoiAction): CommittedBox { return commitExact(roi); } } + case 'rotating_free': case 'rotating': { return commitExact(roi); } diff --git a/stories/edge-cases/init-box.stories.tsx b/stories/edge-cases/init-box.stories.tsx index 439edd4..a60186a 100644 --- a/stories/edge-cases/init-box.stories.tsx +++ b/stories/edge-cases/init-box.stories.tsx @@ -52,7 +52,7 @@ export function RoundInitialValues() { > }> - + diff --git a/stories/full-examples/crop.stories.tsx b/stories/full-examples/crop.stories.tsx index f46f807..d0cd6d2 100644 --- a/stories/full-examples/crop.stories.tsx +++ b/stories/full-examples/crop.stories.tsx @@ -43,7 +43,7 @@ export function CropImage() { target={} > 0.6} getStyle={(roi) => ({ diff --git a/stories/hooks/useActions/mode.stories.tsx b/stories/hooks/useActions/mode.stories.tsx index 831b5c6..6094f29 100644 --- a/stories/hooks/useActions/mode.stories.tsx +++ b/stories/hooks/useActions/mode.stories.tsx @@ -29,6 +29,7 @@ export function ChangeMode() { + ); } diff --git a/stories/hooks/useActions/rotation-mode.stories.tsx b/stories/hooks/useActions/rotation-mode.stories.tsx new file mode 100644 index 0000000..d44d7f4 --- /dev/null +++ b/stories/hooks/useActions/rotation-mode.stories.tsx @@ -0,0 +1,81 @@ +import type { Meta } from '@storybook/react-vite'; +import { useEffect } from 'react'; + +import { + RoiContainer, + RoiList, + RoiProvider, + TargetImage, + useActions, +} from '../../../src/index.ts'; +import { Layout } from '../../utils/Layout.tsx'; +import { getInitialRois } from '../../utils/initialRois.ts'; + +export default { + title: 'hooks/useActions', + decorators: [ + (Story) => ( + + + + ), + ], +} as Meta; + +export function RotationMode() { + const actions = useActions(); + useEffect(() => { + function onKeyDown(event: KeyboardEvent) { + if (event.key === 'Shift') { + actions.setMode('rotate_selected'); + } + } + function onKeyUp(event: KeyboardEvent) { + if (event.key === 'Shift') { + actions.setMode('hybrid'); + } + } + document.addEventListener('keyup', onKeyUp); + document.addEventListener('keydown', onKeyDown); + return () => { + document.removeEventListener('keyup', onKeyUp); + document.removeEventListener('keydown', onKeyDown); + }; + }, [actions]); + return ( + +

+ { + "Use shift to switch between select_rotation and hybrid modes. This allows to rotate an ROI without enabling the ROI's rotation handle." + } +

+ }> + { + if ( + roi.action.type === 'rotating_free' && + roiAdditionalState.isSelected + ) { + return { + rectAttributes: { + stroke: 'red', + fill: 'rgba(255,0,0,0.3)', + }, + }; + } + return { + rectAttributes: { + fill: 'rgba(0,0,0,0.3)', + }, + }; + }} + /> + +
+ ); +} diff --git a/stories/lifecycle/lifecycle.stories.tsx b/stories/lifecycle/lifecycle.stories.tsx index bfee682..e750056 100644 --- a/stories/lifecycle/lifecycle.stories.tsx +++ b/stories/lifecycle/lifecycle.stories.tsx @@ -97,7 +97,7 @@ export function ActionHooks() { fill: 'rgba(0, 0, 0, 0.7)', }, })} - allowRotate + displayRotationHandle renderLabel={(roi) => { if (roi.action.type === 'drawing') return null; if (!roi.data) return null; @@ -301,7 +301,7 @@ export function SyncRoisDuringUpdate() { > renderLabel={(roi) => roi.data?.side} - allowRotate + displayRotationHandle getStyle={(roi) => ({ rectAttributes: { fill: roi.data?.side === 'LEFT' ? 'lightyellow' : 'blue', diff --git a/stories/preferences/commit-strategy.stories.tsx b/stories/preferences/commit-strategy.stories.tsx index b608e7a..871ea58 100644 --- a/stories/preferences/commit-strategy.stories.tsx +++ b/stories/preferences/commit-strategy.stories.tsx @@ -15,7 +15,7 @@ export default { title: 'Preferences', args: { commitStrategy: 'exact', - allowRotate: false, + displayRotationHandle: false, }, argTypes: { commitStrategy: { @@ -27,10 +27,12 @@ export default { }, } as Meta; -export function CommitStrategy(props: { +interface StoryProps { commitStrategy: CommitBoxStrategy; - allowRotate: boolean; -}) { + displayRotationHandle: boolean; +} + +export function CommitStrategy(props: StoryProps) { const initialRois = getInitialRois(320, 320); return ( } > - + diff --git a/stories/roi-styles/custom_styles.stories.tsx b/stories/roi-styles/custom_styles.stories.tsx index 2e1f194..5738d26 100644 --- a/stories/roi-styles/custom_styles.stories.tsx +++ b/stories/roi-styles/custom_styles.stories.tsx @@ -19,7 +19,7 @@ export default { title: 'ROI custom styles', args: { showGrid: false, - allowRotate: false, + displayRotationHandle: false, gridHorizontalLineCount: 2, gridVerticalLineCount: 2, gridSpacingX: 0, @@ -41,7 +41,7 @@ const initialRois = getInitialRois(320, 320, { type StoryProps = Pick< RoiListProps, - | 'allowRotate' + | 'displayRotationHandle' | 'showGrid' | 'gridHorizontalLineCount' | 'gridVerticalLineCount' @@ -179,13 +179,13 @@ export function WithIndividualStyles(props: StoryProps) { ); } -export function CustomLabelRender({ allowRotate }: StoryProps) { +export function CustomLabelRender(props: StoryProps) { return ( }> - allowRotate={allowRotate} + {...props} renderLabel={(roi, { isSelected }) => { if (isSelected) { return null;