lost-sia 2.0.1-alpha8 → 3.0.0

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 (280) hide show
  1. package/README.md +4 -0
  2. package/dist/Annotation/logic/Annotation.d.ts +17 -0
  3. package/dist/Annotation/logic/Annotation.js +1 -0
  4. package/dist/Annotation/ui/AnnotationComponent.d.ts +24 -0
  5. package/dist/Annotation/ui/AnnotationComponent.js +1 -0
  6. package/dist/Annotation/ui/atoms/AnnoBar.d.ts +15 -0
  7. package/dist/Annotation/ui/atoms/AnnoBar.js +1 -0
  8. package/dist/Annotation/ui/atoms/DaviIcon.d.ts +9 -0
  9. package/dist/Annotation/ui/atoms/DaviIcon.js +19 -0
  10. package/dist/Annotation/ui/atoms/Edge.d.ts +17 -0
  11. package/dist/Annotation/ui/atoms/Edge.js +1 -0
  12. package/dist/Annotation/ui/atoms/Node.d.ts +17 -0
  13. package/dist/Annotation/ui/atoms/Node.js +1 -0
  14. package/dist/Annotation/ui/atoms/PolygonArea.d.ts +16 -0
  15. package/dist/Annotation/ui/atoms/PolygonArea.js +1 -0
  16. package/dist/Annotation/ui/tools/BBox.d.ts +21 -0
  17. package/dist/Annotation/ui/tools/BBox.js +1 -0
  18. package/dist/Annotation/ui/tools/Line.d.ts +21 -0
  19. package/dist/Annotation/ui/tools/Line.js +1 -0
  20. package/dist/Annotation/ui/tools/Point.d.ts +16 -0
  21. package/dist/Annotation/ui/tools/Point.js +1 -0
  22. package/dist/Annotation/ui/tools/Polygon.d.ts +23 -0
  23. package/dist/Annotation/ui/tools/Polygon.js +1 -0
  24. package/dist/Canvas/Canvas.d.ts +31 -0
  25. package/dist/Canvas/Canvas.js +1 -0
  26. package/dist/Canvas/LabelInput.d.ts +11 -0
  27. package/dist/Canvas/LabelInput.js +1 -0
  28. package/dist/IconButton.d.ts +25 -0
  29. package/dist/IconButton.js +1 -0
  30. package/dist/Sia.d.ts +33 -0
  31. package/dist/Sia.js +1 -0
  32. package/dist/Toolbar/Toolbar.d.ts +21 -0
  33. package/dist/Toolbar/Toolbar.js +1 -0
  34. package/dist/Toolbar/ToolbarItems/AccessibilityTools.d.ts +7 -0
  35. package/dist/Toolbar/ToolbarItems/AccessibilityTools.js +1 -0
  36. package/dist/Toolbar/ToolbarItems/AnnoToolSelector.d.ts +11 -0
  37. package/dist/Toolbar/ToolbarItems/AnnoToolSelector.js +1 -0
  38. package/dist/Toolbar/ToolbarItems/ImageToolItems/ImageLabelInput.d.ts +11 -0
  39. package/dist/Toolbar/ToolbarItems/ImageToolItems/ImageLabelInput.js +1 -0
  40. package/dist/Toolbar/ToolbarItems/ImageToolItems/TagLabel.d.ts +11 -0
  41. package/dist/Toolbar/ToolbarItems/ImageToolItems/TagLabel.js +1 -0
  42. package/dist/Toolbar/ToolbarItems/ImageTools.d.ts +13 -0
  43. package/dist/Toolbar/ToolbarItems/ImageTools.js +1 -0
  44. package/dist/Toolbar/ToolbarItems/Instructions.d.ts +2 -0
  45. package/dist/Toolbar/ToolbarItems/Instructions.js +1 -0
  46. package/dist/Toolbar/ToolbarItems/InstructionsModal.d.ts +6 -0
  47. package/dist/Toolbar/ToolbarItems/InstructionsModal.js +1 -0
  48. package/dist/assets/SIA-BV1tYu3P.css +1 -0
  49. package/dist/assets/brand-icons-Cu_C0hZ4.svg +1008 -0
  50. package/dist/assets/brand-icons-F3SPCeH1.woff +0 -0
  51. package/dist/assets/brand-icons-XL9sxUpA.woff2 +0 -0
  52. package/dist/assets/brand-icons-sqJ2Pg7a.eot +0 -0
  53. package/dist/assets/brand-icons-ubhWoxly.ttf +0 -0
  54. package/dist/assets/flags-DOLqOU7Y.png +0 -0
  55. package/dist/assets/icons-BOCtAERH.woff +0 -0
  56. package/dist/assets/icons-CHzK1VD9.eot +0 -0
  57. package/dist/assets/icons-D29ZQHHw.ttf +0 -0
  58. package/dist/assets/icons-Du6TOHnR.woff2 +0 -0
  59. package/dist/assets/icons-RwhydX30.svg +1518 -0
  60. package/dist/assets/node_modules/semantic-ui-css/semantic.min-Bvulf91l.css +346 -0
  61. package/dist/assets/outline-icons-BfdLr8tr.svg +366 -0
  62. package/dist/assets/outline-icons-DD8jm0uy.ttf +0 -0
  63. package/dist/assets/outline-icons-DInHoiqI.woff2 +0 -0
  64. package/dist/assets/outline-icons-LX8adJ4n.eot +0 -0
  65. package/dist/assets/outline-icons-aQ88nltS.woff +0 -0
  66. package/dist/index.d.ts +5 -0
  67. package/dist/index.js +1 -0
  68. package/dist/models/AnnotationMode.d.ts +11 -0
  69. package/dist/models/AnnotationMode.js +1 -0
  70. package/dist/models/AnnotationStatus.d.ts +8 -0
  71. package/dist/models/AnnotationStatus.js +1 -0
  72. package/dist/models/AnnotationTool.d.ts +7 -0
  73. package/dist/models/AnnotationTool.js +1 -0
  74. package/dist/models/CanvasAction.d.ts +28 -0
  75. package/dist/models/CanvasAction.js +1 -0
  76. package/dist/models/Direction.d.ts +7 -0
  77. package/dist/models/Direction.js +1 -0
  78. package/dist/models/EditorModes.d.ts +11 -0
  79. package/dist/models/EditorModes.js +1 -0
  80. package/dist/models/KeyAction.d.ts +22 -0
  81. package/dist/models/KeyAction.js +1 -0
  82. package/dist/models/NotificationType.d.ts +7 -0
  83. package/dist/models/NotificationType.js +1 -0
  84. package/dist/models/index.d.ts +6 -0
  85. package/dist/models/index.js +1 -0
  86. package/dist/stories/AnnotationTools.stories.d.ts +40 -0
  87. package/dist/stories/Canvas/Canvas.stories.d.ts +50 -0
  88. package/dist/stories/Canvas/CanvasOffset.d.ts +13 -0
  89. package/dist/stories/Canvas/CanvasWithOffset.stories.d.ts +36 -0
  90. package/dist/stories/FilterDropdown.stories.d.ts +19 -0
  91. package/dist/stories/MinimalSia.stories.d.ts +66 -0
  92. package/dist/stories/SIA/DemoWrapper.d.ts +8 -0
  93. package/dist/stories/SIA/DemoWrapper.stories.d.ts +27 -0
  94. package/dist/stories/SIA/SIA.stories.d.ts +72 -0
  95. package/dist/stories/Toolbar/ImageTools/TagLabel.stories.d.ts +21 -0
  96. package/dist/stories/Toolbar/Instructions.stories.d.ts +11 -0
  97. package/dist/stories/Toolbar/Toolbar.stories.d.ts +37 -0
  98. package/dist/stories/exampleData/exampleAnnotations.d.ts +8 -0
  99. package/dist/stories/exampleData/exampleExternalAnnotations.d.ts +8 -0
  100. package/dist/stories/exampleData/exampleImage.d.ts +2 -0
  101. package/dist/stories/exampleData/exampleLabels.d.ts +6 -0
  102. package/dist/types.d.ts +57 -0
  103. package/dist/types.js +1 -0
  104. package/dist/utils/KeyMapper.d.ts +9 -0
  105. package/dist/utils/KeyMapper.js +1 -0
  106. package/dist/utils/TimeUtils.d.ts +4 -0
  107. package/dist/utils/TimeUtils.js +1 -0
  108. package/dist/utils/color.d.ts +2 -0
  109. package/dist/utils/color.js +1 -0
  110. package/dist/utils/index.d.ts +2 -0
  111. package/dist/utils/index.js +1 -0
  112. package/dist/utils/mouse.d.ts +6 -0
  113. package/dist/utils/mouse.js +1 -0
  114. package/dist/utils/siaIcons.js +12 -0
  115. package/dist/utils/transform.d.ts +28 -0
  116. package/dist/utils/transform.js +1 -0
  117. package/dist/utils/uiConfig.js +1 -0
  118. package/dist/utils/windowViewport.d.ts +22 -0
  119. package/dist/utils/windowViewport.js +1 -0
  120. package/package.json +19 -16
  121. package/src/AnnoExampleViewer.jsx +18 -18
  122. package/src/Annotation/logic/Annotation.ts +24 -26
  123. package/src/Annotation/ui/AnnotationComponent.tsx +115 -86
  124. package/src/Annotation/ui/atoms/AnnoBar.tsx +51 -53
  125. package/src/Annotation/ui/atoms/DaviIcon.tsx +12 -22
  126. package/src/Annotation/ui/atoms/Edge.tsx +25 -22
  127. package/src/Annotation/ui/atoms/Node.tsx +56 -50
  128. package/src/Annotation/ui/atoms/PolygonArea.tsx +30 -35
  129. package/src/Annotation/ui/tools/BBox.tsx +136 -150
  130. package/src/Annotation/ui/tools/Line.tsx +94 -91
  131. package/src/Annotation/ui/tools/Point.tsx +19 -17
  132. package/src/Annotation/ui/tools/Polygon.tsx +126 -95
  133. package/src/Canvas/Canvas.tsx +748 -594
  134. package/src/Canvas/LabelInput.tsx +68 -45
  135. package/src/IconButton.tsx +119 -0
  136. package/src/InfoBoxes/AnnoDetails.jsx +53 -53
  137. package/src/InfoBoxes/AnnoStats.jsx +41 -41
  138. package/src/InfoBoxes/InfoBox.jsx +16 -16
  139. package/src/InfoBoxes/InfoBoxArea.jsx +32 -34
  140. package/src/InfoBoxes/LabelInfo.jsx +30 -30
  141. package/src/SIASettingButton.jsx +25 -25
  142. package/src/Sia.tsx +484 -0
  143. package/src/Toolbar/Toolbar.tsx +38 -31
  144. package/src/Toolbar/ToolbarItems/AccessibilityTools.tsx +26 -46
  145. package/src/Toolbar/ToolbarItems/AnnoToolSelector.tsx +53 -46
  146. package/src/Toolbar/ToolbarItems/ImageToolItems/ImageLabelInput.tsx +127 -0
  147. package/src/Toolbar/ToolbarItems/ImageToolItems/TagLabel.tsx +29 -28
  148. package/src/Toolbar/ToolbarItems/ImageTools.tsx +43 -40
  149. package/src/Toolbar/ToolbarItems/Instructions.tsx +47 -50
  150. package/src/Toolbar/ToolbarItems/InstructionsModal.tsx +8 -8
  151. package/src/index.ts +9 -13
  152. package/src/models/{AnnotationMode.tsx → AnnotationMode.ts} +1 -1
  153. package/src/models/{AnnotationStatus.tsx → AnnotationStatus.ts} +1 -1
  154. package/src/models/{AnnotationTool.tsx → AnnotationTool.ts} +1 -1
  155. package/src/models/{CanvasAction.tsx → CanvasAction.ts} +1 -1
  156. package/src/models/{Direction.tsx → Direction.ts} +1 -1
  157. package/src/models/{EditorModes.tsx → EditorModes.ts} +1 -1
  158. package/src/models/{KeyAction.tsx → KeyAction.ts} +3 -1
  159. package/src/models/NotificationType.ts +8 -0
  160. package/src/models/index.ts +6 -7
  161. package/src/siaDummyData.js +71 -71
  162. package/src/stories/AnnotationTools.mdx +27 -0
  163. package/src/stories/AnnotationTools.stories.tsx +104 -0
  164. package/src/stories/Canvas/Canvas.stories.tsx +59 -113
  165. package/src/stories/Canvas/CanvasOffset.tsx +54 -38
  166. package/src/stories/Canvas/CanvasWithOffset.stories.tsx +42 -113
  167. package/src/stories/FilterDropdown.stories.ts +13 -11
  168. package/src/stories/MinimalSIA.mdx +20 -0
  169. package/src/stories/MinimalSia.stories.tsx +90 -0
  170. package/src/stories/SIA/DemoWrapper.stories.tsx +71 -0
  171. package/src/stories/SIA/DemoWrapper.tsx +55 -0
  172. package/src/stories/SIA/SIA.stories.tsx +79 -45
  173. package/src/stories/Toolbar/ImageTools/TagLabel.stories.tsx +11 -12
  174. package/src/stories/Toolbar/Instructions.stories.tsx +11 -11
  175. package/src/stories/Toolbar/Toolbar.stories.tsx +32 -47
  176. package/src/stories/Welcome.mdx +5 -0
  177. package/src/stories/development/CoordinateSystems.mdx +25 -0
  178. package/src/stories/exampleData/exampleAnnotations.ts +65 -0
  179. package/src/stories/exampleData/exampleExternalAnnotations.ts +115 -0
  180. package/src/stories/{siaDummyData2.ts → exampleData/exampleImage.ts} +3 -264
  181. package/src/stories/exampleData/exampleLabels.ts +146 -0
  182. package/src/stories/main.scss +6 -0
  183. package/src/styles/style.scss +1 -26
  184. package/src/types.ts +67 -0
  185. package/src/utils/KeyMapper.ts +76 -74
  186. package/src/utils/TimeUtils.ts +11 -0
  187. package/src/utils/color.ts +25 -25
  188. package/src/utils/hist.js +22 -22
  189. package/src/utils/index.ts +2 -3
  190. package/src/utils/mouse.ts +45 -0
  191. package/src/utils/siaIcons.jsx +5 -7
  192. package/src/utils/transform.ts +186 -0
  193. package/src/utils/uiConfig.js +19 -22
  194. package/src/utils/windowViewport.ts +34 -0
  195. package/src/AnnoLabelInput.jsx +0 -109
  196. package/src/AnnoToolBar.jsx +0 -153
  197. package/src/Annotation/AnnoBar.jsx +0 -154
  198. package/src/Annotation/Annotation.jsx +0 -395
  199. package/src/Annotation/Annotation.scss +0 -47
  200. package/src/Annotation/BBox.jsx +0 -299
  201. package/src/Annotation/Edge.jsx +0 -92
  202. package/src/Annotation/InfSelectionArea.jsx +0 -72
  203. package/src/Annotation/Line.jsx +0 -68
  204. package/src/Annotation/Node.jsx +0 -282
  205. package/src/Annotation/Point.jsx +0 -200
  206. package/src/Annotation/Polygon.jsx +0 -404
  207. package/src/Annotation/logic/AnnotationUtils.ts +0 -30
  208. package/src/Canvas.jsx +0 -2194
  209. package/src/ImgBar.jsx +0 -131
  210. package/src/LabelInput.jsx +0 -238
  211. package/src/Prompt.jsx +0 -45
  212. package/src/SIAFilterButton.jsx +0 -186
  213. package/src/Sia.jsx +0 -478
  214. package/src/Sia2.tsx +0 -392
  215. package/src/SiaPopup.jsx +0 -15
  216. package/src/ToolBar.jsx +0 -463
  217. package/src/Toolbar/NavigationButtons.tsx +0 -21
  218. package/src/Toolbar/ToolbarItem.jsx +0 -30
  219. package/src/Toolbar/ToolbarItems/ImageToolItems/ImageLabel.tsx +0 -62
  220. package/src/Toolbar.css +0 -13
  221. package/src/ToolbarItem.jsx +0 -31
  222. package/src/filterTools.js +0 -5
  223. package/src/models/AllowedTools.tsx +0 -9
  224. package/src/models/AnnotationSettings.tsx +0 -9
  225. package/src/models/ExternalAnnotation.ts +0 -15
  226. package/src/models/Label.tsx +0 -8
  227. package/src/models/UiConfig.tsx +0 -6
  228. package/src/stories/Button.jsx +0 -54
  229. package/src/stories/Button.stories.js +0 -48
  230. package/src/stories/Header.jsx +0 -69
  231. package/src/stories/Header.stories.js +0 -28
  232. package/src/stories/Page.jsx +0 -87
  233. package/src/stories/Page.stories.js +0 -28
  234. package/src/stories/SIA2/DemoWrapper.stories.tsx +0 -167
  235. package/src/stories/SIA2/DemoWrapper.tsx +0 -54
  236. package/src/stories/SIA2/Sia2.stories.tsx +0 -62
  237. package/src/stories/Toolbar/ImageTools/ImageLabel.stories.tsx +0 -32
  238. package/src/stories/assets/accessibility.png +0 -0
  239. package/src/stories/assets/accessibility.svg +0 -5
  240. package/src/stories/assets/addon-library.png +0 -0
  241. package/src/stories/assets/assets.png +0 -0
  242. package/src/stories/assets/avif-test-image.avif +0 -0
  243. package/src/stories/assets/context.png +0 -0
  244. package/src/stories/assets/discord.svg +0 -15
  245. package/src/stories/assets/docs.png +0 -0
  246. package/src/stories/assets/figma-plugin.png +0 -0
  247. package/src/stories/assets/github.svg +0 -3
  248. package/src/stories/assets/share.png +0 -0
  249. package/src/stories/assets/styling.png +0 -0
  250. package/src/stories/assets/testing.png +0 -0
  251. package/src/stories/assets/theming.png +0 -0
  252. package/src/stories/assets/tutorials.svg +0 -12
  253. package/src/stories/assets/youtube.svg +0 -4
  254. package/src/stories/button.css +0 -30
  255. package/src/stories/header.css +0 -32
  256. package/src/stories/lost.js +0 -54
  257. package/src/stories/page.css +0 -69
  258. package/src/stories/siaDummyData.js +0 -263
  259. package/src/stories/store.js +0 -18
  260. package/src/test.js +0 -7
  261. package/src/types/annoStatus.js +0 -4
  262. package/src/types/canvasActions.js +0 -58
  263. package/src/types/cursorstyles.js +0 -3
  264. package/src/types/modes.js +0 -9
  265. package/src/types/notificationType.js +0 -11
  266. package/src/types/toolbarEvents.js +0 -35
  267. package/src/types/tools.js +0 -17
  268. package/src/types.tsx +0 -11
  269. package/src/utils/annoConversion.js +0 -145
  270. package/src/utils/annoConversion2.ts +0 -145
  271. package/src/utils/colorlut.js +0 -68
  272. package/src/utils/constraints.js +0 -81
  273. package/src/utils/index.js +0 -1
  274. package/src/utils/keyActions.js +0 -113
  275. package/src/utils/mouse.js +0 -14
  276. package/src/utils/mouse2.ts +0 -35
  277. package/src/utils/transform.js +0 -336
  278. package/src/utils/transform2.ts +0 -343
  279. package/src/utils/windowViewport.js +0 -34
  280. package/src/utils/windowViewport2.ts +0 -50
