Skip to content

Commit af7e3cd

Browse files
committed
minor fixes and refactoring. History now doesn't grow to insane sizes
1 parent 83ea7d2 commit af7e3cd

File tree

11 files changed

+121
-61
lines changed

11 files changed

+121
-61
lines changed

src/Annotator/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import combineReducers from "./reducers/combine-reducers.js"
1515
import generalReducer from "./reducers/general-reducer.js"
1616
import imageReducer from "./reducers/image-reducer.js"
1717
import videoReducer from "./reducers/video-reducer.js"
18+
import historyHandler from "./reducers/history-handler.js"
1819

1920
import makeImmutable from "seamless-immutable"
2021

@@ -61,9 +62,11 @@ export const Annotator = ({
6162
return 'Missing required prop "images" or "videoSrc"'
6263
const annotationType = images ? "image" : "video"
6364
const [state, dispatchToReducer] = useReducer(
64-
combineReducers(
65-
annotationType === "image" ? imageReducer : videoReducer,
66-
generalReducer
65+
historyHandler(
66+
combineReducers(
67+
annotationType === "image" ? imageReducer : videoReducer,
68+
generalReducer
69+
)
6770
),
6871
makeImmutable({
6972
annotationType,

src/Annotator/reducers/general-reducer.js

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { moveRegion } from "../../ImageCanvas/region-tools.js"
55
import { getIn, setIn, updateIn } from "seamless-immutable"
66
import moment from "moment"
77
import isEqual from "lodash/isEqual"
8-
import merge from "lodash/fp/merge"
98
import getActiveImage from "./get-active-image"
9+
import { saveToHistory } from "./history-handler.js"
1010

1111
const getRandomId = () =>
1212
Math.random()
@@ -24,12 +24,6 @@ const getRandomColor = () => {
2424
return `hsl(${h},${s}%,${l}%)`
2525
}
2626

27-
const typesToSaveWithHistory = {
28-
BEGIN_BOX_TRANSFORM: "Transform/Move Box",
29-
BEGIN_MOVE_POINT: "Move Point",
30-
DELETE_REGION: "Delete Region"
31-
}
32-
3327
export default (state: MainLayoutState, action: Action) => {
3428
// Throttle certain actions
3529
if (action.type === "MOUSE_MOVE") {
@@ -63,12 +57,10 @@ export default (state: MainLayoutState, action: Action) => {
6357
const [region, regionIndex] = getRegion(regionId)
6458
if (!region) return state
6559
if (obj !== null) {
66-
return updateIn(
67-
state,
68-
[...pathToActiveImage, "regions", regionIndex],
69-
merge,
70-
obj
71-
)
60+
return setIn(state, [...pathToActiveImage, "regions", regionIndex], {
61+
...region,
62+
...obj
63+
})
7264
} else {
7365
// delete region
7466
const regions = activeImage.regions
@@ -91,24 +83,6 @@ export default (state: MainLayoutState, action: Action) => {
9183
)
9284
}
9385

94-
const saveToHistory = (state: MainLayoutState, name: string) =>
95-
updateIn(state, ["history"], h =>
96-
[
97-
{
98-
time: moment().toDate(),
99-
state,
100-
name
101-
}
102-
].concat((h || []).slice(0, 9))
103-
)
104-
105-
if (Object.keys(typesToSaveWithHistory).includes(action.type)) {
106-
state = saveToHistory(
107-
state,
108-
typesToSaveWithHistory[action.type] || action.type
109-
)
110-
}
111-
11286
const closeEditors = (state: MainLayoutState) => {
11387
if (currentImageIndex === null) return state
11488
return setIn(
@@ -153,19 +127,13 @@ export default (state: MainLayoutState, action: Action) => {
153127
action.region
154128
)
155129
}
156-
case "RESTORE_HISTORY": {
157-
if (state.history.length > 0) {
158-
return state.history[0].state
159-
}
160-
return state
161-
}
162130
case "CHANGE_IMAGE": {
163131
if (!activeImage) return state
164132
const { delta } = action
165133
for (const key of Object.keys(delta)) {
166134
if (key === "cls") saveToHistory(state, "Change Image Class")
167135
if (key === "tags") saveToHistory(state, "Change Image Tags")
168-
state = setIn(state, [...pageToActiveImage, key], delta[key])
136+
state = setIn(state, [...pathToActiveImage, key], delta[key])
169137
}
170138
return state
171139
}
@@ -406,7 +374,7 @@ export default (state: MainLayoutState, action: Action) => {
406374
case "DRAW_POLYGON": {
407375
const [polygon, regionIndex] = getRegion(state.mode.regionId)
408376
if (!polygon) break
409-
state = setIn(
377+
return setIn(
410378
state,
411379
[...pathToActiveImage, "regions", regionIndex],
412380
{ ...polygon, points: polygon.points.concat([[x, y]]) }

src/Annotator/reducers/get-implied-video-regions.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export default (
2222
return (
2323
keyframes[keyframeTimes[keyframeTimes.length - 1]].regions || emptyArr
2424
)
25+
} else if (nextKeyframeTimeIndex === 0) {
26+
return emptyArr
2527
}
2628

2729
const t1 = keyframeTimes[nextKeyframeTimeIndex - 1]
@@ -78,7 +80,7 @@ export default (
7880
...prev,
7981
highlighted: false,
8082
editingLabels: false,
81-
points: prev.map((pp, i) => [
83+
points: prev.points.map((pp, i) => [
8284
pp[0] * w1 + next.points[i][0] * w2,
8385
pp[1] * w1 + next.points[i][1] * w2
8486
])
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// @flow
2+
3+
import type { MainLayoutState, Action } from "../../MainLayout/types"
4+
import { setIn, updateIn, asMutable, without } from "seamless-immutable"
5+
import moment from "moment"
6+
7+
const typesToSaveWithHistory = {
8+
BEGIN_BOX_TRANSFORM: "Transform/Move Box",
9+
BEGIN_MOVE_POINT: "Move Point",
10+
DELETE_REGION: "Delete Region"
11+
}
12+
13+
export const saveToHistory = (state: MainLayoutState, name: string) =>
14+
updateIn(state, ["history"], h =>
15+
[
16+
{
17+
time: moment().toDate(),
18+
state: without(state, "history"),
19+
name
20+
}
21+
].concat((h || []).slice(0, 9))
22+
)
23+
24+
export default reducer => {
25+
return (state: MainLayoutState, action: Action) => {
26+
const prevState = state
27+
const nextState = reducer(state, action)
28+
29+
if (action.type === "RESTORE_HISTORY") {
30+
if (state.history.length > 0) {
31+
return setIn(
32+
nextState.history[0].state,
33+
["history"],
34+
nextState.history.slice(1)
35+
)
36+
}
37+
} else {
38+
if (
39+
prevState !== nextState &&
40+
Object.keys(typesToSaveWithHistory).includes(action.type)
41+
) {
42+
return setIn(
43+
nextState,
44+
["history"],
45+
[
46+
{
47+
time: moment().toDate(),
48+
state: without(prevState, "history"),
49+
name: typesToSaveWithHistory[action.type] || action.type
50+
}
51+
]
52+
.concat(nextState.history || [])
53+
.slice(0, 9)
54+
)
55+
}
56+
}
57+
58+
return nextState
59+
}
60+
}

src/Annotator/reducers/video-reducer.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ import type {
66
} from "../../MainLayout/types"
77
import { setIn, without } from "seamless-immutable"
88
import getImpliedVideoRegions from "./get-implied-video-regions"
9+
import { saveToHistory } from "./history-handler.js"
910

1011
export default (state: MainLayoutVideoAnnotationState, action: Action) => {
11-
if (!action.type.includes("MOUSE_MOVE")) console.log(action.type, action)
12-
1312
const copyImpliedRegions = () => {
14-
return setIn(state, ["keyframes", state.currentVideoTime], {
15-
regions: getImpliedVideoRegions(state.keyframes, state.currentVideoTime)
16-
})
13+
return setIn(
14+
saveToHistory(state, "Add Keyframe"),
15+
["keyframes", state.currentVideoTime],
16+
{
17+
regions: getImpliedVideoRegions(state.keyframes, state.currentVideoTime)
18+
}
19+
)
1720
}
1821

1922
switch (action.type) {
@@ -55,6 +58,7 @@ export default (state: MainLayoutVideoAnnotationState, action: Action) => {
5558
case "SELECT_REGION":
5659
case "CHANGE_REGION":
5760
case "DELETE_REGION":
61+
case "OPEN_REGION_EDITOR":
5862
return copyImpliedRegions()
5963
case "MOUSE_DOWN": {
6064
switch (state.selectedTool) {

src/Header/index.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import QueuePlayNextIcon from "@material-ui/icons/QueuePlayNext"
1515
import HotkeysIcon from "@material-ui/icons/Keyboard"
1616
import styles from "./styles"
1717
import KeyframeTimeline from "../KeyframeTimeline"
18+
import classnames from "classnames"
1819

1920
const useStyles = makeStyles(styles)
2021

@@ -37,6 +38,7 @@ export const Header = ({
3738
onHeaderButtonClick,
3839
title,
3940
inFullScreen,
41+
videoMode,
4042
isAVideoFrame = false,
4143
nextVideoFrameHasRegions = false,
4244
videoDuration,
@@ -49,13 +51,18 @@ export const Header = ({
4951
const classes = useStyles()
5052
return (
5153
<div className={classes.header}>
52-
<div className={classes.fileInfo}>{title}</div>
53-
<KeyframeTimeline
54-
currentTime={currentVideoTime}
55-
duration={videoDuration}
56-
onChangeCurrentTime={onChangeCurrentTime}
57-
keyframes={keyframes}
58-
/>
54+
<div className={classnames(classes.fileInfo, videoMode && "videoMode")}>
55+
{title}
56+
</div>
57+
{videoMode && (
58+
<KeyframeTimeline
59+
key="keyframeTimeline"
60+
currentTime={currentVideoTime}
61+
duration={videoDuration}
62+
onChangeCurrentTime={onChangeCurrentTime}
63+
keyframes={keyframes}
64+
/>
65+
)}
5966
<div className={classes.headerActions}>
6067
<HeaderButtonContext.Provider value={{ onHeaderButtonClick }}>
6168
{multipleImages && (
@@ -69,10 +76,14 @@ export const Header = ({
6976
/>
7077
</>
7178
)}
72-
{!videoPlaying ? (
73-
<HeaderButton name="Play" Icon={PlayIcon} />
74-
) : (
75-
<HeaderButton name="Pause" Icon={PauseIcon} />
79+
{videoMode && (
80+
<>
81+
{!videoPlaying ? (
82+
<HeaderButton key="play" name="Play" Icon={PlayIcon} />
83+
) : (
84+
<HeaderButton key="pause" name="Pause" Icon={PauseIcon} />
85+
)}
86+
</>
7687
)}
7788
<HeaderButton name="Settings" Icon={SettingsIcon} />
7889
{/* <HeaderButton name="Help" Icon={HelpIcon} /> */}

src/Header/styles.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export default {
1111
},
1212
fileInfo: {
1313
alignItems: "center",
14+
flexGrow: 1,
15+
"&.videoMode": {
16+
flexMode: 0.1
17+
},
1418
display: "flex",
1519
fontWeight: "bold",
1620
color: grey[800],

src/HighlightBox/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ const useStyles = makeStyles({
1212
highlightBox: {
1313
zIndex: 2,
1414
transition: "opacity 500ms",
15+
"&.highlighted": {
16+
zIndex: 3
17+
},
1518
"&:not(.highlighted)": {
1619
opacity: 0
1720
},

src/HistorySidebarBox/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const HistorySidebarBox = ({
4949
secondary={moment(time).format("LT")}
5050
/>
5151
{i === 0 && (
52-
<ListItemSecondaryAction onClick={onRestoreHistory}>
52+
<ListItemSecondaryAction onClick={() => onRestoreHistory()}>
5353
<IconButton>
5454
<UndoIcon />
5555
</IconButton>

src/MainLayout/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export const MainLayout = ({ state, dispatch }: Props) => {
7979
<div className={classes.headerContainer}>
8080
<Header
8181
onHeaderButtonClick={action("HEADER_BUTTON_CLICKED", "buttonName")}
82+
videoMode={state.annotationType === "video"}
8283
inFullScreen={state.fullScreen}
8384
isAVideoFrame={isAVideoFrame}
8485
nextVideoFrameHasRegions={

0 commit comments

Comments
 (0)