Skip to content
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"react-use": "^13.27.0",
"react-use-measure": "^2.0.0",
"seamless-immutable": "^7.1.4",
"storybook": "^5.3.14",
"transformation-matrix-js": "^2.7.6",
"use-event-callback": "^0.1.0",
"use-key-hook": "^1.3.0"
Expand Down Expand Up @@ -58,10 +59,10 @@
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@storybook/addon-actions": "^5.1.11",
"@storybook/addon-links": "^5.1.11",
"@storybook/addons": "^5.1.11",
"@storybook/react": "^5.1.11",
"@storybook/addon-actions": "^5.3.14",
"@storybook/addon-links": "^5.3.14",
"@storybook/addons": "^5.3.14",
"@storybook/react": "^5.3.14",
"babel-loader": "^8.0.5",
"babel-preset-react-app": "^7.0.0",
"gh-pages": "^2.0.1",
Expand Down
35 changes: 24 additions & 11 deletions src/Annotator/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import React, { useReducer } from "react"
import React, { useReducer, useEffect } from "react"
import MainLayout from "../MainLayout"
import type {
ToolEnum,
Expand All @@ -16,8 +16,8 @@ import generalReducer from "./reducers/general-reducer.js"
import imageReducer from "./reducers/image-reducer.js"
import videoReducer from "./reducers/video-reducer.js"
import historyHandler from "./reducers/history-handler.js"
import useEventCallback from "use-event-callback"

import useEventCallback from "use-event-callback"
import makeImmutable, { without } from "seamless-immutable"

type Props = {
Expand Down Expand Up @@ -57,7 +57,9 @@ export const Annotator = ({
videoSrc,
videoTime = 0,
videoName,
onExit
onExit,
onNextImage,
onPrevImage
}: Props) => {
if (!images && !videoSrc)
return 'Missing required prop "images" or "videoSrc"'
Expand Down Expand Up @@ -102,19 +104,30 @@ export const Annotator = ({
)

const dispatch = useEventCallback((action: Action) => {
if (
action.type === "HEADER_BUTTON_CLICKED" &&
["Exit", "Done", "Save", "Complete"].includes(action.buttonName)
) {
onExit(without(state, "history"))
} else {
dispatchToReducer(action)
if (action.type === "HEADER_BUTTON_CLICKED") {
if (["Exit", "Done", "Save", "Complete"].includes(action.buttonName)) {
return onExit(without(state, "history"))
} else if (action.buttonName === "Next" && onNextImage) {
return onNextImage(without(state, "history"))
} else if (action.buttonName === "Prev" && onPrevImage) {
return onPrevImage(without(state, "history"))
}
}
dispatchToReducer(action)
})

useEffect(() => {
dispatchToReducer({ type: "SELECT_IMAGE", image: state.images.find(img => img.src === selectedImage) })
}, [selectedImage])

return (
<SettingsProvider>
<MainLayout state={state} dispatch={dispatch} />
<MainLayout
alwaysShowNextButton={Boolean(onNextImage)}
alwaysShowPrevButton={Boolean(onPrevImage)}
state={state}
dispatch={dispatch}
/>
</SettingsProvider>
)
}
Expand Down
42 changes: 41 additions & 1 deletion src/Annotator/index.story.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import React from "react"
import React, { useState } from "react"

import { storiesOf } from "@storybook/react"
import { action as actionAddon } from "@storybook/addon-actions"
Expand Down Expand Up @@ -467,3 +467,43 @@ storiesOf("Annotator", module)
/>
</div>
))
.add("Override Next/Prev Button Handling", () => {
const images = [
exampleImage,
"https://loremflickr.com/100/100/cars?lock=1",
"https://loremflickr.com/100/100/cars?lock=2"
]
const [selectedImageIndex, changeSelectedImageIndex] = useState(0)

return (
<Annotator
onExit={actionAddon("onExit")}
onNextImage={() => {
actionAddon("onNextImage")()
changeSelectedImageIndex((selectedImageIndex + 1)%3)
}}
onPrevImage={() => {
actionAddon("onPrevImage")()
changeSelectedImageIndex((selectedImageIndex - 1 + 3)%3)
}}
labelImages
selectedImage={images[selectedImageIndex]}
regionClsList={["Alpha", "Beta", "Charlie", "Delta"]}
imageClsList={["Alpha", "Beta", "Charlie", "Delta"]}
images={[
{
src: exampleImage,
name: "Seve's Desk",
},
{
src: images[1],
name: "Frame 0036"
},
{
src: images[2],
name: "Frame 0037"
}
]}
/>
)
})
9 changes: 7 additions & 2 deletions src/DemoSite/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export const examples = {
src:
"https://images.unsplash.com/photo-1496905583330-eb54c7e5915a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
name: "hot-dogs-1"
},
{
src:
"https://www.bianchi.com/wp-content/uploads/2019/07/YPB17I555K.jpg",
name: "bianchi-oltre-xr4"
}
]
}),
Expand Down Expand Up @@ -123,13 +128,13 @@ const Editor = ({ onOpenAnnotator, lastOutput }: any) => {
className="button"
variant="outlined"
disabled={Boolean(currentError)}
onClick={() =>
onClick={() => {
onOpenAnnotator(
selectedExample === "Custom"
? loadSavedInput()
: examples[selectedExample]
)
}
}}
>
Open Annotator
</Button>
Expand Down
10 changes: 7 additions & 3 deletions src/Header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ export const Header = ({
multipleImages,
videoPlaying,
onChangeCurrentTime,
keyframes
keyframes,
alwaysShowPrevButton,
alwaysShowNextButton
}: Props) => {
const classes = useStyles()
return (
Expand All @@ -65,9 +67,11 @@ export const Header = ({
)}
<div className={classes.headerActions}>
<HeaderButtonContext.Provider value={{ onHeaderButtonClick }}>
{multipleImages && (
{(multipleImages || alwaysShowPrevButton) && (
<HeaderButton name="Prev" Icon={BackIcon} />
)}
{(multipleImages || alwaysShowNextButton) && (
<>
<HeaderButton name="Prev" Icon={BackIcon} />
<HeaderButton name="Next" Icon={NextIcon} />
<HeaderButton
name="Clone"
Expand Down
13 changes: 8 additions & 5 deletions src/MainLayout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const useStyles = makeStyles(styles)

type Props = {
state: MainLayoutState,
dispatch: Action => any
dispatch: Action => any,
alwaysShowNextButton: boolean,
alwaysShowPrevButton: boolean
}

export const MainLayout = ({ state, dispatch }: Props) => {
export default ({ state, dispatch, alwaysShowNextButton = false, alwaysShowPrevButton = false }: Props) => {
const classes = useStyles()
const settings = useSettings()

Expand Down Expand Up @@ -80,6 +82,8 @@ export const MainLayout = ({ state, dispatch }: Props) => {
<Header
onHeaderButtonClick={action("HEADER_BUTTON_CLICKED", "buttonName")}
videoMode={state.annotationType === "video"}
alwaysShowNextButton={alwaysShowNextButton}
alwaysShowPrevButton={alwaysShowPrevButton}
inFullScreen={state.fullScreen}
isAVideoFrame={isAVideoFrame}
nextVideoFrameHasRegions={
Expand Down Expand Up @@ -206,6 +210,7 @@ export const MainLayout = ({ state, dispatch }: Props) => {
onRestoreHistory={action("RESTORE_HISTORY")}
onChangeVideoTime={action("CHANGE_VIDEO_TIME", "newTime")}
onDeleteKeyframe={action("DELETE_KEYFRAME", "time")}
onShortcutActionDispatched={dispatch}
/>
</div>
</div>
Expand All @@ -221,6 +226,4 @@ export const MainLayout = ({ state, dispatch }: Props) => {
</div>
</Fullscreen>
)
}

export default MainLayout
}
2 changes: 1 addition & 1 deletion src/MainLayout/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,5 @@ export type Action =
| {| type: "CLOSE_REGION_EDITOR", region: Region |}
| {| type: "DELETE_REGION", region: Region |}
| {| type: "HEADER_BUTTON_CLICKED", buttonName: string |}
| {| type: "SELECT_TOOL", selectedTool: string |}
| {| type: "SELECT_TOOL", selectedTool: ToolEnum |}
| {| type: "CANCEL" |}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add new actions here...

{| type: "GO_TO_NEXT_IMAGE" |}

{| type: "GO_TO_PREV_IMAGE" |}

9 changes: 9 additions & 0 deletions src/RegionLabel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ export const RegionLabel = ({

return (
<Paper
onKeyPress={e => {
e.stopPropagation()
}}
onKeyDown={e => {
e.stopPropagation()
}}
onKeyUp={e => {
e.stopPropagation()
}}
onClick={() => (!editing ? onOpen(region) : null)}
className={classnames(classes.regionInfo, {
highlighted: region.highlighted
Expand Down
42 changes: 42 additions & 0 deletions src/Shortcuts/ShortcutField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react"
import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles({
shortcutKeyFieldWrapper: {
paddingTop: 8,
display: "inline-flex",
width: '100%'
},
shortcutKeyText: {
lineHeight: 0
},
shortcutTextfield: {
width: "100%",
boxSizing: "border-box",
textAlign: 'center'
}
})

const ShortcutField = ({actionId, actionName, keyName, onChangeShortcut}) =>{
const classes = useStyles()

return(
<div
className={classes.shortcutKeyFieldWrapper}
>
<TextField
variant="outlined"
label={actionName}
className={classes.shortcutTextfield}
value={keyName}
onKeyPress={e => {
onChangeShortcut(actionId, e.key)
e.stopPropagation()
}}
/>
</div>
)
}

export default ShortcutField
Loading