Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Minor image annotator fixes #1742

Merged
merged 4 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions ui/src/image_annotator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ describe('ImageAnnotator.tsx', () => {
expect(wave.args[name]).toMatchObject(items)
})

it('Does not draw a new rect if dimensions too small', async () => {
const { container, getByText } = render(<XImageAnnotator model={model} />)
await waitForLoad()
const canvasEl = container.querySelectorAll('canvas')[1]
fireEvent.click(getByText('Rectangle'))
fireEvent.mouseDown(canvasEl, { clientX: 110, clientY: 110, buttons: 1 })
fireEvent.click(canvasEl, { clientX: 115, clientY: 115 })

expect(wave.args[name]).toMatchObject(items)
})

it('Removes rect after clicking remove btn', async () => {
const { container, getByText } = render(<XImageAnnotator model={model} />)
await waitForLoad()
Expand Down Expand Up @@ -207,6 +218,30 @@ describe('ImageAnnotator.tsx', () => {
expect(wave.args[name]).toMatchObject([{ tag: 'person', shape: { rect: { x1: 20, x2: 110, y1: 20, y2: 110 } } }, polygon])
})

it('Moves rect correctly if click happened outside the canvas', async () => {
const { container } = render(<XImageAnnotator model={model} />)
await waitForLoad()
const canvasEl = container.querySelectorAll('canvas')[1]
fireEvent.click(canvasEl, { clientX: 50, clientY: 50 })
fireEvent.mouseDown(canvasEl, { clientX: 50, clientY: 50, buttons: 1 })
fireEvent.mouseMove(canvasEl, { clientX: 45, clientY: 50, buttons: 1 })
fireEvent.mouseLeave(canvasEl, { clientX: -10, clientY: 60, buttons: 1 })

expect(wave.args[name]).toMatchObject([{ tag: 'person', shape: { rect: { x1: 5, x2: 95, y1: 10, y2: 100 } } }, polygon])
})

it('Does not move rect if click happened outside the canvas but left mouse btn not pressed', async () => {
const { container } = render(<XImageAnnotator model={model} />)
await waitForLoad()
const canvasEl = container.querySelectorAll('canvas')[1]
fireEvent.click(canvasEl, { clientX: 50, clientY: 50 })
fireEvent.mouseDown(canvasEl, { clientX: 50, clientY: 50, buttons: 1 })
fireEvent.mouseMove(canvasEl, { clientX: 45, clientY: 50, buttons: 1 })
fireEvent.mouseLeave(canvasEl, { clientX: -10, clientY: 60 })

expect(wave.args[name]).toMatchObject(items)
})

it('Does not move rect if left mouse btn not pressed (dragging)', async () => {
const { container } = render(<XImageAnnotator model={model} />)
await waitForLoad()
Expand Down Expand Up @@ -542,6 +577,18 @@ describe('ImageAnnotator.tsx', () => {
expect(pushMock).toBeCalledTimes(1)
})

it('Calls sync after moving rect and finishing outside of canvas', async () => {
const { container } = render(<XImageAnnotator model={{ ...model, trigger: true }} />)
await waitForLoad()
const canvasEl = container.querySelectorAll('canvas')[1]
fireEvent.click(canvasEl, { clientX: 50, clientY: 50 })
fireEvent.mouseDown(canvasEl, { clientX: 50, clientY: 50, buttons: 1 })
fireEvent.mouseMove(canvasEl, { clientX: 60, clientY: 60, buttons: 1 })
fireEvent.click(canvasEl, { clientX: 60, clientY: 60 })

expect(pushMock).toBeCalledTimes(1)
})

it('Calls sync after resizing rect', async () => {
const { container } = render(<XImageAnnotator model={{ ...model, trigger: true }} />)
await waitForLoad()
Expand All @@ -560,12 +607,11 @@ describe('ImageAnnotator.tsx', () => {
const canvasEl = container.querySelectorAll('canvas')[1]
fireEvent.click(canvasEl, { clientX: 50, clientY: 50 })
await waitForLoad()
fireEvent.click(getByText('Remove selection').parentElement?.parentElement?.parentElement!)
fireEvent.click(getByText('Remove selection').parentElement!.parentElement!.parentElement!)

expect(pushMock).toBeCalledTimes(1)
})


it('Calls sync after removing polygon', async () => {
const { container, getByText } = render(<XImageAnnotator model={{ ...model, trigger: true }} />)
await waitForLoad()
Expand Down
12 changes: 12 additions & 0 deletions ui/src/image_annotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,17 @@ export const XImageAnnotator = ({ model }: { model: ImageAnnotator }) => {
redrawExistingShapes()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [redrawExistingShapes]),

onMouseLeave = (e: React.MouseEvent<HTMLCanvasElement>) => {
const canvas = canvasRef.current
if (!canvas || e.buttons !== 1) return

setWaveArgs(drawnShapes)

polygonRef.current?.resetDragging()
rectRef.current?.resetDragging()
redrawExistingShapes()
},
onMouseDown = (e: React.MouseEvent) => {
const canvas = canvasRef.current
if (!canvas) return
Expand Down Expand Up @@ -462,6 +473,7 @@ export const XImageAnnotator = ({ model }: { model: ImageAnnotator }) => {
className={css.canvas}
onMouseMove={onMouseMove}
onMouseDown={onMouseDown}
onMouseLeave={onMouseLeave}
onKeyDown={onKeyDown}
// Do not show context menu on right click.
onContextMenu={e => e.preventDefault()}
Expand Down
4 changes: 3 additions & 1 deletion ui/src/image_annotator_rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export class RectAnnotator {
onClick = (cursor_x: U, cursor_y: U, tag: S, start?: Position): DrawnShape | undefined => {
let newRect
if (!this.resizedCorner && start?.dragging) {
newRect = { shape: { rect: this.createRect(start.x, cursor_x, start.y, cursor_y) }, tag }
const rect = this.createRect(start.x, cursor_x, start.y, cursor_y)
if (!rect) return
newRect = { shape: { rect }, tag }
}

this.resetDragging()
Expand Down