@searpent/react-image-annotate 2.0.75 → 2.0.77

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 +899 -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/{Editor → src/Editor}/annotation-plugin/annotation.css +20 -0
  41. package/src/Editor/annotation-plugin/annotation.js +546 -0
  42. package/src/Editor/index.js +50 -0
  43. package/src/Editor/readOnly.js +31 -0
  44. package/{Editor → src/Editor}/tools.js +3 -2
  45. package/src/Errorer/index.js +13 -0
  46. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  47. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  48. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  49. package/src/FullImageSegmentationAnnotator/index.js +7 -0
  50. package/src/FullImageSegmentationAnnotator/index.story.js +177 -0
  51. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  52. package/src/GroupSelectorSidebarBox/index.js +48 -0
  53. package/src/GroupsEditorSidebarBox/index.js +108 -0
  54. package/src/HelpSidebarBox/index.js +43 -0
  55. package/src/HighlightBox/index.js +143 -0
  56. package/src/HistorySidebarBox/index.js +78 -0
  57. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  58. package/src/ImageCanvas/index.js +515 -0
  59. package/src/ImageCanvas/index.story.js +314 -0
  60. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  61. package/src/ImageCanvas/region-tools.js +171 -0
  62. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  63. package/{ImageCanvas → src/ImageCanvas}/styles.js +8 -12
  64. package/src/ImageCanvas/use-mouse.js +168 -0
  65. package/src/ImageCanvas/use-project-box.js +23 -0
  66. package/src/ImageCanvas/use-wasd-mode.js +50 -0
  67. package/src/ImageMask/index.js +127 -0
  68. package/src/ImageMask/load-image.js +32 -0
  69. package/src/ImageSelectorSidebarBox/index.js +54 -0
  70. package/src/KeyframeTimeline/get-time-string.js +25 -0
  71. package/src/KeyframeTimeline/index.js +223 -0
  72. package/src/KeyframesSelectorSidebarBox/index.js +93 -0
  73. package/src/LandingPage/content.md +57 -0
  74. package/src/LandingPage/github-markdown.css +964 -0
  75. package/src/LandingPage/index.js +147 -0
  76. package/src/Locker/index.js +13 -0
  77. package/src/MainLayout/RightSidebarItemsWrapper.js +21 -0
  78. package/src/MainLayout/icon-dictionary.js +79 -0
  79. package/src/MainLayout/index.js +564 -0
  80. package/src/MainLayout/index.story.js +240 -0
  81. package/{MainLayout → src/MainLayout}/styles.js +7 -6
  82. package/src/MainLayout/types.js +171 -0
  83. package/src/MainLayout/use-implied-video-regions.js +17 -0
  84. package/src/MetadataEditorSidebarBox/index.js +160 -0
  85. package/src/PageSelector/index.js +159 -0
  86. package/src/PointDistances/index.js +90 -0
  87. package/src/PreventScrollToParents/index.js +48 -0
  88. package/src/PreventScrollToParents/index.story.js +23 -0
  89. package/src/RegionLabel/index.js +236 -0
  90. package/{RegionLabel → src/RegionLabel}/styles.js +15 -12
  91. package/src/RegionSelectAndTransformBoxes/index.js +236 -0
  92. package/src/RegionSelectorSidebarBox/index.js +220 -0
  93. package/{RegionSelectorSidebarBox → src/RegionSelectorSidebarBox}/styles.js +14 -13
  94. package/src/RegionShapes/index.js +254 -0
  95. package/src/RegionTags/index.js +136 -0
  96. package/src/SettingsDialog/index.js +58 -0
  97. package/src/SettingsProvider/index.js +57 -0
  98. package/src/Shortcuts/ShortcutField.js +44 -0
  99. package/src/Shortcuts/index.js +129 -0
  100. package/src/ShortcutsManager/index.js +162 -0
  101. package/src/Sidebar/index.js +117 -0
  102. package/src/SidebarBoxContainer/index.js +93 -0
  103. package/src/SmallToolButton/index.js +57 -0
  104. package/src/TagsSidebarBox/index.js +93 -0
  105. package/src/TaskDescriptionSidebarBox/index.js +43 -0
  106. package/src/Theme/index.js +36 -0
  107. package/src/VideoOrImageCanvasBackground/index.js +170 -0
  108. package/src/colors.js +32 -0
  109. package/src/hooks/use-colors.js +95 -0
  110. package/src/hooks/use-event-callback.js +11 -0
  111. package/src/hooks/use-exclude-pattern.js +27 -0
  112. package/src/hooks/use-load-image.js +21 -0
  113. package/src/hooks/use-window-size.js +46 -0
  114. package/{hooks → src/hooks}/xpattern.js +1 -1
  115. package/src/hooks/xpattern.png +0 -0
  116. package/src/index.js +18 -0
  117. package/src/lib.js +7 -0
  118. package/src/screenshot.png +0 -0
  119. package/src/site.css +5 -0
  120. package/src/stories.js +2 -0
  121. package/src/utils/blocks-to-article.js +61 -0
  122. package/{utils → src/utils}/blocks-to-article.test.js +8 -5
  123. package/{utils → src/utils}/default-locked-until.js +1 -2
  124. package/{utils → src/utils}/filter-only-unique.js +1 -1
  125. package/src/utils/get-from-local-storage.js +7 -0
  126. package/src/utils/get-hotkey-help-text.js +11 -0
  127. package/src/utils/get-landmarks-with-transform.js +23 -0
  128. package/src/utils/photosToImages.js +67 -0
  129. package/src/utils/regions-groups.js +19 -0
  130. package/src/utils/regions-to-blocks.js +16 -0
  131. package/src/utils/saveable-actions-enum.js +5 -0
  132. package/src/utils/set-in-local-storage.js +6 -0
  133. package/src/utils/sleep.js +3 -0
  134. package/src/utils/uuid-to-hash.js +5 -0
  135. package/Annotator/exampleImages.js +0 -41
  136. package/Annotator/examplePhotos.js +0 -6980
  137. package/Annotator/index.js +0 -417
  138. package/Annotator/reducers/combine-reducers.js +0 -14
  139. package/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -73
  140. package/Annotator/reducers/general-reducer.js +0 -1430
  141. package/Annotator/reducers/get-active-image.js +0 -27
  142. package/Annotator/reducers/get-implied-video-regions.js +0 -180
  143. package/Annotator/reducers/history-handler.js +0 -38
  144. package/Annotator/reducers/image-reducer.js +0 -20
  145. package/Annotator/reducers/video-reducer.js +0 -88
  146. package/ClassSelectionMenu/index.js +0 -140
  147. package/Crosshairs/index.js +0 -53
  148. package/DebugSidebarBox/index.js +0 -20
  149. package/DemoSite/Editor.js +0 -194
  150. package/DemoSite/ErrorBoundaryDialog.js +0 -64
  151. package/DemoSite/index.js +0 -40
  152. package/Editor/annotation-plugin/annotation.js +0 -647
  153. package/Editor/index.js +0 -93
  154. package/Editor/readOnly.js +0 -73
  155. package/Errorer/index.js +0 -11
  156. package/FullImageSegmentationAnnotator/index.js +0 -7
  157. package/GroupSelectorSidebarBox/index.js +0 -63
  158. package/GroupsEditorSidebarBox/index.js +0 -138
  159. package/HelpSidebarBox/index.js +0 -58
  160. package/HighlightBox/index.js +0 -102
  161. package/HistorySidebarBox/index.js +0 -71
  162. package/ImageCanvas/index.js +0 -441
  163. package/ImageCanvas/region-tools.js +0 -165
  164. package/ImageCanvas/use-mouse.js +0 -180
  165. package/ImageCanvas/use-project-box.js +0 -27
  166. package/ImageCanvas/use-wasd-mode.js +0 -62
  167. package/ImageMask/index.js +0 -133
  168. package/ImageMask/load-image.js +0 -25
  169. package/ImageSelectorSidebarBox/index.js +0 -60
  170. package/KeyframeTimeline/get-time-string.js +0 -27
  171. package/KeyframeTimeline/index.js +0 -233
  172. package/KeyframesSelectorSidebarBox/index.js +0 -93
  173. package/LandingPage/index.js +0 -159
  174. package/Locker/index.js +0 -11
  175. package/MainLayout/RightSidebarItemsWrapper.js +0 -19
  176. package/MainLayout/icon-dictionary.js +0 -104
  177. package/MainLayout/index.js +0 -526
  178. package/MainLayout/types.js +0 -0
  179. package/MainLayout/use-implied-video-regions.js +0 -13
  180. package/MetadataEditorSidebarBox/index.js +0 -231
  181. package/PageSelector/index.js +0 -180
  182. package/PointDistances/index.js +0 -73
  183. package/PreventScrollToParents/index.js +0 -51
  184. package/RegionLabel/index.js +0 -232
  185. package/RegionSelectAndTransformBoxes/index.js +0 -169
  186. package/RegionSelectorSidebarBox/index.js +0 -254
  187. package/RegionShapes/index.js +0 -294
  188. package/RegionTags/index.js +0 -144
  189. package/SettingsDialog/index.js +0 -52
  190. package/SettingsProvider/index.js +0 -60
  191. package/Shortcuts/ShortcutField.js +0 -46
  192. package/Shortcuts/index.js +0 -133
  193. package/ShortcutsManager/index.js +0 -155
  194. package/Sidebar/index.js +0 -69
  195. package/SidebarBoxContainer/index.js +0 -93
  196. package/SmallToolButton/index.js +0 -42
  197. package/TagsSidebarBox/index.js +0 -105
  198. package/TaskDescriptionSidebarBox/index.js +0 -58
  199. package/Theme/index.js +0 -30
  200. package/VideoOrImageCanvasBackground/index.js +0 -151
  201. package/colors.js +0 -14
  202. package/hooks/use-colors.js +0 -97
  203. package/hooks/use-event-callback.js +0 -10
  204. package/hooks/use-exclude-pattern.js +0 -24
  205. package/hooks/use-load-image.js +0 -26
  206. package/hooks/use-window-size.js +0 -46
  207. package/index.js +0 -3
  208. package/lib.js +0 -3
  209. package/stories.js +0 -5
  210. package/utils/blocks-to-article.js +0 -60
  211. package/utils/get-from-local-storage.js +0 -7
  212. package/utils/get-hotkey-help-text.js +0 -9
  213. package/utils/get-landmarks-with-transform.js +0 -40
  214. package/utils/photosToImages.js +0 -85
  215. package/utils/regions-groups.js +0 -28
  216. package/utils/regions-to-blocks.js +0 -18
  217. package/utils/saveable-actions-enum.js +0 -3
  218. package/utils/set-in-local-storage.js +0 -3
  219. package/utils/sleep.js +0 -7
  220. package/utils/uuid-to-hash.js +0 -5
  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,170 @@