package/src/Sia.tsx ADDED
@@ -0,0 +1,484 @@
1
+ import { useEffect, useState, ReactElement, useRef, CSSProperties } from 'react'
2
+ import { CSpinner } from '@coreui/react'
3
+ import Canvas from './Canvas/Canvas'
4
+ import AnnotationTool from './models/AnnotationTool'
5
+ import Toolbar from './Toolbar/Toolbar'
6
+ import Annotation from './Annotation/logic/Annotation'
7
+ import AnnotationMode from './models/AnnotationMode'
8
+ import AnnotationStatus from './models/AnnotationStatus'
9
+ import {
10
+ AllowedTools,
11
+ AnnotationSettings,
12
+ ExternalAnnotation,
13
+ Label,
14
+ PolygonOperationResult,
15
+ SIANotification,
16
+ UiConfig,
17
+ } from './types'
18
+
19
+ type SiaProps = {
20
+ additionalButtons?: ReactElement
21
+ allowedTools?: AllowedTools
22
+ polygonOperationResult?: PolygonOperationResult
23
+ annotationSettings?: AnnotationSettings
24
+ defaultAnnotationTool?: AnnotationTool
25
+ defaultLabelId?: number
26
+ image?: string
27
+ isLoading?: boolean
28
+ isPolygonSelectionMode?: boolean
29
+ initialAnnotations?: ExternalAnnotation[]
30
+ initialImageLabelIds?: number[]
31
+ initialIsImageJunk?: boolean
32
+ possibleLabels: Label[]
33
+ uiConfig?: UiConfig
34
+ onAnnoCreated?: (createdAnno: Annotation, allAnnos: Annotation[]) => void
35
+ onAnnoCreationFinished?: (createdAnno: Annotation, allAnnos: Annotation[]) => void
36
+ onAnnoChanged?: (changedAnno: Annotation, allAnnos: Annotation[]) => void
37
+ onAnnoDeleted?: (deletedAnno: Annotation, allAnnos: Annotation[]) => void
38
+ onImageLabelsChanged?: (selectedImageIds: number[]) => void
39
+ onIsImageJunk?: (isJunk: boolean) => void
40
+ onNotification?: (notification: SIANotification) => void
41
+ onSelectAnnotation?: (annotation: Annotation) => void
42
+ }
43
+
44
+ /**
45
+ * Main SIA component
46
+ */
47
+ const Sia2 = ({
48
+ additionalButtons,
49
+ allowedTools: propAllowedTools,
50
+ polygonOperationResult = { annotationsToDelete: [], polygonsToCreate: [] },
51
+ annotationSettings: propAnnotationSettings,
52
+ uiConfig: propUiConfig,
53
+ defaultAnnotationTool,
54
+ defaultLabelId,
55
+ image,
56
+ isLoading = false,
57
+ isPolygonSelectionMode = false,
58
+ initialAnnotations = undefined,
59
+ initialImageLabelIds = undefined,
60
+ initialIsImageJunk = false,
61
+ possibleLabels,
62
+ onAnnoCreated = (_, __) => {},
63
+ onAnnoCreationFinished = (_, __) => {},
64
+ onAnnoChanged = (_, __) => {},
65
+ onAnnoDeleted = (_, __) => {},
66
+ onImageLabelsChanged = () => {},
67
+ onIsImageJunk = () => {},
68
+ onNotification = (_) => {},
69
+ onSelectAnnotation = (_) => {},
70
+ }: SiaProps) => {
71
+ const marginBetweenToolbarAndContainerPixels: number = 10
72
+
73
+ // ref for accessing the toolbar height (adjustable by screen size + custom components)
74
+ const toolbarContainerRef = useRef(null)
75
+
76
+ const [allowedTools, setAllowedTools] = useState<AllowedTools>()
77
+
78
+ const [annotations, setAnnotations] = useState<Annotation[]>([])
79
+ const [annotationSettings, setAnnotationSettings] = useState<AnnotationSettings>()
80
+
81
+ const [uiConfig, setUiConfig] = useState<UiConfig>()
82
+
83
+ const [selectedAnnotation, setSelectedAnnotation] = useState<Annotation>()
84
+
85
+ const [selectedAnnoTool, setSelectedAnnoTool] = useState<AnnotationTool>(
86
+ defaultAnnotationTool ?? AnnotationTool.Point,
87
+ )
88
+
89
+ // for adjusting the container/canvas size
90
+ // const [toolbarHeight, setToolbarHeight] = useState<number>(-1);
91
+
92
+ // const [outerContainerStyle, setOuterContainerStyle] = useState<CSSProperties>({
93
+ // // use the max available height as a flex child
94
+ // flex: '1 1 auto',
95
+ // minHeight: 0,
96
+
97
+ // // give the max available height to the next child
98
+ // display: 'flex',
99
+ // flexDirection: 'column',
100
+ // })
101
+
102
+ const [imageLabelIds, setImageLabelIds] = useState<number[]>(initialImageLabelIds)
103
+
104
+ const [isImageJunk, setIsImageJunk] = useState<boolean>()
105
+ const [isFullscreen, setIsFullscreen] = useState<boolean>(false)
106
+
107
+ // keep track which numbers are already used for annotation ids - even if they are deleted
108
+ const [usedInternalIds, setUsedInternalIds] = useState<number[]>([])
109
+
110
+ const deleteAnnotationByInternalId = (internalId: number) => {
111
+ // get index of selected annotation
112
+ const annoListIndex: number = annotations.findIndex(
113
+ (anno) => anno.internalId === internalId,
114
+ )
115
+
116
+ // dereference list to force state update
117
+ const _annotations: Annotation[] = [...annotations]
118
+
119
+ // remove annotation
120
+ const removedAnno: Annotation = _annotations.splice(annoListIndex, 1)[0]
121
+
122
+ setAnnotations(_annotations)
123
+ setSelectedAnnotation(undefined)
124
+
125
+ // inform the outside world about our changes
126
+ onAnnoDeleted(removedAnno, _annotations)
127
+ }
128
+
129
+ const deleteSelectedAnnotation = () => {
130
+ if (selectedAnnotation === undefined) return
131
+
132
+ deleteAnnotationByInternalId(selectedAnnotation.internalId)
133
+ }
134
+
135
+ const createInitialAnnotations = () => {
136
+ // this is only run during initialization, so internal id list is always empty at this point
137
+ // fill this without the dedicated createNewInternalAnnotationId to avoid accessing old state
138
+ // setState in loop thats depending on its value => you are in react hell
139
+ let internalAnnoId: number = 0
140
+
141
+ // create internal annotation object from external annotations
142
+ // assign internal id, add default data if not set from the outside
143
+ const _annotations: Annotation[] = initialAnnotations.map(
144
+ (externalAnno: ExternalAnnotation) => {
145
+ const _anno: Annotation = {
146
+ ...externalAnno,
147
+ internalId: internalAnnoId++,
148
+ mode: AnnotationMode.VIEW,
149
+ selectedNode: 1,
150
+ status: externalAnno.status,
151
+ annoTime: externalAnno.annoTime ?? 0,
152
+ }
153
+
154
+ return _anno
155
+ },
156
+ )
157
+
158
+ // list all used internal ids (from 0 to internalAnnoId)
159
+ setUsedInternalIds([...new Array(internalAnnoId).keys()])
160
+
161
+ setAnnotations(_annotations)
162
+ }
163
+
164
+ const createNewInternalAnnotationId = (): number => {
165
+ // find the next free number
166
+ let newInternalId: number = 0
167
+ while (usedInternalIds.includes(newInternalId)) newInternalId++
168
+
169
+ // add it to the used numbers (dereference list to trigger react state change)
170
+ const _usedInternalIds = [...usedInternalIds]
171
+ _usedInternalIds.push(newInternalId)
172
+ setUsedInternalIds(_usedInternalIds)
173
+
174
+ return newInternalId
175
+ }
176
+
177
+ const handleAnnoEditing = (annotation: Annotation) => {
178
+ const _annotations: Annotation[] = [...annotations]
179
+
180
+ // annotation is being edited - remove it from current annotations for this time
181
+ const selectedAnnotationIndex: number = _annotations.findIndex(
182
+ (annotation: Annotation) =>
183
+ annotation.internalId === selectedAnnotation?.internalId,
184
+ )
185
+
186
+ if (selectedAnnotationIndex === -1) return
187
+
188
+ // remove the old anno
189
+ const removedAnno: Annotation = _annotations.splice(selectedAnnotationIndex, 1)[0]
190
+
191
+ // do deletion state update without the new anno!
192
+ onAnnoDeleted(removedAnno, _annotations)
193
+
194
+ // add the new anno
195
+ const newAnnoations: Annotation[] = [..._annotations]
196
+ newAnnoations.push(annotation)
197
+
198
+ // update the list
199
+ setAnnotations(newAnnoations)
200
+
201
+ setSelectedAnnotation(annotation)
202
+ }
203
+
204
+ const handleImageJunk = (newJunkState: boolean) => {
205
+ setIsImageJunk(newJunkState)
206
+ onIsImageJunk(newJunkState)
207
+ }
208
+
209
+ useEffect(() => {
210
+ // remove current annotations when the image changes
211
+ if (image === undefined) {
212
+ setAnnotations([])
213
+ setSelectedAnnotation(undefined)
214
+ }
215
+ }, [image])
216
+
217
+ useEffect(() => {
218
+ setIsImageJunk(initialIsImageJunk)
219
+
220
+ // update the initial annotations only when the image is not set
221
+ // (the annotations are always loaded before the image)
222
+ // when we dont have any annos, we dont need to call it (prevents render errors on initialization)
223
+ if (
224
+ image !== undefined ||
225
+ initialAnnotations === undefined ||
226
+ initialAnnotations.length === 0
227
+ )
228
+ return
229
+
230
+ createInitialAnnotations()
231
+ }, [initialAnnotations])
232
+
233
+ useEffect(() => {
234
+ setImageLabelIds(initialImageLabelIds)
235
+ }, [initialImageLabelIds])
236
+
237
+ // update annotation settings if changed in the parent
238
+ useEffect(() => {
239
+ const defaultAnnotationSettigs: AnnotationSettings = {
240
+ canCreate: true,
241
+ canEdit: true,
242
+ canHaveMultipleLabels: false,
243
+ canLabel: true,
244
+ minimalArea: 250,
245
+ }
246
+
247
+ // use default values if a key is not set
248
+ const newAnnotationSettings = {
249
+ ...defaultAnnotationSettigs,
250
+ ...propAnnotationSettings,
251
+ }
252
+
253
+ setAnnotationSettings(newAnnotationSettings)
254
+ }, [propAnnotationSettings])
255
+
256
+ useEffect(() => {
257
+ const defaultUiConfig: UiConfig = {
258
+ nodeRadius: 4,
259
+ strokeWidth: 4,
260
+ imageCentered: false,
261
+ }
262
+
263
+ // use default values if a key is not set
264
+ const newUiConfig = {
265
+ ...defaultUiConfig,
266
+ ...propUiConfig,
267
+ }
268
+
269
+ setUiConfig(newUiConfig)
270
+ }, [propUiConfig])
271
+
272
+ // set default allowed tools if user has not specified them
273
+ useEffect(() => {
274
+ const defaultAllowedTools: AllowedTools = {
275
+ bbox: true,
276
+ point: true,
277
+ line: true,
278
+ junk: true,
279
+ polygon: true,
280
+ }
281
+
282
+ if (propAllowedTools === undefined) return setAllowedTools(defaultAllowedTools)
283
+
284
+ setAllowedTools(propAllowedTools)
285
+ }, [propAllowedTools])
286
+
287
+ // useEffect(() => {
288
+ // if (toolbarHeight < 0) return;
289
+
290
+ // setOuterContainerStyle({
291
+ // height: `calc(100% - ${toolbarHeight}px)`,
292
+ // });
293
+ // }, [toolbarHeight]);
294
+
295
+ // useEffect(() => {
296
+ // if (toolbarContainerRef.current === null) return;
297
+ // const { width, height } =
298
+ // toolbarContainerRef.current.getBoundingClientRect();
299
+
300
+ // setToolbarHeight(height + marginBetweenToolbarAndContainerPixels);
301
+ // }, [toolbarContainerRef]);
302
+
303
+ const fullscreenStyle: CSSProperties = {
304
+ position: 'fixed',
305
+ top: 0,
306
+ left: 0,
307
+ zIndex: 6000,
308
+ backgroundColor: '#ffff',
309
+ width: '100%',
310
+ height: '100%',
311
+ padding: 15,
312
+ }
313
+
314
+ const outerContainerStyle: CSSProperties = {
315
+ // use the max available height as a flex child
316
+ flex: '1 1 auto',
317
+ minHeight: 0,
318
+
319
+ // give the max available height to the next child
320
+ display: 'flex',
321
+ flexDirection: 'column',
322
+ }
323
+
324
+ if (allowedTools === undefined)
325
+ return (
326
+ <div className="d-flex justify-content-center">
327
+ <CSpinner color="primary" style={{ width: '5rem', height: '5rem' }} />
328
+ </div>
329
+ )
330
+
331
+ return (
332
+ <div
333
+ style={{
334
+ ...(isFullscreen ? fullscreenStyle : {}),
335
+ // use the max available height as a flex child
336
+ flex: '1 1 auto',
337
+ minHeight: 0,
338
+
339
+ // give the max available height to the next child
340
+ display: 'flex',
341
+ flexDirection: 'column',
342
+ }}
343
+ >
344
+ <div
345
+ ref={toolbarContainerRef}
346
+ style={{
347
+ marginBottom: marginBetweenToolbarAndContainerPixels,
348
+ }}
349
+ >
350
+ <Toolbar
351
+ annotationSettings={annotationSettings}
352
+ allowedTools={allowedTools}
353
+ additionalButtons={additionalButtons}
354
+ isDisabled={isLoading}
355
+ isFullscreen={isFullscreen}
356
+ isImageJunk={isImageJunk}
357
+ imageLabelIds={imageLabelIds}
358
+ possibleLabels={possibleLabels}
359
+ selectedTool={selectedAnnoTool}
360
+ onImageLabelsChanged={(newImageLabelIds: number[]) => {
361
+ setImageLabelIds(newImageLabelIds)
362
+ onImageLabelsChanged(newImageLabelIds)
363
+ }}
364
+ onSetIsFullscreen={setIsFullscreen}
365
+ onSetIsImageJunk={handleImageJunk}
366
+ onSetSelectedTool={setSelectedAnnoTool}
367
+ onShouldDeleteSelectedAnnotation={deleteSelectedAnnotation}
368
+ />
369
+ </div>
370
+ <div style={outerContainerStyle}>
371
+ {isLoading && (
372
+ <div className="d-flex justify-content-center">
373
+ <CSpinner
374
+ color="primary"
375
+ style={{ width: '5rem', height: '5rem', marginTop: 200 }}
376
+ />
377
+ </div>
378
+ )}
379
+
380
+ {image && annotations && (
381
+ <Canvas
382
+ annotations={annotations}
383
+ annotationSettings={annotationSettings}
384
+ defaultLabelId={defaultLabelId}
385
+ image={image}
386
+ isFullscreen={isFullscreen}
387
+ isImageJunk={isImageJunk}
388
+ isPolygonSelectionMode={isPolygonSelectionMode}
389
+ selectedAnnotation={selectedAnnotation}
390
+ selectedAnnoTool={selectedAnnoTool}
391
+ polygonOperationResult={polygonOperationResult}
392
+ possibleLabels={possibleLabels}
393
+ uiConfig={uiConfig}
394
+ onAnnoCreated={(annotation: Annotation) => {
395
+ const _annotations: Annotation[] = [...annotations]
396
+ _annotations.push(annotation)
397
+ setAnnotations(_annotations)
398
+ setSelectedAnnotation(annotation)
399
+ onAnnoCreated(annotation, _annotations)
400
+ }}
401
+ onAnnoChanged={(changedAnno: Annotation) => {
402
+ // update annotation list
403
+ const annoListIndex: number = annotations.findIndex(
404
+ (anno) => anno.internalId === changedAnno.internalId,
405
+ )
406
+
407
+ // only fire event if item found
408
+ if (annoListIndex === -1) return
409
+
410
+ const _annotations: Annotation[] = [...annotations]
411
+ _annotations[annoListIndex] = changedAnno
412
+ setAnnotations(_annotations)
413
+
414
+ // inform the outside world about our change
415
+ onAnnoChanged(changedAnno, _annotations)
416
+ }}
417
+ onAnnoCreationFinished={(
418
+ changedAnno: Annotation,
419
+ hasAnnoJustBeenCreated: boolean,
420
+ ) => {
421
+ // update annotation list
422
+ const _annotations: Annotation[] = [...annotations]
423
+
424
+ // remove the previous annotations we used to do the operation with
425
+ if (isPolygonSelectionMode) {
426
+ if (polygonOperationResult?.annotationsToDelete !== undefined) {
427
+ // we also want to remove the current selected annotation
428
+ polygonOperationResult.annotationsToDelete.push(selectedAnnotation)
429
+
430
+ for (const annotation of polygonOperationResult.annotationsToDelete) {
431
+ // polygonOperationResult.annotationsToDelete.forEach((annotation) => {
432
+ // remove annotations "the official way" (inform the server what we did)
433
+ deleteAnnotationByInternalId(annotation.internalId)
434
+
435
+ // since we are updating the annotations list after all the deletions again, their disappearance wouldn't be noticed
436
+ // therefore also manually remove the annotations here
437
+
438
+ // get index of selected annotation
439
+ const annoListIndex: number = _annotations.findIndex(
440
+ (anno) => anno.internalId === annotation.internalId,
441
+ )
442
+
443
+ // remove annotation from object
444
+ _annotations.splice(annoListIndex, 1)
445
+ }
446
+ }
447
+ }
448
+
449
+ // are we just marking an existing annotation as finished or did we created it in the same frame
450
+ if (hasAnnoJustBeenCreated) _annotations.push(changedAnno)
451
+ else {
452
+ // all other annotation types
453
+ const annoListIndex: number = annotations.findIndex(
454
+ (anno) => anno.internalId === changedAnno.internalId,
455
+ )
456
+ _annotations[annoListIndex] = changedAnno
457
+ }
458
+
459
+ setAnnotations(_annotations)
460
+
461
+ // mark annotation as fully created
462
+ changedAnno.status = AnnotationStatus.CREATED
463
+
464
+ // inform the outer world about our changes
465
+ onAnnoCreationFinished(changedAnno, _annotations)
466
+ }}
467
+ onAnnoEditing={handleAnnoEditing}
468
+ onSetIsImageJunk={handleImageJunk}
469
+ onNotification={onNotification}
470
+ onRequestNewAnnoId={createNewInternalAnnotationId}
471
+ onSelectAnnotation={(annotation) => {
472
+ setSelectedAnnotation(annotation)
473
+ onSelectAnnotation(annotation)
474
+ }}
475
+ onSetSelectedTool={setSelectedAnnoTool}
476
+ onShouldDeleteAnno={deleteAnnotationByInternalId}
477
+ />
478
+ )}
479
+ </div>
480
+ </div>
481
+ )
482
+ }
483
+
484
+ export default Sia2
@@ -1,28 +1,28 @@
1
- import { CCol, CRow } from "@coreui/react";
1
+ import { CCol, CRow } from '@coreui/react'
2
2
 
