@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,515 @@
1
+ // @flow weak
2
+
3
+ import React, {
4
+ useRef,
5
+ useState,
6
+ useLayoutEffect,
7
+ useEffect,
8
+ useMemo,
9
+ } from "react"
10
+ import type { Node } from "react"
11
+ import { Matrix } from "transformation-matrix-js"
12
+ import Crosshairs from "../Crosshairs"
13
+ import type {
14
+ Region,
15
+ Point,
16
+ Polygon,
17
+ Box,
18
+ Keypoints,
19
+ KeypointsDefinition,
20
+ } from "./region-tools.js"
21
+ import { makeStyles } from "@mui/styles"
22
+ import { createTheme, ThemeProvider } from "@mui/material/styles"
23
+ import styles from "./styles"
24
+ import PreventScrollToParents from "../PreventScrollToParents"
25
+ import useWindowSize from "../hooks/use-window-size.js"
26
+ import useMouse from "./use-mouse"
27
+ import useProjectRegionBox from "./use-project-box"
28
+ import useExcludePattern from "../hooks/use-exclude-pattern"
29
+ import { useRafState } from "react-use"
30
+ import PointDistances from "../PointDistances"
31
+ import RegionTags from "../RegionTags"
32
+ import RegionLabel from "../RegionLabel"
33
+ import ImageMask from "../ImageMask"
34
+ import RegionSelectAndTransformBoxes from "../RegionSelectAndTransformBoxes"
35
+ import VideoOrImageCanvasBackground from "../VideoOrImageCanvasBackground"
36
+ import useEventCallback from "use-event-callback"
37
+ import RegionShapes from "../RegionShapes"
38
+ import useWasdMode from "./use-wasd-mode"
39
+ import useKey from "use-key-hook"
40
+
41
+ const theme = createTheme()
42
+ const useStyles = makeStyles((theme) => styles)
43
+
44
+ type Props = {
45
+ regions: Array<Region>,
46
+ imageSrc?: string,
47
+ videoSrc?: string,
48
+ videoTime?: number,
49
+ keypointDefinitions?: KeypointDefinitions,
50
+ onMouseMove?: ({ x: number, y: number }) => any,
51
+ onMouseDown?: ({ x: number, y: number }) => any,
52
+ onMouseUp?: ({ x: number, y: number }) => any,
53
+ dragWithPrimary?: boolean,
54
+ zoomWithPrimary?: boolean,
55
+ createWithPrimary?: boolean,
56
+ showTags?: boolean,
57
+ realSize?: { width: number, height: number, unitName: string },
58
+ showCrosshairs?: boolean,
59
+ showMask?: boolean,
60
+ showHighlightBox?: boolean,
61
+ showPointDistances?: boolean,
62
+ pointDistancePrecision?: number,
63
+ regionClsList?: Array<string>,
64
+ regionTagList?: Array<string>,
65
+ allowedArea?: { x: number, y: number, w: number, h: number },
66
+ RegionEditLabel?: Node,
67
+ videoPlaying?: boolean,
68
+ zoomOnAllowedArea?: boolean,
69
+ fullImageSegmentationMode?: boolean,
70
+ autoSegmentationOptions?: Object,
71
+ modifyingAllowedArea?: boolean,
72
+ allowComments?: Boolean,
73
+ onChangeRegion: (Region) => any,
74
+ onBeginRegionEdit: (Region) => any,
75
+ onCloseRegionEdit: (Region) => any,
76
+ onDeleteRegion: (Region) => any,
77
+ onDeleteGroup: (string) => any,
78
+ onBeginBoxTransform: (Box, [number, number]) => any,
79
+ onBeginMovePolygonPoint: (Polygon, index: number) => any,
80
+ onBeginMoveKeypoint: (Keypoints, index: number) => any,
81
+ onAddPolygonPoint: (Polygon, point: [number, number], index: number) => any,
82
+ onSelectRegion: (Region) => any,
83
+ onBeginMovePoint: (Point) => any,
84
+ onImageOrVideoLoaded: ({
85
+ naturalWidth: number,
86
+ naturalHeight: number,
87
+ duration?: number,
88
+ }) => any,
89
+ onChangeVideoTime: (number) => any,
90
+ onRegionClassAdded: () => {},
91
+ onChangeVideoPlaying?: Function,
92
+ onResetZoom: Function,
93
+ hideNotEditingLabel?: boolean,
94
+ allowedGroups?: []
95
+ }
96
+
97
+ const getDefaultMat = (allowedArea = null, { iw, ih } = {}) => {
98
+ let mat = Matrix.from(1, 0, 0, 1, -10, -10)
99
+ if (allowedArea && iw) {
100
+ mat = mat
101
+ .translate(allowedArea.x * iw, allowedArea.y * ih)
102
+ .scaleU(allowedArea.w + 0.05)
103
+ }
104
+ return mat
105
+ }
106
+
107
+ export const ImageCanvas = ({
108
+ regions,
109
+ imageSrc,
110
+ videoSrc,
111
+ videoTime,
112
+ realSize,
113
+ showTags,
114
+ onMouseMove = (p) => null,
115
+ onMouseDown = (p) => null,
116
+ onMouseUp = (p) => null,
117
+ dragWithPrimary = false,
118
+ zoomWithPrimary = false,
119
+ createWithPrimary = false,
120
+ pointDistancePrecision = 0,
121
+ regionClsList,
122
+ regionTagList,
123
+ showCrosshairs,
124
+ showHighlightBox = true,
125
+ showPointDistances,
126
+ allowedArea,
127
+ RegionEditLabel = null,
128
+ videoPlaying = false,
129
+ showMask = true,
130
+ fullImageSegmentationMode,
131
+ autoSegmentationOptions,
132
+ onImageOrVideoLoaded,
133
+ onChangeRegion,
134
+ onBeginRegionEdit,
135
+ onCloseRegionEdit,
136
+ onBeginBoxTransform,
137
+ onBeginMovePolygonPoint,
138
+ onAddPolygonPoint,
139
+ onBeginMoveKeypoint,
140
+ onSelectRegion,
141
+ onBeginMovePoint,
142
+ onDeleteRegion,
143
+ onDeleteGroup,
144
+ onChangeVideoTime,
145
+ onChangeVideoPlaying,
146
+ onResetZoom,
147
+ onRegionClassAdded,
148
+ zoomOnAllowedArea = true,
149
+ modifyingAllowedArea = false,
150
+ keypointDefinitions,
151
+ allowComments,
152
+ hideNotEditingLabel = false,
153
+ allowedGroups,
154
+ }: Props) => {
155
+ const classes = useStyles()
156
+
157
+ const canvasEl = useRef(null)
158
+ const layoutParams = useRef({})
159
+ const [dragging, changeDragging] = useRafState(false)
160
+ const [maskImagesLoaded, changeMaskImagesLoaded] = useRafState(0)
161
+ const [zoomStart, changeZoomStart] = useRafState(null)
162
+ const [zoomEnd, changeZoomEnd] = useRafState(null)
163
+ const [mat, changeMat] = useRafState(getDefaultMat())
164
+ const maskImages = useRef({})
165
+ const windowSize = useWindowSize()
166
+
167
+ const getLatestMat = useEventCallback(() => mat)
168
+ useWasdMode({ getLatestMat, changeMat })
169
+
170
+ const { mouseEvents, mousePosition } = useMouse({
171
+ canvasEl,
172
+ dragging,
173
+ mat,
174
+ layoutParams,
175
+ changeMat,
176
+ zoomStart,
177
+ zoomEnd,
178
+ changeZoomStart,
179
+ changeZoomEnd,
180
+ changeDragging,
181
+ zoomWithPrimary,
182
+ dragWithPrimary,
183
+ onMouseMove,
184
+ onMouseDown,
185
+ onMouseUp,
186
+ })
187
+
188
+ useLayoutEffect(() => changeMat(mat.clone()), [windowSize])
189
+
190
+ const innerMousePos = mat.applyToPoint(
191
+ mousePosition.current.x,
192
+ mousePosition.current.y
193
+ )
194
+
195
+ const projectRegionBox = useProjectRegionBox({ layoutParams, mat })
196
+
197
+ const [imageDimensions, changeImageDimensions] = useState()
198
+ const imageLoaded = Boolean(imageDimensions && imageDimensions.naturalWidth)
199
+
200
+ const onVideoOrImageLoaded = useEventCallback(
201
+ ({ naturalWidth, naturalHeight, duration }) => {
202
+ const dims = { naturalWidth, naturalHeight, duration }
203
+ if (onImageOrVideoLoaded) onImageOrVideoLoaded(dims)
204
+ changeImageDimensions(dims)
205
+ // Redundant update to fix rerendering issues
206
+ setTimeout(() => changeImageDimensions(dims), 10)
207
+ }
208
+ )
209
+
210
+ const excludePattern = useExcludePattern()
211
+
212
+ const canvas = canvasEl.current
213
+ if (canvas && imageLoaded) {
214
+ const { clientWidth, clientHeight } = canvas
215
+
216
+ const fitScale = Math.max(
217
+ imageDimensions.naturalWidth / (clientWidth - 20),
218
+ imageDimensions.naturalHeight / (clientHeight - 20)
219
+ )
220
+
221
+ const [iw, ih] = [
222
+ imageDimensions.naturalWidth / fitScale,
223
+ imageDimensions.naturalHeight / fitScale,
224
+ ]
225
+
226
+ layoutParams.current = {
227
+ iw,
228
+ ih,
229
+ fitScale,
230
+ canvasWidth: clientWidth,
231
+ canvasHeight: clientHeight,
232
+ }
233
+ }
234
+
235
+ const resetZoom = () => {
236
+ onResetZoom();
237
+ changeMat(
238
+ getDefaultMat(
239
+ zoomOnAllowedArea ? allowedArea : null,
240
+ layoutParams.current
241
+ )
242
+ )
243
+ }
244
+
245
+ useKey(resetZoom, {
246
+ detectKeys: ['r'],
247
+ })
248
+
249
+
250
+ useEffect(() => {
251
+ if (!imageLoaded) return
252
+ changeMat(
253
+ getDefaultMat(
254
+ zoomOnAllowedArea ? allowedArea : null,
255
+ layoutParams.current
256
+ )
257
+ )
258
+ // eslint-disable-next-line
259
+ }, [imageLoaded])
260
+
261
+ useLayoutEffect(() => {
262
+ if (!imageDimensions) return
263
+ const { clientWidth, clientHeight } = canvas
264
+ canvas.width = clientWidth
265
+ canvas.height = clientHeight
266
+ const context = canvas.getContext("2d")
267
+
268
+ context.save()
269
+ context.transform(...mat.clone().inverse().toArray())
270
+
271
+ const { iw, ih } = layoutParams.current
272
+
273
+ if (allowedArea) {
274
+ // Pattern to indicate the NOT allowed areas
275
+ const { x, y, w, h } = allowedArea
276
+ context.save()
277
+ context.globalAlpha = 1
278
+ const outer = [
279
+ [0, 0],
280
+ [iw, 0],
281
+ [iw, ih],
282
+ [0, ih],
283
+ ]
284
+ const inner = [
285
+ [x * iw, y * ih],
286
+ [x * iw + w * iw, y * ih],
287
+ [x * iw + w * iw, y * ih + h * ih],
288
+ [x * iw, y * ih + h * ih],
289
+ ]
290
+ context.moveTo(...outer[0])
291
+ outer.forEach((p) => context.lineTo(...p))
292
+ context.lineTo(...outer[0])
293
+ context.closePath()
294
+
295
+ inner.reverse()
296
+ context.moveTo(...inner[0])
297
+ inner.forEach((p) => context.lineTo(...p))
298
+ context.lineTo(...inner[0])
299
+
300
+ context.fillStyle = excludePattern || "#f00"
301
+ context.fill()
302
+
303
+ context.restore()
304
+ }
305
+
306
+ context.restore()
307
+ })
308
+
309
+ const { iw, ih } = layoutParams.current
310
+
311
+ let zoomBox =
312
+ !zoomStart || !zoomEnd
313
+ ? null
314
+ : {
315
+ ...mat.clone().inverse().applyToPoint(zoomStart.x, zoomStart.y),
316
+ w: (zoomEnd.x - zoomStart.x) / mat.a,
317
+ h: (zoomEnd.y - zoomStart.y) / mat.d,
318
+ }
319
+ if (zoomBox) {
320
+ if (zoomBox.w < 0) {
321
+ zoomBox.x += zoomBox.w
322
+ zoomBox.w *= -1
323
+ }
324
+ if (zoomBox.h < 0) {
325
+ zoomBox.y += zoomBox.h
326
+ zoomBox.h *= -1
327
+ }
328
+ }
329
+
330
+ const imagePosition = {
331
+ topLeft: mat.clone().inverse().applyToPoint(0, 0),
332
+ bottomRight: mat.clone().inverse().applyToPoint(iw, ih),
333
+ }
334
+
335
+ const highlightedRegion = useMemo(() => {
336
+ const highlightedRegions = regions.filter((r) => r.highlighted)
337
+ if (highlightedRegions.length !== 1) return null
338
+ return highlightedRegions[0]
339
+ }, [regions])
340
+
341
+ return (
342
+ <ThemeProvider theme={theme}>
343
+ <div
344
+ style={{
345
+ width: "100%",
346
+ height: "100vh",
347
+ position: "relative",
348
+ overflow: "hidden",
349
+ cursor: createWithPrimary
350
+ ? "crosshair"
351
+ : dragging
352
+ ? "grabbing"
353
+ : dragWithPrimary
354
+ ? "grab"
355
+ : zoomWithPrimary
356
+ ? mat.a < 1
357
+ ? "zoom-out"
358
+ : "zoom-in"
359
+ : undefined,
360
+ }}
361
+ >
362
+ {showCrosshairs && (
363
+ <Crosshairs key="crossHairs" mousePosition={mousePosition} />
364
+ )}
365
+ {imageLoaded && !dragging && (
366
+ <RegionSelectAndTransformBoxes
367
+ key="regionSelectAndTransformBoxes"
368
+ regions={
369
+ !modifyingAllowedArea || !allowedArea
370
+ ? regions
371
+ : [
372
+ {
373
+ type: "box",
374
+ id: "$$allowed_area",
375
+ cls: "allowed_area",
376
+ highlighted: true,
377
+ x: allowedArea.x,
378
+ y: allowedArea.y,
379
+ w: allowedArea.w,
380
+ h: allowedArea.h,
381
+ visible: true,
382
+ color: "#ff0",
383
+ },
384
+ ]
385
+ }
386
+ mouseEvents={mouseEvents}
387
+ projectRegionBox={projectRegionBox}
388
+ dragWithPrimary={dragWithPrimary}
389
+ createWithPrimary={createWithPrimary}
390
+ zoomWithPrimary={zoomWithPrimary}
391
+ onBeginMovePoint={onBeginMovePoint}
392
+ onSelectRegion={onSelectRegion}
393
+ layoutParams={layoutParams}
394
+ mat={mat}
395
+ onBeginBoxTransform={onBeginBoxTransform}
396
+ onBeginMovePolygonPoint={onBeginMovePolygonPoint}
397
+ onBeginMoveKeypoint={onBeginMoveKeypoint}
398
+ onAddPolygonPoint={onAddPolygonPoint}
399
+ showHighlightBox={showHighlightBox}
400
+ />
401
+ )}
402
+ {imageLoaded && showTags && !dragging && (
403
+ <PreventScrollToParents key="regionTags">
404
+ <RegionTags
405
+ regions={regions}
406
+ projectRegionBox={projectRegionBox}
407
+ mouseEvents={mouseEvents}
408
+ regionClsList={regionClsList}
409
+ regionTagList={regionTagList}
410
+ onBeginRegionEdit={onBeginRegionEdit}
411
+ onChangeRegion={onChangeRegion}
412
+ onCloseRegionEdit={onCloseRegionEdit}
413
+ onDeleteRegion={onDeleteRegion}
414
+ onDeleteGroup={onDeleteGroup}
415
+ layoutParams={layoutParams}
416
+ imageSrc={imageSrc}
417
+ RegionEditLabel={RegionEditLabel}
418
+ onRegionClassAdded={onRegionClassAdded}
419
+ allowComments={allowComments}
420
+ hideNotEditingLabel={hideNotEditingLabel}
421
+ allowedGroups={allowedGroups}
422
+ />
423
+ </PreventScrollToParents>
424
+ )}
425
+ {!showTags && highlightedRegion && (
426
+ <div key="topLeftTag" className={classes.fixedRegionLabel}>
427
+ <RegionLabel
428
+ disableClose
429
+ allowedClasses={regionClsList}
430
+ allowedTags={regionTagList}
431
+ onChange={onChangeRegion}
432
+ onDelete={onDeleteRegion}
433
+ onDeleteGroup={onDeleteGroup}
434
+ editing
435
+ region={highlightedRegion}
436
+ imageSrc={imageSrc}
437
+ allowComments={allowComments}
438
+ />
439
+ </div>
440
+ )}
441
+
442
+ {zoomWithPrimary && zoomBox !== null && (
443
+ <div
444
+ key="zoomBox"
445
+ style={{
446
+ position: "absolute",
447
+ zIndex: 1,
448
+ border: "1px solid #fff",
449
+ pointerEvents: "none",
450
+ left: zoomBox.x,
451
+ top: zoomBox.y,
452
+ width: zoomBox.w,
453
+ height: zoomBox.h,
454
+ }}
455
+ />
456
+ )}
457
+ {showPointDistances && (
458
+ <PointDistances
459
+ key="pointDistances"
460
+ regions={regions}
461
+ realSize={realSize}
462
+ projectRegionBox={projectRegionBox}
463
+ pointDistancePrecision={pointDistancePrecision}
464
+ />
465
+ )}
466
+ <PreventScrollToParents
467
+ style={{ width: "100%", height: "100%" }}
468
+ {...mouseEvents}
469
+ >
470
+ <>
471
+ {fullImageSegmentationMode && (
472
+ <ImageMask
473
+ hide={!showMask}
474
+ autoSegmentationOptions={autoSegmentationOptions}
475
+ imagePosition={imagePosition}
476
+ regionClsList={regionClsList}
477
+ imageSrc={imageSrc}
478
+ regions={regions}
479
+ />
480
+ )}
481
+ <canvas
482
+ style={{ opacity: 0.25 }}
483
+ className={classes.canvas}
484
+ ref={canvasEl}
485
+ />
486
+ <RegionShapes
487
+ mat={mat}
488
+ keypointDefinitions={keypointDefinitions}
489
+ imagePosition={imagePosition}
490
+ regions={regions}
491
+ fullSegmentationMode={fullImageSegmentationMode}
492
+ />
493
+ <VideoOrImageCanvasBackground
494
+ videoPlaying={videoPlaying}
495
+ imagePosition={imagePosition}
496
+ mouseEvents={mouseEvents}
497
+ onLoad={onVideoOrImageLoaded}
498
+ videoTime={videoTime}
499
+ videoSrc={videoSrc}
500
+ imageSrc={imageSrc}
501
+ useCrossOrigin={fullImageSegmentationMode}
502
+ onChangeVideoTime={onChangeVideoTime}
503
+ onChangeVideoPlaying={onChangeVideoPlaying}
504
+ />
505
+ </>
506
+ </PreventScrollToParents>
507
+ <div className={classes.zoomIndicator}>
508
+ {((1 / mat.a) * 100).toFixed(0)}%
509
+ </div>
510
+ </div>
511
+ </ThemeProvider>
512
+ )
513
+ }
514
+
515
+ export default ImageCanvas