1
+ // @flow weak
2
+
3
+ import React, { useRef, useEffect, useMemo, useState } from "react"
4
+ import { styled } from "@mui/material/styles"
5
+ import { createTheme, ThemeProvider } from "@mui/material/styles"
6
+ import useEventCallback from "use-event-callback"
7
+ import { useSettings } from "../SettingsProvider"
8
+
9
+ const theme = createTheme()
10
+ const Video = styled("video")(({ theme }) => ({
11
+ zIndex: 0,
12
+ position: "absolute",
13
+ }))
14
+
15
+ const StyledImage = styled("img")(({ theme }) => ({
16
+ zIndex: 0,
17
+ position: "absolute",
18
+ }))
19
+
20
+ const Error = styled("div")(({ theme }) => ({
21
+ zIndex: 0,
22
+ position: "absolute",
23
+ left: 0,
24
+ right: 0,
25
+ bottom: 0,
26
+ top: 0,
27
+ backgroundColor: "rgba(255,0,0,0.2)",
28
+ color: "#ff0000",
29
+ fontWeight: "bold",
30
+ whiteSpace: "pre-wrap",
31
+ padding: 50,
32
+ }))
33
+
34
+ export default ({
35
+ imagePosition,
36
+ mouseEvents,
37
+ videoTime,
38
+ videoSrc,
39
+ imageSrc,
40
+ onLoad,
41
+ useCrossOrigin = false,
42
+ videoPlaying,
43
+ onChangeVideoTime,
44
+ onChangeVideoPlaying,
45
+ }) => {
46
+ const settings = useSettings()
47
+ const videoRef = useRef()
48
+ const imageRef = useRef()
49
+ const [error, setError] = useState()
50
+
51
+ useEffect(() => {
52
+ if (!videoPlaying && videoRef.current) {
53
+ videoRef.current.currentTime = (videoTime || 0) / 1000
54
+ }
55
+ }, [videoTime])
56
+
57
+ useEffect(() => {
58
+ let renderLoopRunning = false
59
+ if (videoRef.current) {
60
+ if (videoPlaying) {
61
+ videoRef.current.play()
62
+ renderLoopRunning = true
63
+ if (settings.videoPlaybackSpeed) {
64
+ videoRef.current.playbackRate = parseFloat(
65
+ settings.videoPlaybackSpeed
66
+ )
67
+ }
68
+ } else {
69
+ videoRef.current.pause()
70
+ }
71
+ }
72
+
73
+ function checkForNewFrame() {
74
+ if (!renderLoopRunning) return
75
+ if (!videoRef.current) return
76
+ const newVideoTime = Math.floor(videoRef.current.currentTime * 1000)
77
+ if (videoTime !== newVideoTime) {
78
+ onChangeVideoTime(newVideoTime)
79
+ }
80
+ if (videoRef.current.paused) {
81
+ renderLoopRunning = false
82
+ onChangeVideoPlaying(false)
83
+ }
84
+ requestAnimationFrame(checkForNewFrame)
85
+ }
86
+ checkForNewFrame()
87
+
88
+ return () => {
89
+ renderLoopRunning = false
90
+ }
91
+ }, [videoPlaying])
92
+
93
+ const onLoadedVideoMetadata = useEventCallback((event) => {
94
+ const videoElm = event.currentTarget
95
+ videoElm.currentTime = (videoTime || 0) / 1000
96
+ if (onLoad)
97
+ onLoad({
98
+ naturalWidth: videoElm.videoWidth,
99
+ naturalHeight: videoElm.videoHeight,
100
+ videoElm: videoElm,
101
+ duration: videoElm.duration,
102
+ })
103
+ })
104
+ const onImageLoaded = useEventCallback((event) => {
105
+ const imageElm = event.currentTarget
106
+ if (onLoad)
107
+ onLoad({
108
+ naturalWidth: imageElm.naturalWidth,
109
+ naturalHeight: imageElm.naturalHeight,
110
+ imageElm,
111
+ })
112
+ })
113
+ const onImageError = useEventCallback((event) => {
114
+ setError(
115
+ `Could not load image\n\nMake sure your image works by visiting ${
116
+ imageSrc || videoSrc
117
+ } in a web browser. If that URL works, the server hosting the URL may be not allowing you to access the image from your current domain. Adjust server settings to enable the image to be viewed.${
118
+ !useCrossOrigin
119
+ ? ""
120
+ : `\n\nYour image may be blocked because it's not being sent with CORs headers. To do pixel segmentation, browser web security requires CORs headers in order for the algorithm to read the pixel data from the image. CORs headers are easy to add if you're using an S3 bucket or own the server hosting your images.`
121
+ }\n\n If you need a hand, reach out to the community at universaldatatool.slack.com`
122
+ )
123
+ })
124
+
125
+ const stylePosition = useMemo(() => {
126
+ let width = imagePosition.bottomRight.x - imagePosition.topLeft.x
127
+ let height = imagePosition.bottomRight.y - imagePosition.topLeft.y
128
+ return {
129
+ imageRendering: "pixelated",
130
+ left: imagePosition.topLeft.x,
131
+ top: imagePosition.topLeft.y,
132
+ width: isNaN(width) ? 0 : width,
133
+ height: isNaN(height) ? 0 : height,
134
+ }
135
+ }, [
136
+ imagePosition.topLeft.x,
137
+ imagePosition.topLeft.y,
138
+ imagePosition.bottomRight.x,
139
+ imagePosition.bottomRight.y,
140
+ ])
141
+
142
+ if (!videoSrc && !imageSrc)
143
+ return <Error>No imageSrc or videoSrc provided</Error>
144
+
145
+ if (error) return <Error>{error}</Error>
146
+
147
+ return (
148
+ <ThemeProvider theme={theme}>
149
+ {imageSrc && videoTime === undefined ? (
150
+ <StyledImage
151
+ {...mouseEvents}
152
+ src={imageSrc}
153
+ ref={imageRef}
154
+ style={stylePosition}
155
+ onLoad={onImageLoaded}
156
+ onError={onImageError}
157
+ crossOrigin={useCrossOrigin ? "anonymous" : undefined}
158
+ />
159
+ ) : (
160
+ <Video
161
+ {...mouseEvents}
162
+ ref={videoRef}
163
+ style={stylePosition}
164
+ onLoadedMetadata={onLoadedVideoMetadata}
165
+ src={videoSrc || imageSrc}
166
+ />
167
+ )}
168
+ </ThemeProvider>
169
+ )
170
+ }
package/src/colors.js ADDED
@@ -0,0 +1,32 @@
1
+ // @flow
2
+
3
+ import * as muiColors from "@mui/material/colors"
4
+
5
+ export const colors = [
6
+ muiColors.red[500],
7
+ muiColors.blue[500],
8
+ muiColors.green[500],
9
+ muiColors.orange[800],
10
+ muiColors.brown[500],
11
+ muiColors.lightGreen[700],
12
+ muiColors.pink[500],
13
+ muiColors.purple[500],
14
+ muiColors.indigo[500],
15
+ muiColors.teal[500],
16
+ muiColors.lime[500],
17
+ muiColors.blueGrey[500],
18
+ ]
19
+
20
+ const transparency = 0x88000000
21
+
22
+ function reverseParseColor(rrggbb) {
23
+ rrggbb = rrggbb.replace("#", "")
24
+ const bbggrr = rrggbb.substr(4, 2) + rrggbb.substr(2, 2) + rrggbb.substr(0, 2)
25
+ return parseInt(bbggrr, 16)
26
+ }
27
+
28
+ export const colorInts: Array<number> = colors.map(
29
+ (c) => (reverseParseColor(c) | transparency) >>> 0
30
+ )
31
+
32
+ export default colors
@@ -0,0 +1,95 @@
1
+ import { useSettings } from "../SettingsProvider"
2
+
3
+ const DEFAULT_GROUP_COLOR = "#32CD32";
4
+
5
+ function defaultClsColor(cls) {
6
+ switch (cls) {
7
+ case 'title':
8
+ return '#f70202'
9
+ case 'subtitle':
10
+ return "#ffb405"
11
+ case 'text':
12
+ return "#14deef"
13
+ case 'author':
14
+ return "#f8d51e"
15
+ case 'appendix':
16
+ return "#bfede2"
17
+ case 'photo_author':
18
+ return "#9a17bb"
19
+ case 'photo_caption':
20
+ return "#ff84f6"
21
+ case 'advertisement':
22
+ return "#ffb201"
23
+ case 'other_graphics':
24
+ return "#ff5400"
25
+ case 'unknown':
26
+ return "#bfede2"
27
+ case 'about_author':
28
+ return "#9a17bb"
29
+ case 'image':
30
+ return "#14deef"
31
+ case 'interview':
32
+ return "#23b20f"
33
+ case 'table':
34
+ return "#02b4ba"
35
+ case 'section':
36
+ return "#ffcccc"
37
+ case 'continuation_ref':
38
+ return '#FF33CC'
39
+ case 'cover_clip':
40
+ return '#669966'
41
+ case 'page_id':
42
+ return '#4433AA'
43
+ case 'continuation_mark':
44
+ return '#660066'
45
+ case 'follow_up_mark':
46
+ return '#873e23'
47
+ case 'article_termination_mark':
48
+ return '#873e23'
49
+ case 'page_splitting_stripe':
50
+ return '#873e23'
51
+ case 'column_id_stripe':
52
+ return '#873e23'
53
+ case 'prev_page_reference':
54
+ return '#f3a864'
55
+ case 'section_subcategory':
56
+ return '#442c55'
57
+ default:
58
+ return "#02b4ba"
59
+ }
60
+ }
61
+
62
+ function stringToNumber(str) {
63
+ let sum = 0
64
+ for (let index = 0; index < str.length; index++) {
65
+ sum += str.charCodeAt(index)
66
+
67
+ }
68
+ return sum
69
+ }
70
+
71
+ const useColors = () => {
72
+ const { clsColors, groupColors } = useSettings()
73
+
74
+ const clsColor = (cls) => {
75
+ if (!clsColors) { return DEFAULT_GROUP_COLOR }
76
+ if (clsColors[cls]) { return clsColors[cls] }
77
+ return defaultClsColor(cls)
78
+ }
79
+
80
+ const groupColor = (idx) => {
81
+ if (isNaN(idx)) {
82
+ return groupColors[stringToNumber(idx) % groupColors.length] || DEFAULT_GROUP_COLOR
83
+ } else {
84
+ return groupColors[idx % groupColors.length] || DEFAULT_GROUP_COLOR
85
+ }
86
+
87
+ }
88
+
89
+ return {
90
+ clsColor,
91
+ groupColor
92
+ }
93
+ }
94
+
95
+ export default useColors;
@@ -0,0 +1,11 @@
1
+ // @flow
2
+
3
+ import { useRef, useCallback, useLayoutEffect, useEffect } from "react"
4
+
5
+ export default (fn) => {
6
+ let ref = useRef()
7
+ useLayoutEffect(() => {
8
+ ref.current = fn
9
+ })
10
+ return useCallback((...args) => (0, ref.current)(...args), [])
11
+ }
@@ -0,0 +1,27 @@
1
+ // @flow weak
2
+
3
+ import { useRef } from "react"
4
+ import excludePatternSrc from "./xpattern.js"
5
+
6
+ export default () => {
7
+ const excludePattern = useRef(null)
8
+ if (excludePattern.current === null) {
9
+ excludePattern.current = {
10
+ image: new Image(),
11
+ pattern: null,
12
+ }
13
+ const canvas = document.createElement("canvas")
14
+ canvas.width = 100
15
+ canvas.height = 100
16
+ const context = canvas.getContext("2d")
17
+
18
+ excludePattern.current.image.onload = () => {
19
+ excludePattern.current.pattern = context.createPattern(
20
+ excludePattern.current.image,
21
+ "repeat"
22
+ )
23
+ }
24
+ excludePattern.current.image.src = excludePatternSrc
25
+ }
26
+ return excludePattern.current.pattern
27
+ }
@@ -0,0 +1,21 @@
1
+ // @flow weak
2
+
3
+ import { useRef, useState } from "react"
4
+
5
+ export default (imageSrc, onImageLoaded) => {
6
+ const [imageLoaded, changeImageLoaded] = useState(false)
7
+ const image = useRef(null)
8
+ if (image.current === null) {
9
+ image.current = new Image()
10
+ image.current.onload = () => {
11
+ changeImageLoaded(true)
12
+ if (onImageLoaded)
13
+ onImageLoaded({
14
+ width: image.current.naturalWidth,
15
+ height: image.current.naturalHeight,
16
+ })
17
+ }
18
+ image.current.src = imageSrc
19
+ }
20
+ return [image.current, imageLoaded]
21
+ }
@@ -0,0 +1,46 @@
1
+ // @flow
2
+
3
+ import { useEffect } from "react"
4
+
5
+ import { useRafState, useInterval } from "react-use"
6
+
7
+ const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
8
+ const isClient = typeof window !== "undefined"
9
+ const [state, setState] = useRafState({
10
+ width: isClient ? window.innerWidth : initialWidth,
11
+ height: isClient ? window.innerHeight : initialHeight,
12
+ })
13
+
14
+ useEffect(() => {
15
+ if (!isClient) return
16
+ const handler = () => {
17
+ setState({
18
+ width: window.innerWidth,
19
+ height: window.innerHeight,
20
+ })
21
+ }
22
+
23
+ window.addEventListener("resize", handler)
24
+
25
+ return () => {
26
+ window.removeEventListener("resize", handler)
27
+ }
28
+ }, [])
29
+
30
+ useInterval(() => {
31
+ if (!isClient) return
32
+ if (
33
+ window.innerWidth !== state.width ||
34
+ window.innerHeight !== state.height
35
+ ) {
36
+ setState({
37
+ width: window.innerWidth,
38
+ height: window.innerHeight,
39
+ })
40
+ }
41
+ }, 100)
42
+
43
+ return state
44
+ }
45
+
46
+ export default useWindowSize
@@ -1 +1 @@
1
- export default "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4wMSAxY5oG+lzgAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAcSURBVAjXY/jPwPCfAQnA+TAGugLcAhhakRUAAK3lEe8m9qZhAAAAAElFTkSuQmCC";
1
+ export default `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4wMSAxY5oG+lzgAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAcSURBVAjXY/jPwPCfAQnA+TAGugLcAhhakRUAAK3lEe8m9qZhAAAAAElFTkSuQmCC`
Binary file
package/src/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // @flow
2
+
3
+ import React from "react"
4
+ import ReactDOM from "react-dom"
5
+ import Theme from "./Theme"
6
+ import DemoSite from "./DemoSite"
7
+ import LandingPage from "./LandingPage"
8
+ import "./site.css"
9
+
10
+ const Site = () => {
11
+ const path = window.location.pathname
12
+ .replace(/\/$/, "")
13
+ .split("/")
14
+ .slice(-1)[0]
15
+ return <Theme>{path === "demo" ? <DemoSite /> : <LandingPage />}</Theme>
16
+ }
17
+
18
+ ReactDOM.render(<Site />, document.getElementById("root"))
package/src/lib.js ADDED
@@ -0,0 +1,7 @@
1
+ // @flow
2
+
3
+ import Annotator from "./Annotator"
4
+
5
+ export { Annotator }
6
+
7
+ export default Annotator
Binary file
package/src/site.css ADDED
@@ -0,0 +1,5 @@
1
+ html,
2
+ body {
3
+ padding: 0;
4
+ margin: 0;
5
+ }
package/src/stories.js ADDED
@@ -0,0 +1,2 @@
1
+ const importAll = (r) => r.keys().map(r)
2
+ importAll(require.context("./", true, /\.story\.js$/))
@@ -0,0 +1,61 @@
1
+ import { whitespaceCharactersToHTML } from '../Editor/annotation-plugin/annotation';
2
+
3
+ function sanitizedText(text) {
4
+ const escapedWhitespaces = whitespaceCharactersToHTML(text);
5
+
6
+ // remove whitespaces
7
+ const trimmed = escapedWhitespaces.trim();
8
+
9
+ // replace dashes at the end of sentence
10
+ const noTrailingDash = trimmed.replace(/-$/, "")
11
+
12
+ return noTrailingDash;
13
+ }
14
+
15
+ function getConnectingSymbol(labelName) {
16
+ switch (labelName) {
17
+ case 'text':
18
+ return "";
19
+ case 'appendix':
20
+ return "<br><br>"
21
+ default:
22
+ return "<br>"
23
+ }
24
+ }
25
+
26
+ function blocksToArticle(blocks) {
27
+ const renamedBlocks = blocks.map(b => {
28
+ const newBlock = {
29
+ ...b, data: {
30
+ ...b.data,
31
+ labelName: b.data.labelName === 'interview' ? 'text' : b.data.labelName
32
+ }
33
+ }
34
+ return newBlock
35
+ })
36
+
37
+ const article = renamedBlocks.reduce((acc, curr) => {
38
+ const { labelName, text } = curr?.data;
39
+ if (acc[labelName] === undefined) {
40
+ acc[labelName] = ""
41
+ }
42
+
43
+ let connectingSymbol = getConnectingSymbol(labelName);
44
+
45
+ // if last symbol is dot, next sentence should start with space
46
+ if (acc[labelName].charAt(acc[labelName].length - 1) === "." && connectingSymbol === "") {
47
+ connectingSymbol = " "
48
+ }
49
+
50
+ acc[labelName] = acc[labelName] + connectingSymbol + sanitizedText(text);
51
+
52
+ return acc;
53
+ }, {
54
+ title: "",
55
+ text: ""
56
+ })
57
+
58
+ return article;
59
+ }
60
+
61
+ export default blocksToArticle;
@@ -1,5 +1,6 @@
1
1
  import blocksToArticle from "./blocks-to-article";