3
- import AnnoToolSelector from "./ToolbarItems/AnnoToolSelector";
4
- import ImageTools from "./ToolbarItems/ImageTools";
5
- import AnnotationTool from "../models/AnnotationTool";
6
- import AllowedTools from "../models/AllowedTools";
7
- import AccessibilityTools from "./ToolbarItems/AccessibilityTools";
8
- import { ReactElement } from "react";
9
- import AnnotationSettings from "../models/AnnotationSettings";
10
- import Label from "../models/Label";
3
+ import AnnoToolSelector from './ToolbarItems/AnnoToolSelector'
4
+ import ImageTools from './ToolbarItems/ImageTools'
5
+ import AnnotationTool from '../models/AnnotationTool'
6
+ import AccessibilityTools from './ToolbarItems/AccessibilityTools'
7
+ import { ReactElement } from 'react'
8
+ import { AllowedTools, AnnotationSettings, Label } from '../types'
11
9
 
12
10
  type ToolbarProps = {
13
- annotationSettings: AnnotationSettings;
14
- allowedTools: AllowedTools;
15
- additionalButtons: ReactElement | undefined;
16
- isImageJunk?: boolean;
17
- imageLabelIds?: number[];
18
- isDisabled?: boolean;
19
- possibleLabels: Label[];
20
- selectedTool: AnnotationTool;
21
- onImageLabelsChanged?: (selectedImageIds: number[]) => void;
22
- onSetIsImageJunk?: (isImageJunk: boolean) => void;
23
- onSetSelectedTool?: (selectedTool: AnnotationTool) => void;
24
- onShouldDeleteSelectedAnnotation?: () => void;
25
- };
11
+ annotationSettings: AnnotationSettings
12
+ allowedTools: AllowedTools
13
+ additionalButtons?: ReactElement
14
+ isImageJunk?: boolean
15
+ imageLabelIds?: number[]
16
+ isDisabled?: boolean
17
+ isFullscreen?: boolean
18
+ possibleLabels: Label[]
19
+ selectedTool: AnnotationTool
20
+ onImageLabelsChanged?: (selectedImageIds: number[]) => void
21
+ onSetIsFullscreen?: (isFullscreen: boolean) => void
22
+ onSetIsImageJunk?: (isImageJunk: boolean) => void
23
+ onSetSelectedTool?: (selectedTool: AnnotationTool) => void
24
+ onShouldDeleteSelectedAnnotation?: () => void
25
+ }
26
26
 
