@searpent/react-image-annotate 2.0.75 → 2.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/.babelrc +6 -0
  2. package/.env +1 -0
  3. package/.flowconfig +2 -0
  4. package/.github/workflows/release-on-master.yml +32 -0
  5. package/.github/workflows/test.yml +16 -0
  6. package/.prettierrc +3 -0
  7. package/.releaserc.js +18 -0
  8. package/.storybook/addons.js +2 -0
  9. package/.storybook/config.js +16 -0
  10. package/LICENSE +21 -0
  11. package/package.json +1 -1
  12. package/public/favicon.ico +0 -0
  13. package/public/index.html +38 -0
  14. package/src/Annotator/bike-pic.png +0 -0
  15. package/src/Annotator/bike-pic2.png +0 -0
  16. package/src/Annotator/dab-keyframes.story.json +1 -0
  17. package/src/Annotator/exampleImages.js +48 -0
  18. package/src/Annotator/examplePhotos.js +7603 -0
  19. package/src/Annotator/index.js +380 -0
  20. package/src/Annotator/index.story.js +877 -0
  21. package/src/Annotator/poses.story.js +150 -0
  22. package/src/Annotator/reducers/combine-reducers.js +7 -0
  23. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +53 -0
  24. package/{Annotator → src/Annotator}/reducers/fix-twisted.js +5 -3
  25. package/src/Annotator/reducers/general-reducer.js +1228 -0
  26. package/src/Annotator/reducers/get-active-image.js +21 -0
  27. package/src/Annotator/reducers/get-implied-video-regions.js +115 -0
  28. package/src/Annotator/reducers/history-handler.js +60 -0
  29. package/src/Annotator/reducers/image-reducer.js +23 -0
  30. package/src/Annotator/reducers/video-reducer.js +85 -0
  31. package/src/Annotator/video.story.js +51 -0
  32. package/src/ClassSelectionMenu/index.js +112 -0
  33. package/src/Crosshairs/index.js +64 -0
  34. package/src/DebugSidebarBox/index.js +36 -0
  35. package/src/DemoSite/Editor.js +235 -0
  36. package/src/DemoSite/ErrorBoundaryDialog.js +34 -0
  37. package/src/DemoSite/index.js +41 -0
  38. package/src/DemoSite/index.story.js +10 -0
  39. package/src/DemoSite/simple-segmentation-example.json +572 -0
  40. package/src/Editor/annotation-plugin/annotation.js +536 -0
  41. package/src/Editor/index.js +50 -0
  42. package/src/Editor/readOnly.js +21 -0
  43. package/{Editor → src/Editor}/tools.js +3 -2
  44. package/src/Errorer/index.js +13 -0
  45. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  46. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  47. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  48. package/src/FullImageSegmentationAnnotator/index.js +7 -0
  49. package/src/FullImageSegmentationAnnotator/index.story.js +177 -0
  50. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  51. package/src/GroupSelectorSidebarBox/index.js +48 -0
  52. package/src/GroupsEditorSidebarBox/index.js +108 -0
  53. package/src/HelpSidebarBox/index.js +43 -0
  54. package/src/HighlightBox/index.js +143 -0
  55. package/src/HistorySidebarBox/index.js +78 -0
  56. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  57. package/src/ImageCanvas/index.js +515 -0
  58. package/src/ImageCanvas/index.story.js +314 -0
  59. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  60. package/src/ImageCanvas/region-tools.js +171 -0
  61. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  62. package/{ImageCanvas → src/ImageCanvas}/styles.js +8 -12
  63. package/src/ImageCanvas/use-mouse.js +168 -0
  64. package/src/ImageCanvas/use-project-box.js +23 -0
  65. package/src/ImageCanvas/use-wasd-mode.js +50 -0
  66. package/src/ImageMask/index.js +127 -0
  67. package/src/ImageMask/load-image.js +32 -0
  68. package/src/ImageSelectorSidebarBox/index.js +54 -0
  69. package/src/KeyframeTimeline/get-time-string.js +25 -0
  70. package/src/KeyframeTimeline/index.js +223 -0
  71. package/src/KeyframesSelectorSidebarBox/index.js +93 -0
  72. package/src/LandingPage/content.md +57 -0
  73. package/src/LandingPage/github-markdown.css +964 -0
  74. package/src/LandingPage/index.js +147 -0
  75. package/src/Locker/index.js +13 -0
  76. package/src/MainLayout/RightSidebarItemsWrapper.js +21 -0
  77. package/src/MainLayout/icon-dictionary.js +79 -0
  78. package/src/MainLayout/index.js +564 -0
  79. package/src/MainLayout/index.story.js +240 -0
  80. package/{MainLayout → src/MainLayout}/styles.js +7 -6
  81. package/src/MainLayout/types.js +171 -0
  82. package/src/MainLayout/use-implied-video-regions.js +17 -0
  83. package/src/MetadataEditorSidebarBox/index.js +160 -0
  84. package/src/PageSelector/index.js +159 -0
  85. package/src/PointDistances/index.js +90 -0
  86. package/src/PreventScrollToParents/index.js +48 -0
  87. package/src/PreventScrollToParents/index.story.js +23 -0
  88. package/src/RegionLabel/index.js +236 -0
  89. package/{RegionLabel → src/RegionLabel}/styles.js +15 -12
  90. package/src/RegionSelectAndTransformBoxes/index.js +236 -0
  91. package/src/RegionSelectorSidebarBox/index.js +220 -0
  92. package/{RegionSelectorSidebarBox → src/RegionSelectorSidebarBox}/styles.js +14 -13
  93. package/src/RegionShapes/index.js +254 -0
  94. package/src/RegionTags/index.js +136 -0
  95. package/src/SettingsDialog/index.js +58 -0
  96. package/src/SettingsProvider/index.js +57 -0
  97. package/src/Shortcuts/ShortcutField.js +44 -0
  98. package/src/Shortcuts/index.js +129 -0
  99. package/src/ShortcutsManager/index.js +162 -0
  100. package/src/Sidebar/index.js +117 -0
  101. package/src/SidebarBoxContainer/index.js +93 -0
  102. package/src/SmallToolButton/index.js +57 -0
  103. package/src/TagsSidebarBox/index.js +93 -0
  104. package/src/TaskDescriptionSidebarBox/index.js +43 -0
  105. package/src/Theme/index.js +36 -0
  106. package/src/VideoOrImageCanvasBackground/index.js +170 -0
  107. package/src/colors.js +32 -0
  108. package/src/hooks/use-colors.js +75 -0
  109. package/src/hooks/use-event-callback.js +11 -0
  110. package/src/hooks/use-exclude-pattern.js +27 -0
  111. package/src/hooks/use-load-image.js +21 -0
  112. package/src/hooks/use-window-size.js +46 -0
  113. package/{hooks → src/hooks}/xpattern.js +1 -1
  114. package/src/hooks/xpattern.png +0 -0
  115. package/src/index.js +18 -0
  116. package/src/lib.js +7 -0
  117. package/src/screenshot.png +0 -0
  118. package/src/site.css +5 -0
  119. package/src/stories.js +2 -0
  120. package/src/utils/blocks-to-article.js +61 -0
  121. package/{utils → src/utils}/blocks-to-article.test.js +8 -5
  122. package/{utils → src/utils}/default-locked-until.js +1 -2
  123. package/{utils → src/utils}/filter-only-unique.js +1 -1
  124. package/src/utils/get-from-local-storage.js +7 -0
  125. package/src/utils/get-hotkey-help-text.js +11 -0
  126. package/src/utils/get-landmarks-with-transform.js +23 -0
  127. package/src/utils/photosToImages.js +67 -0
  128. package/src/utils/regions-groups.js +19 -0
  129. package/src/utils/regions-to-blocks.js +16 -0
  130. package/src/utils/saveable-actions-enum.js +5 -0
  131. package/src/utils/set-in-local-storage.js +6 -0
  132. package/src/utils/sleep.js +3 -0
  133. package/src/utils/uuid-to-hash.js +5 -0
  134. package/Annotator/exampleImages.js +0 -41
  135. package/Annotator/examplePhotos.js +0 -6980
  136. package/Annotator/index.js +0 -417
  137. package/Annotator/reducers/combine-reducers.js +0 -14
  138. package/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -73
  139. package/Annotator/reducers/general-reducer.js +0 -1430
  140. package/Annotator/reducers/get-active-image.js +0 -27
  141. package/Annotator/reducers/get-implied-video-regions.js +0 -180
  142. package/Annotator/reducers/history-handler.js +0 -38
  143. package/Annotator/reducers/image-reducer.js +0 -20
  144. package/Annotator/reducers/video-reducer.js +0 -88
  145. package/ClassSelectionMenu/index.js +0 -140
  146. package/Crosshairs/index.js +0 -53
  147. package/DebugSidebarBox/index.js +0 -20
  148. package/DemoSite/Editor.js +0 -194
  149. package/DemoSite/ErrorBoundaryDialog.js +0 -64
  150. package/DemoSite/index.js +0 -40
  151. package/Editor/annotation-plugin/annotation.js +0 -647
  152. package/Editor/index.js +0 -93
  153. package/Editor/readOnly.js +0 -73
  154. package/Errorer/index.js +0 -11
  155. package/FullImageSegmentationAnnotator/index.js +0 -7
  156. package/GroupSelectorSidebarBox/index.js +0 -63
  157. package/GroupsEditorSidebarBox/index.js +0 -138
  158. package/HelpSidebarBox/index.js +0 -58
  159. package/HighlightBox/index.js +0 -102
  160. package/HistorySidebarBox/index.js +0 -71
  161. package/ImageCanvas/index.js +0 -441
  162. package/ImageCanvas/region-tools.js +0 -165
  163. package/ImageCanvas/use-mouse.js +0 -180
  164. package/ImageCanvas/use-project-box.js +0 -27
  165. package/ImageCanvas/use-wasd-mode.js +0 -62
  166. package/ImageMask/index.js +0 -133
  167. package/ImageMask/load-image.js +0 -25
  168. package/ImageSelectorSidebarBox/index.js +0 -60
  169. package/KeyframeTimeline/get-time-string.js +0 -27
  170. package/KeyframeTimeline/index.js +0 -233
  171. package/KeyframesSelectorSidebarBox/index.js +0 -93
  172. package/LandingPage/index.js +0 -159
  173. package/Locker/index.js +0 -11
  174. package/MainLayout/RightSidebarItemsWrapper.js +0 -19
  175. package/MainLayout/icon-dictionary.js +0 -104
  176. package/MainLayout/index.js +0 -526
  177. package/MainLayout/types.js +0 -0
  178. package/MainLayout/use-implied-video-regions.js +0 -13
  179. package/MetadataEditorSidebarBox/index.js +0 -231
  180. package/PageSelector/index.js +0 -180
  181. package/PointDistances/index.js +0 -73
  182. package/PreventScrollToParents/index.js +0 -51
  183. package/RegionLabel/index.js +0 -232
  184. package/RegionSelectAndTransformBoxes/index.js +0 -169
  185. package/RegionSelectorSidebarBox/index.js +0 -254
  186. package/RegionShapes/index.js +0 -294
  187. package/RegionTags/index.js +0 -144
  188. package/SettingsDialog/index.js +0 -52
  189. package/SettingsProvider/index.js +0 -60
  190. package/Shortcuts/ShortcutField.js +0 -46
  191. package/Shortcuts/index.js +0 -133
  192. package/ShortcutsManager/index.js +0 -155
  193. package/Sidebar/index.js +0 -69
  194. package/SidebarBoxContainer/index.js +0 -93
  195. package/SmallToolButton/index.js +0 -42
  196. package/TagsSidebarBox/index.js +0 -105
  197. package/TaskDescriptionSidebarBox/index.js +0 -58
  198. package/Theme/index.js +0 -30
  199. package/VideoOrImageCanvasBackground/index.js +0 -151
  200. package/colors.js +0 -14
  201. package/hooks/use-colors.js +0 -97
  202. package/hooks/use-event-callback.js +0 -10
  203. package/hooks/use-exclude-pattern.js +0 -24
  204. package/hooks/use-load-image.js +0 -26
  205. package/hooks/use-window-size.js +0 -46
  206. package/index.js +0 -3
  207. package/lib.js +0 -3
  208. package/stories.js +0 -5
  209. package/utils/blocks-to-article.js +0 -60
  210. package/utils/get-from-local-storage.js +0 -7
  211. package/utils/get-hotkey-help-text.js +0 -9
  212. package/utils/get-landmarks-with-transform.js +0 -40
  213. package/utils/photosToImages.js +0 -85
  214. package/utils/regions-groups.js +0 -28
  215. package/utils/regions-to-blocks.js +0 -18
  216. package/utils/saveable-actions-enum.js +0 -3
  217. package/utils/set-in-local-storage.js +0 -3
  218. package/utils/sleep.js +0 -7
  219. package/utils/uuid-to-hash.js +0 -5
  220. /package/{Editor → src/Editor}/annotation-plugin/annotation.css +0 -0
  221. /package/{Errorer → src/Errorer}/errorer.css +0 -0
  222. /package/{Locker → src/Locker}/locker.css +0 -0
  223. /package/{PageSelector → src/PageSelector}/page-selector.css +0 -0
  224. /package/{utils → src/utils}/next-group-id.js +0 -0