2
- var blocks = [{
2
+
3
+ const blocks = [{
3
4
  id: "a1",
4
5
  type: "annotation",
5
6
  data: {
@@ -44,11 +45,13 @@ var blocks = [{
44
45
  labelName: "text",
45
46
  text: "potamus is a big animal."
46
47
  }
47
- }];
48
- test('blocksToArticle', function () {
49
- var article = blocksToArticle(blocks);
48
+ }]
49
+
50
+ test('blocksToArticle', () => {
51
+ const article = blocksToArticle(blocks);
50
52
  expect(article).toEqual({
51
53
  title: "Tohle je jeden kus title.",
52
54
  text: "First part of text. First part of interview. Second part of text. Hippopotamus is a big animal."
53
55
  });
54
- });
56
+ });
57
+
@@ -1,6 +1,5 @@
1
1
  export default function defaultLockedUntil() {
2
2
  var now = new Date();
3
3
  now.setDate(now.getDate() + 1); // Add 1 day to current date
4
-
5
- return now;
4
+ return now
6
5
  }
@@ -2,4 +2,4 @@ function onlyUnique(value, index, self) {
2
2
  return self.indexOf(value) === index;
3
3
  }
4
4
 
5
- export default onlyUnique;
5
+ export default onlyUnique;
@@ -0,0 +1,7 @@
1
+ export default (key, defaultValue) => {
2
+ try {
3
+ return JSON.parse(window.localStorage[`__REACT_IMAGE_ANNOTATE_${key}`])
4
+ } catch (e) {
5
+ return defaultValue
6
+ }
7
+ }
@@ -0,0 +1,11 @@
1
+ import { getApplicationKeyMap } from "react-hotkeys"
2
+
3
+ export const getHotkeyHelpText = (commandName) => {
4
+ const firstSequence =
5
+ getApplicationKeyMap()[commandName]?.sequences?.[0]?.sequence
6
+
7
+ if (!firstSequence) return ""
8
+ return ` (${firstSequence})`
9
+ }
10
+
11
+ export default getHotkeyHelpText
@@ -0,0 +1,23 @@
1
+ // @flow
2
+ import type { KeypointDefinition } from "../ImageCanvas/region-tools"
3
+
4
+ type Parameters = {
5
+ center: { x: number, y: number },
6
+ scale: number,
7
+ landmarks: {
8
+ [string]: KeypointDefinition,
9
+ },
10
+ }
11
+
12
+ export default ({ center, scale, landmarks }: Parameters) => {
13
+ const points = {}
14
+ for (const [keypointId, { defaultPosition }] of (Object.entries(
15
+ landmarks
16
+ ): any)) {
17
+ points[keypointId] = {
18
+ x: defaultPosition[0] * scale + center.x,
19
+ y: defaultPosition[1] * scale + center.y,
20
+ }
21
+ }
22
+ return points
23
+ }
@@ -0,0 +1,67 @@
1
+ function labelAndTextFromResultText(resultText) {
2
+ if (!resultText) { return {} }
3
+ const parsedResultText = JSON.parse(resultText);
4
+ const label = parsedResultText[0].label;
5
+ const text = parsedResultText[0].text;
6
+ return { label, text }
7
+ }
8
+
9
+ function extractionEngineModelResultsToRegions(modelResults) {
10
+ return modelResults.map(r => {
11
+ const { label, text } = labelAndTextFromResultText(r.text);
12
+ return {
13
+ id: r.id,
14
+ type: "box",
15
+ visible: r.label === 'metadata' ? false : true,
16
+ cls: label,
17
+ highlighted: false,
18
+ groupHighlighted: false,
19
+ x: r.box.X1,
20
+ y: r.box.Y1,
21
+ w: r.box.X2 - r.box.X1,
22
+ h: r.box.Y2 - r.box.Y1,
23
+ groupId: r.groupId,
24
+ text: text,
25
+ }
26
+ })
27
+ }
28
+
29
+ function metadataEngineModelResultsToRegions(modelResults) {
30
+ return modelResults.map(r => {
31
+ return {
32
+ id: r.id,
33
+ type: "box",
34
+ visible: false,
35
+ cls: "metadata",
36
+ highlighted: false,
37
+ groupHighlighted: false,
38
+ x: r.box.X1,
39
+ y: r.box.Y1,
40
+ w: r.box.X2 - r.box.X1,
41
+ h: r.box.Y2 - r.box.Y1,
42
+ groupId: r.groupId,
43
+ text: r.text,
44
+ }
45
+ })
46
+ }
47
+
48
+
49
+ function modelResultsToRegions(modelResults) {
50
+ const extractionEngineRegions = extractionEngineModelResultsToRegions(modelResults.find(mr => mr.name === 'extraction-engine')?.results || [])
51
+ const metadataEngineRegions = metadataEngineModelResultsToRegions(modelResults.find(mr => mr.name === 'metadata-engine')?.results || [])
52
+ return [...extractionEngineRegions, ...metadataEngineRegions]
53
+ }
54
+
55
+ function photosToImages(photos) {
56
+ return photos.map(photo => ({
57
+ id: photo.id,
58
+ src: photo.fullsize.key,
59
+ thumbnail: photo.thumbnail.key,
60
+ name: photo.fullsize.key,
61
+ regions: modelResultsToRegions(photo.modelResults.v1),
62
+ metadata: photo.metadata,
63
+ lockedUntil: photo.lockedUntil,
64
+ }))
65
+ }
66
+
67
+ export default photosToImages;
@@ -0,0 +1,19 @@
1
+ const MAX_GROUP_LENGTH = 20;
2
+
3
+ function regionsGroups(regions) {
4
+ if (!regions) {
5
+ return []
6
+ }
7
+ const groups = regions.reduce((acc, curr) => {
8
+ const { groupId } = curr;
9
+ if (acc.some(e => e.id === groupId)) {
10
+ return acc
11
+ }
12
+ acc.push({ id: groupId, label: curr?.text?.substring(0, MAX_GROUP_LENGTH) || groupId })
13
+ return acc;
14
+ }, [])
15
+
16
+ return groups;
17
+ }
18
+
19
+ export default regionsGroups;