27
27
  const Toolbar = ({
28
28
  annotationSettings,
@@ -31,33 +31,40 @@ const Toolbar = ({
31
31
  isImageJunk = false,
32
32
  imageLabelIds = [],
33
33
  isDisabled = false,
34
+ isFullscreen = false,
34
35
  possibleLabels,
35
36
  selectedTool,
36
37
  onImageLabelsChanged = () => {},
38
+ onSetIsFullscreen = () => {},
37
39
  onSetIsImageJunk = () => {},
38
40
  onSetSelectedTool = () => {},
39
41
  onShouldDeleteSelectedAnnotation = () => {},
40
42
  }: ToolbarProps) => {
41
43
  return (
42
- <CRow xs={{ gutterY: 2 }}>
43
- <CCol xs={4} sm={2} xxl={1}>
44
+ <CRow className="d-flex justify-content-center flex-wrap align-items-center gap-0 py-2 px-4">
45
+ <CCol xs="auto">
44
46
  <ImageTools
45
47
  canJunk={allowedTools.junk}
46
48
  isImageJunk={isImageJunk}
47
49
  imageLabelIds={imageLabelIds}
48
50
  isDisabled={isDisabled}
51
+ isFullscreen={isFullscreen}
49
52
  possibleLabels={possibleLabels}
50
53
  onImageLabelsChanged={onImageLabelsChanged}
51
54
  onSetIsImageJunk={onSetIsImageJunk}
52
55
  />
53
56
  </CCol>
54
57
 
55
- <CCol xs={2} sm={1}>
56
- <AccessibilityTools isDisabled={isDisabled} />
58
+ <CCol xs="auto">
59
+ <AccessibilityTools
60
+ isDisabled={isDisabled}
61
+ isFullscreen={isFullscreen}
62
+ onSetIsFullscreen={onSetIsFullscreen}
63
+ />
57
64
  </CCol>
58
65
 
59
66
  {annotationSettings.canCreate && (
60
- <CCol xs={8} sm={5} md={4} xl={3} xxl={3}>
67
+ <CCol xs="auto">
61
68
  <AnnoToolSelector
62
69
  allowedTools={allowedTools}
63
70
  isDisabled={isDisabled}
@@ -68,9 +75,9 @@ const Toolbar = ({
68
75
  </CCol>
69
76
  )}
70
77
 
71
- {additionalButtons && additionalButtons}
78
+ {additionalButtons}
72
79
  </CRow>
73
- );
74
- };
80
+ )
81
+ }
75
82
 
76
- export default Toolbar;
83
+ export default Toolbar
@@ -1,69 +1,49 @@
1
- import { CButton, CButtonGroup } from "@coreui/react";
2
- import {
3
- faCog,
4
- faFilter,
5
- faMaximize,
6
- faQuestion,
7
- } from "@fortawesome/free-solid-svg-icons";
8
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
9
- import { IconProp } from "@fortawesome/fontawesome-svg-core";
10
- import { useState } from "react";
11
- import InstructionsModal from "./InstructionsModal";
1
+ import { CButtonGroup } from '@coreui/react'
2
+ import { faMaximize, faQuestion } from '@fortawesome/free-solid-svg-icons'
3
+ import { useState } from 'react'
4
+ import InstructionsModal from './InstructionsModal'
5
+ import IconButton from '../../IconButton'
12
6
 
13
7
  type AccessibilityToolsProps = {
14
- isDisabled?: boolean;
15
- };
8
+ isDisabled?: boolean
9
+ isFullscreen?: boolean
10
+ onSetIsFullscreen?: (isFullscreen: boolean) => void
11
+ }
16
12
 
17
13
  const AccessibilityTools = ({
18
14
  isDisabled = false,
15
+ isFullscreen = false,
16
+ onSetIsFullscreen = () => {},
19
17
  }: AccessibilityToolsProps) => {
20
18
  const [isInstructionsModalVisible, setIsInstructionsModalVisible] =
21
- useState<boolean>(false);
19
+ useState<boolean>(false)
22
20
 
23
21
  return (
24
22
  <CButtonGroup role="group" aria-label="Basic example">
25
- {/* <CButton
23
+ <IconButton
26
24
  color="primary"
25
+ icon={faMaximize}
26
+ isOutline={!isFullscreen}
27
27
  disabled={isDisabled}
28
- variant="outline"
29
- onClick={() => {}}
30
- >
31
- <FontAwesomeIcon icon={faFilter as IconProp} size="lg" />
32
- </CButton> */}
33
-
34
- {/* <CButton
35
- color="primary"
36
- disabled={isDisabled}
37
- variant="outline"
38
- onClick={() => {}}
39
- >
40
- <FontAwesomeIcon icon={faMaximize as IconProp} size="lg" />
41
- </CButton>
42
-
43
- <CButton
44
- color="primary"
45
- disabled={isDisabled}
46
- variant="outline"
47
- onClick={() => {}}
48
- >
49
- <FontAwesomeIcon icon={faCog as IconProp} size="lg" />
50
- </CButton> */}
28
+ onClick={() => onSetIsFullscreen(!isFullscreen)}
29
+ tooltip="Toggle fullscreen"
30
+ />
51
31
 
52
- <CButton
32
+ <IconButton
53
33
  color="primary"
34
+ icon={faQuestion}
35
+ isOutline={true}
54
36
  disabled={isDisabled}
55
- variant="outline"
56
37
  onClick={() => setIsInstructionsModalVisible(true)}
57
- >
58
- <FontAwesomeIcon icon={faQuestion as IconProp} size="lg" />
59
- </CButton>
38
+ tooltip="Open instructions"
39
+ />
60
40
 
61
41
  <InstructionsModal
62
42
  isOpen={isInstructionsModalVisible}
63
43
  setIsOpen={setIsInstructionsModalVisible}
64
44
  />
65
45
  </CButtonGroup>
66
- );
67
- };
46
+ )
47
+ }
68
48
 
69
- export default AccessibilityTools;
49
+ export default AccessibilityTools