@@ -0,0 +1,564 @@
1
+ // @flow
2
+
3
+ import type { Action, MainLayoutState } from "./types"
4
+ import { FullScreen, useFullScreenHandle } from "react-full-screen"
5
+ import React, { useCallback, useMemo, useRef } from "react"
6
+ import { makeStyles } from "@mui/styles"
7
+ import { createTheme, ThemeProvider } from "@mui/material/styles"
8
+ import { styled } from "@mui/material/styles"
9
+ import ClassSelectionMenu from "../ClassSelectionMenu"
10
+ import DebugBox from "../DebugSidebarBox"
11
+ import HistorySidebarBox from "../HistorySidebarBox"
12
+ import ImageCanvas from "../ImageCanvas"
13
+ import ImageSelector from "../ImageSelectorSidebarBox"
14
+ import GroupSelector from "../GroupSelectorSidebarBox"
15
+ import KeyframeTimeline from "../KeyframeTimeline"
16
+ import KeyframesSelector from "../KeyframesSelectorSidebarBox"
17
+ import type { Node } from "react"
18
+ import RegionSelector from "../RegionSelectorSidebarBox"
19
+ import SettingsDialog from "../SettingsDialog"
20
+ import TagsSidebarBox from "../TagsSidebarBox"
21
+ import TaskDescription from "../TaskDescriptionSidebarBox"
22
+ import Help from "../HelpSidebarBox"
23
+ import MetadataEditor from "../MetadataEditorSidebarBox"
24
+ import GroupsEditor from "../GroupsEditorSidebarBox"
25
+ import Workspace from "react-material-workspace-layout/Workspace"
26
+ import classnames from "classnames"
27
+ import getActiveImage from "../Annotator/reducers/get-active-image"
28
+ import getHotkeyHelpText from "../utils/get-hotkey-help-text"
29
+ import iconDictionary from "./icon-dictionary"
30
+ import styles from "./styles"
31
+ import { useDispatchHotkeyHandlers } from "../ShortcutsManager"
32
+ import useEventCallback from "use-event-callback"
33
+ import useImpliedVideoRegions from "./use-implied-video-regions"
34
+ import useKey from "use-key-hook"
35
+ import { useSettings } from "../SettingsProvider"
36
+ import { withHotKeys } from "react-hotkeys"
37
+ import Editor from "../Editor"
38
+ import regionsToBlocks from '../utils/regions-to-blocks';
39
+ import PageSelector from "../PageSelector"
40
+ import regionsGroups from '../utils/regions-groups';
41
+ import RightSidebarItemsWrapper from './RightSidebarItemsWrapper';
42
+ import Locker from '../Locker';
43
+ import { reacalcActionsEnum } from "../utils/saveable-actions-enum";
44
+ import intersection from "lodash/intersection";
45
+ import useColors from '../hooks/use-colors';
46
+
47
+ // import Fullscreen from "../Fullscreen"
48
+
49
+ const emptyArr = []
50
+ const theme = createTheme()
51
+ const useStyles = makeStyles((theme) => styles)
52
+
53
+ const HotkeyDiv = withHotKeys(({ hotKeys, children, divRef, ...props }) => (
54
+ <div {...{ ...hotKeys, ...props }} ref={divRef}>
55
+ {children}
56
+ </div>
57
+ ))
58
+
59
+ const FullScreenContainer = styled("div")(({ theme }) => ({
60
+ width: "100%",
61
+ height: "100%",
62
+ "& .fullscreen": {
63
+ width: "100%",
64
+ height: "100%",
65
+ },
66
+ }))
67
+
68
+ const WorkspaceWrapper = styled("div")(({ theme }) => ({
69
+ height: "100vh",
70
+ width: "auto",
71
+ backgroundColor: "red",
72
+ flex: 1,
73
+ }))
74
+
75
+ const EditorWrapper = styled("div")(({ theme }) => ({
76
+ padding: "1rem",
77
+ paddingLeft: "2rem",
78
+ height: "100vh",
79
+ width: "30vw",
80
+ overflowY: "scroll"
81
+ }))
82
+
83
+ type Props = {
84
+ state: MainLayoutState,
85
+ RegionEditLabel?: Node,
86
+ dispatch: (Action) => any,
87
+ alwaysShowNextButton?: boolean,
88
+ alwaysShowPrevButton?: boolean,
89
+ onRegionClassAdded: () => {},
90
+ hideHeader?: boolean,
91
+ hideHeaderText?: boolean,
92
+ groups?: Array<any>,
93
+ onGroupSelect?: (any) => any,
94
+ hideHistory?: boolean,
95
+ hideNotEditingLabel?: boolean,
96
+ showEditor?: boolean,
97
+ showPageSelector?: boolean,
98
+ recalcActive?: boolean,
99
+ saveActive?: boolean,
100
+ onMetadataChange: (any) => any,
101
+ onAddGroup: (any) => any,
102
+ onRecalcClick: (any) => any
103
+ }
104
+
105
+ export const MainLayout = ({
106
+ state,
107
+ dispatch,
108
+ alwaysShowNextButton = false,
109
+ alwaysShowPrevButton = false,
110
+ RegionEditLabel,
111
+ onRegionClassAdded,
112
+ hideHeader,
113
+ hideHeaderText,
114
+ hideNext = false,
115
+ hidePrev = false,
116
+ hideClone = false,
117
+ hideSettings = false,
118
+ hideFullScreen = false,
119
+ hideSave = false,
120
+ groups = [],
121
+ onGroupSelect = () => { },
122
+ hideHistory = false,
123
+ hideNotEditingLabel = false,
124
+ showEditor = false,
125
+ showPageSelector = false,
126
+ recalcActive = false,
127
+ saveActive = false,
128
+ onMetadataChange,
129
+ onAddGroup,
130
+ onRecalcClick
131
+ }: Props) => {
132
+ const classes = useStyles()
133
+ const settings = useSettings()
134
+ const fullScreenHandle = useFullScreenHandle()
135
+ const { clsColor } = useColors();
136
+
137
+ const memoizedActionFns = useRef({})
138
+ const action = (type: string, ...params: Array<string>) => {
139
+ const fnKey = `${type}(${params.join(",")})`
140
+ if (memoizedActionFns.current[fnKey])
141
+ return memoizedActionFns.current[fnKey]
142
+
143
+ const fn = (...args: any) =>
144
+ params.length > 0
145
+ ? dispatch(
146
+ ({
147
+ type,
148
+ ...params.reduce((acc, p, i) => ((acc[p] = args[i]), acc), {}),
149
+ }: any)
150
+ )
151
+ : dispatch({ type, ...args[0] })
152
+ memoizedActionFns.current[fnKey] = fn
153
+ return fn
154
+ }
155
+
156
+ const { currentImageIndex, activeImage } = getActiveImage(state)
157
+ let nextImage
158
+ if (currentImageIndex !== null) {
159
+ nextImage = state.images[currentImageIndex + 1]
160
+ }
161
+
162
+ useKey(() => dispatch({ type: "CANCEL" }), {
163
+ detectKeys: [27],
164
+ })
165
+
166
+ const isAVideoFrame = activeImage && activeImage.frameTime !== undefined
167
+ const innerContainerRef = useRef()
168
+ const hotkeyHandlers = useDispatchHotkeyHandlers({ dispatch })
169
+
170
+ let impliedVideoRegions = useImpliedVideoRegions(state)
171
+
172
+ const refocusOnMouseEvent = useCallback((e) => {
173
+ if (!innerContainerRef.current) return
174
+ if (innerContainerRef.current.contains(document.activeElement)) return
175
+ if (innerContainerRef.current.contains(e.target)) {
176
+ innerContainerRef.current.focus()
177
+ e.target.focus()
178
+ }
179
+ }, [])
180
+
181
+ const allowedGroups = useMemo(() => regionsGroups(state.images[state.selectedImage].regions), [state.images, state.selectedImage])
182
+
183
+ const canvas = (
184
+ <ImageCanvas
185
+ {...settings}
186
+ showCrosshairs={
187
+ settings.showCrosshairs &&
188
+ !["select", "pan", "zoom"].includes(state.selectedTool)
189
+ }
190
+ key={state.selectedImage}
191
+ showMask={state.showMask}
192
+ fullImageSegmentationMode={state.fullImageSegmentationMode}
193
+ autoSegmentationOptions={state.autoSegmentationOptions}
194
+ showTags={state.showTags}
195
+ allowedArea={state.allowedArea}
196
+ modifyingAllowedArea={state.selectedTool === "modify-allowed-area"}
197
+ regionClsList={state.regionClsList}
198
+ regionTagList={state.regionTagList}
199
+ regions={
200
+ state.annotationType === "image"
201
+ ? activeImage.regions || []
202
+ : impliedVideoRegions
203
+ }
204
+ realSize={activeImage ? activeImage.realSize : undefined}
205
+ videoPlaying={state.videoPlaying}
206
+ imageSrc={state.annotationType === "image" ? activeImage.src : null}
207
+ videoSrc={state.annotationType === "video" ? state.videoSrc : null}
208
+ pointDistancePrecision={state.pointDistancePrecision}
209
+ createWithPrimary={state.selectedTool.includes("create")}
210
+ dragWithPrimary={state.selectedTool === "pan"}
211
+ zoomWithPrimary={state.selectedTool === "zoom"}
212
+ showPointDistances={state.showPointDistances}
213
+ videoTime={
214
+ state.annotationType === "image"
215
+ ? state.selectedImageFrameTime
216
+ : state.currentVideoTime
217
+ }
218
+ keypointDefinitions={state.keypointDefinitions}
219
+ onMouseMove={action("MOUSE_MOVE")}
220
+ onMouseDown={action("MOUSE_DOWN")}
221
+ onMouseUp={action("MOUSE_UP")}
222
+ onChangeRegion={action("CHANGE_REGION", "region")}
223
+ onBeginRegionEdit={action("OPEN_REGION_EDITOR", "region")}
224
+ onCloseRegionEdit={action("CLOSE_REGION_EDITOR", "region")}
225
+ onDeleteRegion={action("DELETE_REGION", "region")}
226
+ onDeleteGroup={action("DELETE_GROUP", "groupId")}
227
+ onBeginBoxTransform={action("BEGIN_BOX_TRANSFORM", "box", "directions")}
228
+ onResetZoom={() => dispatch({
229
+ type: "ZOOM_RESET",
230
+ })}
231
+ onBeginMovePolygonPoint={action(
232
+ "BEGIN_MOVE_POLYGON_POINT",
233
+ "polygon",
234
+ "pointIndex"
235
+ )}
236
+ onBeginMoveKeypoint={action(
237
+ "BEGIN_MOVE_KEYPOINT",
238
+ "region",
239
+ "keypointId"
240
+ )}
241
+ onAddPolygonPoint={action(
242
+ "ADD_POLYGON_POINT",
243
+ "polygon",
244
+ "point",
245
+ "pointIndex"
246
+ )}
247
+ onSelectRegion={action("SELECT_REGION", "region")}
248
+ onBeginMovePoint={action("BEGIN_MOVE_POINT", "point")}
249
+ onImageLoaded={action("IMAGE_LOADED", "image")}
250
+ RegionEditLabel={RegionEditLabel}
251
+ onImageOrVideoLoaded={action("IMAGE_OR_VIDEO_LOADED", "metadata")}
252
+ onChangeVideoTime={action("CHANGE_VIDEO_TIME", "newTime")}
253
+ onChangeVideoPlaying={action("CHANGE_VIDEO_PLAYING", "isPlaying")}
254
+ onRegionClassAdded={onRegionClassAdded}
255
+ allowComments={state.allowComments}
256
+ hideNotEditingLabel={hideNotEditingLabel}
257
+ allowedGroups={allowedGroups}
258
+ />
259
+ )
260
+
261
+ const onClickIconSidebarItem = useEventCallback((item) => {
262
+ dispatch({ type: "SELECT_TOOL", selectedTool: item.name })
263
+ })
264
+
265
+ const onClickHeaderItem = useEventCallback((item) => {
266
+ if (item.name === "Fullscreen") {
267
+ fullScreenHandle.enter()
268
+ } else if (item.name === "Window") {
269
+ fullScreenHandle.exit()
270
+ }
271
+ dispatch({ type: "HEADER_BUTTON_CLICKED", buttonName: item.name })
272
+ })
273
+
274
+ const debugModeOn = Boolean(window.localStorage.$ANNOTATE_DEBUG_MODE && state)
275
+ const nextImageHasRegions =
276
+ !nextImage || (nextImage.regions && nextImage.regions.length > 0)
277
+
278
+ // Editor.js blocks
279
+ const selectedGroupId = state.images[state.selectedImage]?.selectedGroupId || null;
280
+ const extractionEngineRegions = (state.images[state.selectedImage]?.regions || []).filter(r => r.cls !== 'metadata')
281
+ const editorBlocks = regionsToBlocks(extractionEngineRegions, clsColor);
282
+ const blocks = editorBlocks.filter(i => i?.data?.groupId === selectedGroupId);
283
+
284
+ const handleEditorChange = ({ imageIndex, data }) => {
285
+ const newRegions = data.blocks.map(i => ({
286
+ id: i.id,
287
+ cls: i.data.labelName,
288
+ text: i.data.text
289
+ }))
290
+ dispatch({ type: "UPDATE_REGIONS", regions: newRegions, imageIndex })
291
+ }
292
+
293
+ const pages = state.images.map((i, idx) => ({
294
+ id: `${i.id}`,
295
+ src: i.thumbnail,
296
+ isActive: idx === state.selectedImage,
297
+ pageNumber: i?.metadata?.find(md => md.key === "pageNumber")?.value || null,
298
+ metadata: i.metadata || [],
299
+ lockedUntil: i.lockedUntil,
300
+ syncError: i.syncError || null,
301
+ isRecalcReady: intersection(reacalcActionsEnum, state.images[idx].saveableActions).length > 0
302
+ }))
303
+
304
+ const handlePageClick = (pageIndex) => {
305
+ dispatch({ type: "SELECT_IMAGE", imageIndex: pageIndex })
306
+ }
307
+
308
+ const isSelectedImageLocked = state.images[state.selectedImage]?.lockedUntil ? true : false;
309
+ const selectedFrame = state.images[state.selectedImage]?.regions.find(i => i.highlighted === true)?.id || '';
310
+
311
+ return (
312
+ <ThemeProvider theme={theme}>
313
+ <FullScreenContainer>
314
+ <FullScreen
315
+ handle={fullScreenHandle}
316
+ onChange={(open) => {
317
+ if (!open) {
318
+ fullScreenHandle.exit()
319
+ action("HEADER_BUTTON_CLICKED", "buttonName")("Window")
320
+ }
321
+ }}
322
+ >
323
+ <HotkeyDiv
324
+ tabIndex={-1}
325
+ divRef={innerContainerRef}
326
+ onMouseDown={refocusOnMouseEvent}
327
+ onMouseOver={refocusOnMouseEvent}
328
+ allowChanges
329
+ handlers={hotkeyHandlers}
330
+ className={classnames(
331
+ classes.container,
332
+ state.fullScreen && "Fullscreen"
333
+ )}
334
+ >
335
+ <div style={{
336
+ display: 'flex',
337
+ flexDirection: 'row'
338
+ }}>
339
+ {
340
+ showPageSelector && (
341
+ <PageSelector pages={pages} onPageClick={handlePageClick} onMetadataChange={onMetadataChange} metadataConfigs={state.metadataConfigs || []} onRecalcClick={onRecalcClick} />
342
+ )
343
+ }
344
+ <WorkspaceWrapper >
345
+ <Workspace
346
+ style={{
347
+ width: "auto",
348
+ }}
349
+ allowFullscreen
350
+ iconDictionary={iconDictionary}
351
+ hideHeader={hideHeader}
352
+ hideHeaderText={hideHeaderText}
353
+ headerLeftSide={[
354
+ state.annotationType === "video" ? (
355
+ <KeyframeTimeline
356
+ currentTime={state.currentVideoTime}
357
+ duration={state.videoDuration}
358
+ onChangeCurrentTime={action("CHANGE_VIDEO_TIME", "newTime")}
359
+ keyframes={state.keyframes}
360
+ />
361
+ ) : activeImage ? (
362
+ <div className={classes.headerTitle}>{activeImage.name}</div>
363
+ ) : null,
364
+ ].filter(Boolean)}
365
+ headerItems={[
366
+ !hidePrev && { name: "Prev" },
367
+ !hideNext && { name: "Next" },
368
+ state.annotationType !== "video"
369
+ ? null
370
+ : !state.videoPlaying
371
+ ? { name: "Play" }
372
+ : { name: "Pause" },
373
+ !hideClone &&
374
+ !nextImageHasRegions &&
375
+ activeImage.regions && { name: "Clone" },
376
+ !hideSettings && { name: "Settings" },
377
+ !hideFullScreen &&
378
+ (state.fullScreen
379
+ ? { name: "Window" }
380
+ : { name: "Fullscreen" }),
381
+ !hideSave && { name: "Save" },
382
+ ].filter(Boolean)}
383
+ onClickHeaderItem={onClickHeaderItem}
384
+ onClickIconSidebarItem={onClickIconSidebarItem}
385
+ selectedTools={[
386
+ state.selectedTool,
387
+ state.showTags && "show-tags",
388
+ state.showMask && "show-mask",
389
+ ].filter(Boolean)}
390
+ iconSidebarItems={!state.enabledTools ? [] : [
391
+ {
392
+ name: "select",
393
+ helperText: "Select" + getHotkeyHelpText("select_tool"),
394
+ alwaysShowing: false,
395
+ },
396
+ {
397
+ name: "pan",
398
+ helperText:
399
+ "Drag/Pan (right or middle click)" +
400
+ getHotkeyHelpText("pan_tool"),
401
+ alwaysShowing: false,
402
+ },
403
+ {
404
+ name: "zoom",
405
+ helperText:
406
+ "Zoom In/Out (scroll)" + getHotkeyHelpText("zoom_tool"),
407
+ alwaysShowing: false,
408
+ },
409
+ {
410
+ name: "show-tags",
411
+ helperText: "Show / Hide Tags",
412
+ alwaysShowing: false,
413
+ },
414
+ {
415
+ name: "create-point",
416
+ helperText: "Add Point" + getHotkeyHelpText("create_point"),
417
+ },
418
+ {
419
+ name: "create-box",
420
+ helperText:
421
+ "Add Bounding Box" +
422
+ getHotkeyHelpText("create_bounding_box"),
423
+ },
424
+ {
425
+ name: "create-polygon",
426
+ helperText:
427
+ "Add Polygon" + getHotkeyHelpText("create_polygon"),
428
+ },
429
+ {
430
+ name: "create-line",
431
+ helperText: "Add Line",
432
+ },
433
+ {
434
+ name: "create-expanding-line",
435
+ helperText: "Add Expanding Line",
436
+ },
437
+ {
438
+ name: "create-keypoints",
439
+ helperText: "Add Keypoints (Pose)",
440
+ },
441
+ state.fullImageSegmentationMode && {
442
+ name: "show-mask",
443
+ alwaysShowing: false,
444
+ helperText: "Show / Hide Mask",
445
+ },
446
+ {
447
+ name: "modify-allowed-area",
448
+ helperText: "Modify Allowed Area",
449
+ },
450
+ ]
451
+ .filter(Boolean)
452
+ .filter(
453
+ (a) => a.alwaysShowing || state.enabledTools.includes(a.name)
454
+ )}
455
+ rightSidebarItems={[
456
+ <RightSidebarItemsWrapper>
457
+ {
458
+ [
459
+ isSelectedImageLocked && (<Locker />),
460
+ debugModeOn && (
461
+ <DebugBox state={debugModeOn} lastAction={state.lastAction} key="debug-box" />
462
+ ),
463
+ state.taskDescription && (
464
+ <TaskDescription description={state.taskDescription} key="task-description" />
465
+ ),
466
+ state.help && (
467
+ <Help help={state.help} key="help" />
468
+ ),
469
+ state.regionClsList && (
470
+ <ClassSelectionMenu
471
+ selectedCls={state.selectedCls}
472
+ regionClsList={state.regionClsList}
473
+ onSelectCls={action("SELECT_CLASSIFICATION", "cls")}
474
+ key="class-selection-menu"
475
+ />
476
+ ),
477
+ state.labelImages && (
478
+ <TagsSidebarBox
479
+ currentImage={activeImage}
480
+ imageClsList={state.imageClsList}
481
+ imageTagList={state.imageTagList}
482
+ onChangeImage={action("CHANGE_IMAGE", "delta")}
483
+ expandedByDefault
484
+ key="tags-sidebar-box"
485
+ />
486
+ ),
487
+ // (state.images?.length || 0) > 1 && (
488
+ // <ImageSelector
489
+ // onSelect={action("SELECT_REGION", "region")}
490
+ // images={state.images}
491
+ // />
492
+ // ),
493
+ // groups && (
494
+ // <GroupSelector
495
+ // title="Articles"
496
+ // groups={groups}
497
+ // selectedGroupId={selectedGroupId}
498
+ // onSelect={onGroupSelect}
499
+ // />
500
+ // )
501
+ ,
502
+ <RegionSelector
503
+ regions={activeImage ? activeImage.regions : emptyArr}
504
+ onSelectRegion={action("SELECT_REGION", "region")}
505
+ onDeleteRegion={action("DELETE_REGION", "region")}
506
+ onChangeRegion={action("CHANGE_REGION", "region")}
507
+ key="region-selector"
508
+ />,
509
+ state.keyframes && (
510
+ <KeyframesSelector
511
+ onChangeVideoTime={action("CHANGE_VIDEO_TIME", "newTime")}
512
+ onDeleteKeyframe={action("DELETE_KEYFRAME", "time")}
513
+ onChangeCurrentTime={action("CHANGE_VIDEO_TIME", "newTime")}
514
+ currentTime={state.currentVideoTime}
515
+ duration={state.videoDuration}
516
+ keyframes={state.keyframes}
517
+ key="key-frame-selector"
518
+ />
519
+ ),
520
+ !hideHistory && (
521
+ <HistorySidebarBox
522
+ history={state.history}
523
+ onRestoreHistory={action("RESTORE_HISTORY")}
524
+ key="history-sidebar"
525
+ />
526
+ ),
527
+ <MetadataEditor state={state} onMetadataChange={onMetadataChange} key="metadata-editor" />,
528
+ <GroupsEditor groups={allowedGroups} onAddGroup={onAddGroup} key="groups-editor" />,
529
+ ].filter(Boolean)
530
+ }
531
+ </RightSidebarItemsWrapper>
532
+ ]}
533
+ >
534
+ {
535
+ isSelectedImageLocked && (<Locker />)
536
+ }
537
+ {canvas}
538
+ </Workspace>
539
+ </WorkspaceWrapper>
540
+ {
541
+ (showEditor && !isSelectedImageLocked) && (
542
+ <EditorWrapper id="editor-wrapper">
543
+ <Editor id="editor" blocks={blocks} imageIndex={state.selectedImage} key={`${state.selectedImage}#${selectedGroupId}`} selectedFrame={selectedFrame} onChange={handleEditorChange} />
544
+ </EditorWrapper>
545
+ )
546
+ }
547
+ </div>
548
+ <SettingsDialog
549
+ open={state.settingsOpen}
550
+ onClose={() =>
551
+ dispatch({
552
+ type: "HEADER_BUTTON_CLICKED",
553
+ buttonName: "Settings",
554
+ })
555
+ }
556
+ />
557
+ </HotkeyDiv>
558
+ </FullScreen>
559
+ </FullScreenContainer>
560
+ </ThemeProvider >
561
+ )
562
+ }
563
+
564
+ export default MainLayout