@searpent/react-image-annotate 2.0.77 → 2.0.79

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/Annotator/exampleImages.js +41 -0
  2. package/Annotator/examplePhotos.js +6980 -0
  3. package/Annotator/index.js +417 -0
  4. package/Annotator/reducers/combine-reducers.js +14 -0
  5. package/Annotator/reducers/convert-expanding-line-to-polygon.js +73 -0
  6. package/{src/Annotator → Annotator}/reducers/fix-twisted.js +3 -5
  7. package/Annotator/reducers/general-reducer.js +1430 -0
  8. package/Annotator/reducers/get-active-image.js +27 -0
  9. package/Annotator/reducers/get-implied-video-regions.js +180 -0
  10. package/Annotator/reducers/history-handler.js +38 -0
  11. package/Annotator/reducers/image-reducer.js +20 -0
  12. package/Annotator/reducers/video-reducer.js +88 -0
  13. package/ClassSelectionMenu/index.js +140 -0
  14. package/Crosshairs/index.js +53 -0
  15. package/DebugSidebarBox/index.js +20 -0
  16. package/DemoSite/Editor.js +194 -0
  17. package/DemoSite/ErrorBoundaryDialog.js +64 -0
  18. package/DemoSite/index.js +40 -0
  19. package/Editor/annotation-plugin/annotation.js +702 -0
  20. package/Editor/index.js +93 -0
  21. package/Editor/readOnly.js +123 -0
  22. package/{src/Editor → Editor}/tools.js +2 -3
  23. package/Errorer/index.js +11 -0
  24. package/FullImageSegmentationAnnotator/index.js +7 -0
  25. package/GroupSelectorSidebarBox/index.js +63 -0
  26. package/GroupsEditorSidebarBox/index.js +138 -0
  27. package/HelpSidebarBox/index.js +58 -0
  28. package/HighlightBox/index.js +102 -0
  29. package/HistorySidebarBox/index.js +71 -0
  30. package/ImageCanvas/index.js +441 -0
  31. package/ImageCanvas/region-tools.js +165 -0
  32. package/{src/ImageCanvas → ImageCanvas}/styles.js +12 -8
  33. package/ImageCanvas/use-mouse.js +180 -0
  34. package/ImageCanvas/use-project-box.js +27 -0
  35. package/ImageCanvas/use-wasd-mode.js +62 -0
  36. package/ImageMask/index.js +133 -0
  37. package/ImageMask/load-image.js +25 -0
  38. package/ImageSelectorSidebarBox/index.js +60 -0
  39. package/KeyframeTimeline/get-time-string.js +27 -0
  40. package/KeyframeTimeline/index.js +233 -0
  41. package/KeyframesSelectorSidebarBox/index.js +93 -0
  42. package/LandingPage/index.js +159 -0
  43. package/Locker/index.js +11 -0
  44. package/MainLayout/RightSidebarItemsWrapper.js +19 -0
  45. package/MainLayout/icon-dictionary.js +104 -0
  46. package/MainLayout/index.js +526 -0
  47. package/{src/MainLayout → MainLayout}/styles.js +6 -7
  48. package/MainLayout/types.js +0 -0
  49. package/MainLayout/use-implied-video-regions.js +13 -0
  50. package/MetadataEditorSidebarBox/index.js +231 -0
  51. package/PageSelector/index.js +180 -0
  52. package/PointDistances/index.js +73 -0
  53. package/PreventScrollToParents/index.js +51 -0
  54. package/RegionLabel/index.js +232 -0
  55. package/{src/RegionLabel → RegionLabel}/styles.js +12 -15
  56. package/RegionSelectAndTransformBoxes/index.js +169 -0
  57. package/RegionSelectorSidebarBox/index.js +254 -0
  58. package/{src/RegionSelectorSidebarBox → RegionSelectorSidebarBox}/styles.js +13 -14
  59. package/RegionShapes/index.js +294 -0
  60. package/RegionTags/index.js +144 -0
  61. package/SettingsDialog/index.js +52 -0
  62. package/SettingsProvider/index.js +60 -0
  63. package/Shortcuts/ShortcutField.js +46 -0
  64. package/Shortcuts/index.js +133 -0
  65. package/ShortcutsManager/index.js +155 -0
  66. package/Sidebar/index.js +69 -0
  67. package/SidebarBoxContainer/index.js +93 -0
  68. package/SmallToolButton/index.js +42 -0
  69. package/TagsSidebarBox/index.js +105 -0
  70. package/TaskDescriptionSidebarBox/index.js +58 -0
  71. package/Theme/index.js +30 -0
  72. package/VideoOrImageCanvasBackground/index.js +151 -0
  73. package/colors.js +14 -0
  74. package/hooks/use-colors.js +127 -0
  75. package/hooks/use-event-callback.js +10 -0
  76. package/hooks/use-exclude-pattern.js +24 -0
  77. package/hooks/use-load-image.js +26 -0
  78. package/hooks/use-window-size.js +46 -0
  79. package/{src/hooks → hooks}/xpattern.js +1 -1
  80. package/index.js +3 -0
  81. package/lib.js +3 -0
  82. package/package.json +1 -1
  83. package/stories.js +5 -0
  84. package/utils/blocks-to-article.js +60 -0
  85. package/{src/utils → utils}/blocks-to-article.test.js +5 -8
  86. package/{src/utils → utils}/default-locked-until.js +2 -1
  87. package/{src/utils → utils}/filter-only-unique.js +1 -1
  88. package/utils/get-from-local-storage.js +7 -0
  89. package/utils/get-hotkey-help-text.js +9 -0
  90. package/utils/get-landmarks-with-transform.js +40 -0
  91. package/utils/photosToImages.js +85 -0
  92. package/utils/regions-groups.js +28 -0
  93. package/utils/regions-to-blocks.js +18 -0
  94. package/utils/saveable-actions-enum.js +3 -0
  95. package/utils/set-in-local-storage.js +3 -0
  96. package/utils/sleep.js +7 -0
  97. package/utils/uuid-to-hash.js +5 -0
  98. package/.babelrc +0 -6
  99. package/.env +0 -1
  100. package/.flowconfig +0 -2
  101. package/.github/workflows/release-on-master.yml +0 -32
  102. package/.github/workflows/test.yml +0 -16
  103. package/.prettierrc +0 -3
  104. package/.releaserc.js +0 -18
  105. package/.storybook/addons.js +0 -2
  106. package/.storybook/config.js +0 -16
  107. package/LICENSE +0 -21
  108. package/public/favicon.ico +0 -0
  109. package/public/index.html +0 -38
  110. package/src/Annotator/bike-pic.png +0 -0
  111. package/src/Annotator/bike-pic2.png +0 -0
  112. package/src/Annotator/dab-keyframes.story.json +0 -1
  113. package/src/Annotator/exampleImages.js +0 -48
  114. package/src/Annotator/examplePhotos.js +0 -7603
  115. package/src/Annotator/index.js +0 -380
  116. package/src/Annotator/index.story.js +0 -899
  117. package/src/Annotator/poses.story.js +0 -150
  118. package/src/Annotator/reducers/combine-reducers.js +0 -7
  119. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -53
  120. package/src/Annotator/reducers/general-reducer.js +0 -1228
  121. package/src/Annotator/reducers/get-active-image.js +0 -21
  122. package/src/Annotator/reducers/get-implied-video-regions.js +0 -115
  123. package/src/Annotator/reducers/history-handler.js +0 -60
  124. package/src/Annotator/reducers/image-reducer.js +0 -23
  125. package/src/Annotator/reducers/video-reducer.js +0 -85
  126. package/src/Annotator/video.story.js +0 -51
  127. package/src/ClassSelectionMenu/index.js +0 -112
  128. package/src/Crosshairs/index.js +0 -64
  129. package/src/DebugSidebarBox/index.js +0 -36
  130. package/src/DemoSite/Editor.js +0 -235
  131. package/src/DemoSite/ErrorBoundaryDialog.js +0 -34
  132. package/src/DemoSite/index.js +0 -41
  133. package/src/DemoSite/index.story.js +0 -10
  134. package/src/DemoSite/simple-segmentation-example.json +0 -572
  135. package/src/Editor/annotation-plugin/annotation.js +0 -546
  136. package/src/Editor/index.js +0 -50
  137. package/src/Editor/readOnly.js +0 -31
  138. package/src/Errorer/index.js +0 -13
  139. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  140. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  141. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  142. package/src/FullImageSegmentationAnnotator/index.js +0 -7
  143. package/src/FullImageSegmentationAnnotator/index.story.js +0 -177
  144. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  145. package/src/GroupSelectorSidebarBox/index.js +0 -48
  146. package/src/GroupsEditorSidebarBox/index.js +0 -108
  147. package/src/HelpSidebarBox/index.js +0 -43
  148. package/src/HighlightBox/index.js +0 -143
  149. package/src/HistorySidebarBox/index.js +0 -78
  150. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  151. package/src/ImageCanvas/index.js +0 -515
  152. package/src/ImageCanvas/index.story.js +0 -314
  153. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  154. package/src/ImageCanvas/region-tools.js +0 -171
  155. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  156. package/src/ImageCanvas/use-mouse.js +0 -168
  157. package/src/ImageCanvas/use-project-box.js +0 -23
  158. package/src/ImageCanvas/use-wasd-mode.js +0 -50
  159. package/src/ImageMask/index.js +0 -127
  160. package/src/ImageMask/load-image.js +0 -32
  161. package/src/ImageSelectorSidebarBox/index.js +0 -54
  162. package/src/KeyframeTimeline/get-time-string.js +0 -25
  163. package/src/KeyframeTimeline/index.js +0 -223
  164. package/src/KeyframesSelectorSidebarBox/index.js +0 -93
  165. package/src/LandingPage/content.md +0 -57
  166. package/src/LandingPage/github-markdown.css +0 -964
  167. package/src/LandingPage/index.js +0 -147
  168. package/src/Locker/index.js +0 -13
  169. package/src/MainLayout/RightSidebarItemsWrapper.js +0 -21
  170. package/src/MainLayout/icon-dictionary.js +0 -79
  171. package/src/MainLayout/index.js +0 -564
  172. package/src/MainLayout/index.story.js +0 -240
  173. package/src/MainLayout/types.js +0 -171
  174. package/src/MainLayout/use-implied-video-regions.js +0 -17
  175. package/src/MetadataEditorSidebarBox/index.js +0 -160
  176. package/src/PageSelector/index.js +0 -159
  177. package/src/PointDistances/index.js +0 -90
  178. package/src/PreventScrollToParents/index.js +0 -48
  179. package/src/PreventScrollToParents/index.story.js +0 -23
  180. package/src/RegionLabel/index.js +0 -236
  181. package/src/RegionSelectAndTransformBoxes/index.js +0 -236
  182. package/src/RegionSelectorSidebarBox/index.js +0 -220
  183. package/src/RegionShapes/index.js +0 -254
  184. package/src/RegionTags/index.js +0 -136
  185. package/src/SettingsDialog/index.js +0 -58
  186. package/src/SettingsProvider/index.js +0 -57
  187. package/src/Shortcuts/ShortcutField.js +0 -44
  188. package/src/Shortcuts/index.js +0 -129
  189. package/src/ShortcutsManager/index.js +0 -162
  190. package/src/Sidebar/index.js +0 -117
  191. package/src/SidebarBoxContainer/index.js +0 -93
  192. package/src/SmallToolButton/index.js +0 -57
  193. package/src/TagsSidebarBox/index.js +0 -93
  194. package/src/TaskDescriptionSidebarBox/index.js +0 -43
  195. package/src/Theme/index.js +0 -36
  196. package/src/VideoOrImageCanvasBackground/index.js +0 -170
  197. package/src/colors.js +0 -32
  198. package/src/hooks/use-colors.js +0 -95
  199. package/src/hooks/use-event-callback.js +0 -11
  200. package/src/hooks/use-exclude-pattern.js +0 -27
  201. package/src/hooks/use-load-image.js +0 -21
  202. package/src/hooks/use-window-size.js +0 -46
  203. package/src/hooks/xpattern.png +0 -0
  204. package/src/index.js +0 -18
  205. package/src/lib.js +0 -7
  206. package/src/screenshot.png +0 -0
  207. package/src/site.css +0 -5
  208. package/src/stories.js +0 -2
  209. package/src/utils/blocks-to-article.js +0 -61
  210. package/src/utils/get-from-local-storage.js +0 -7
  211. package/src/utils/get-hotkey-help-text.js +0 -11
  212. package/src/utils/get-landmarks-with-transform.js +0 -23
  213. package/src/utils/photosToImages.js +0 -67
  214. package/src/utils/regions-groups.js +0 -19
  215. package/src/utils/regions-to-blocks.js +0 -16
  216. package/src/utils/saveable-actions-enum.js +0 -5
  217. package/src/utils/set-in-local-storage.js +0 -6
  218. package/src/utils/sleep.js +0 -3
  219. package/src/utils/uuid-to-hash.js +0 -5
  220. /package/{src/Editor → Editor}/annotation-plugin/annotation.css +0 -0
  221. /package/{src/Errorer → Errorer}/errorer.css +0 -0
  222. /package/{src/Locker → Locker}/locker.css +0 -0
  223. /package/{src/PageSelector → PageSelector}/page-selector.css +0 -0
  224. /package/{src/utils → utils}/next-group-id.js +0 -0
@@ -1,50 +0,0 @@
1
- import { useEffect } from "react"
2
- import { useSettings } from "../SettingsProvider"
3
-
4
- export default ({ getLatestMat, changeMat }) => {
5
- const { wasdMode } = useSettings()
6
- useEffect(() => {
7
- if (!wasdMode) return
8
- const vel = 10
9
- const dirs = {
10
- w: [0, -vel],
11
- a: [-vel, 0],
12
- s: [0, vel],
13
- d: [vel, 0],
14
- }
15
- const keysDown = {}
16
- const keys = Object.keys(dirs)
17
- const keyDownListener = (e) => {
18
- if (keys.includes(e.key)) {
19
- keysDown[e.key] = true
20
- e.preventDefault()
21
- e.stopPropagation()
22
- }
23
- }
24
- const keyUpListener = (e) => {
25
- if (keys.includes(e.key)) {
26
- keysDown[e.key] = false
27
- e.preventDefault()
28
- e.stopPropagation()
29
- }
30
- }
31
- const interval = setInterval(() => {
32
- let newMat = getLatestMat().clone()
33
- let somethingChanged = false
34
- for (const key in keysDown) {
35
- if (keysDown[key]) {
36
- newMat = newMat.translate(...dirs[key])
37
- somethingChanged = true
38
- }
39
- }
40
- if (somethingChanged) changeMat(newMat)
41
- }, 16)
42
- window.addEventListener("keydown", keyDownListener)
43
- window.addEventListener("keyup", keyUpListener)
44
- return () => {
45
- clearInterval(interval)
46
- window.removeEventListener("keydown", keyDownListener)
47
- window.removeEventListener("keyup", keyUpListener)
48
- }
49
- }, [wasdMode])
50
- }
@@ -1,127 +0,0 @@
1
- // @flow
2
-
3
- import React, { useState, useEffect, useMemo, useRef } from "react"
4
- import { colorInts } from "../colors"
5
- import { useDebounce } from "react-use"
6
- import loadImage from "./load-image"
7
- import autoseg from "autoseg/webworker"
8
-
9
- function convertToUDTRegions(regions) {
10
- return regions
11
- .map((r) => {
12
- switch (r.type) {
13
- case "point": {
14
- return {
15
- regionType: "point",
16
- classification: r.cls,
17
- x: r.x,
18
- y: r.y,
19
- }
20
- }
21
- case "polygon": {
22
- return {
23
- regionType: "polygon",
24
- classification: r.cls,
25
- points: r.points.map(([x, y]) => ({ x, y })),
26
- }
27
- }
28
- case "box": {
29
- return {
30
- regionType: "bounding-box",
31
- classification: r.cls,
32
- centerX: r.x + r.w / 2,
33
- centerY: r.y + r.h / 2,
34
- width: r.w,
35
- height: r.h,
36
- }
37
- }
38
- default: {
39
- return null
40
- }
41
- }
42
- })
43
- .filter(Boolean)
44
- }
45
-
46
- export const ImageMask = ({
47
- regions,
48
- regionClsList,
49
- imageSrc,
50
- imagePosition,
51
- zIndex = 1,
52
- hide = false,
53
- autoSegmentationOptions = { type: "simple" },
54
- }) => {
55
- // if (!window.mmgc) window.mmgc = MMGC_INIT()
56
- // const mmgc = window.mmgc
57
- const [canvasRef, setCanvasRef] = useState(null)
58
-
59
- const [sampleImageData, setSampleImageData] = useState()
60
-
61
- useEffect(() => {
62
- if (!imageSrc) return
63
-
64
- loadImage(imageSrc).then((imageData) => {
65
- autoseg.setConfig({
66
- classNames: regionClsList,
67
- ...autoSegmentationOptions,
68
- })
69
- autoseg.loadImage(imageData)
70
- setSampleImageData(imageData)
71
- })
72
- }, [imageSrc])
73
-
74
- useDebounce(
75
- () => {
76
- if (hide) return
77
- if (!canvasRef) return
78
- if (!sampleImageData) return
79
- if (regions.filter((cp) => cp.cls).length < 2) return
80
-
81
- const udtRegions = convertToUDTRegions(regions)
82
-
83
- autoseg.getMask(udtRegions).then((maskImageData) => {
84
- const context = canvasRef.getContext("2d")
85
- context.clearRect(0, 0, maskImageData.width, maskImageData.height)
86
- context.putImageData(maskImageData, 0, 0)
87
- })
88
- },
89
- 1000,
90
- [canvasRef, sampleImageData, regions, hide]
91
- )
92
-
93
- const style = useMemo(() => {
94
- let width = imagePosition.bottomRight.x - imagePosition.topLeft.x
95
- let height = imagePosition.bottomRight.y - imagePosition.topLeft.y
96
- return {
97
- display: hide ? "none" : undefined,
98
- imageRendering: "pixelated",
99
- transform: "translateZ(0px)",
100
- left: imagePosition.topLeft.x,
101
- top: imagePosition.topLeft.y,
102
- width: isNaN(width) ? 0 : width,
103
- height: isNaN(height) ? 0 : height,
104
- zIndex,
105
- position: "absolute",
106
- pointerEvents: "none",
107
- }
108
- }, [
109
- imagePosition.topLeft.x,
110
- imagePosition.topLeft.y,
111
- imagePosition.bottomRight.x,
112
- imagePosition.bottomRight.y,
113
- zIndex,
114
- hide,
115
- ])
116
-
117
- return (
118
- <canvas
119
- style={style}
120
- width={sampleImageData ? sampleImageData.width : 0}
121
- height={sampleImageData ? sampleImageData.height : 0}
122
- ref={setCanvasRef}
123
- />
124
- )
125
- }
126
-
127
- export default ImageMask
@@ -1,32 +0,0 @@
1
- export const loadImage = (imageSrc) => {
2
- // Check if image is already loaded in a page element
3
- let image = Array.from(document.getElementsByTagName("img")).find(
4
- (img) => img.src === imageSrc
5
- )
6
-
7
- const canvas = document.createElement("canvas")
8
- const ctx = canvas.getContext("2d")
9
-
10
- if (!image) {
11
- image = new Image()
12
- image.crossOrigin = "anonymous"
13
- image.src = imageSrc
14
- }
15
-
16
- return new Promise((resolve, reject) => {
17
- image.onload = () => {
18
- canvas.width = image.naturalWidth
19
- canvas.height = image.naturalHeight
20
- ctx.drawImage(image, 0, 0)
21
- const imageData = ctx.getImageData(
22
- 0,
23
- 0,
24
- image.naturalWidth,
25
- image.naturalHeight
26
- )
27
- resolve(imageData)
28
- }
29
- })
30
- }
31
-
32
- export default loadImage
@@ -1,54 +0,0 @@
1
- // @flow
2
-
3
- import React, { memo } from "react"
4
- import { makeStyles } from "@mui/styles"
5
- import { createTheme, ThemeProvider } from "@mui/material/styles"
6
- import SidebarBoxContainer from "../SidebarBoxContainer"
7
- import CollectionsIcon from "@mui/icons-material/Collections"
8
- import { grey } from "@mui/material/colors"
9
- import List from "@mui/material/List"
10
- import ListItem from "@mui/material/ListItem"
11
- import ListItemText from "@mui/material/ListItemText"
12
- import Avatar from "@mui/material/Avatar"
13
- import isEqual from "lodash/isEqual"
14
-
15
- const theme = createTheme()
16
- const useStyles = makeStyles((theme) => ({
17
- img: { width: 40, height: 40, borderRadius: 8 },
18
- }))
19
-
20
- export const ImageSelectorSidebarBox = ({ images, onSelect }) => {
21
- const classes = useStyles()
22
- return (
23
- <ThemeProvider theme={theme}>
24
- <SidebarBoxContainer
25
- title="Images"
26
- subTitle={`(${images.length})`}
27
- icon={<CollectionsIcon style={{ color: grey[700] }} />}
28
- >
29
- <div>
30
- <List>
31
- {images.map((img, i) => (
32
- <ListItem button onClick={() => onSelect(img)} dense key={i}>
33
- <img className={classes.img} src={img.src} />
34
- <ListItemText
35
- primary={img.name}
36
- secondary={`${(img.regions || []).length} Labels`}
37
- />
38
- </ListItem>
39
- ))}
40
- </List>
41
- </div>
42
- </SidebarBoxContainer>
43
- </ThemeProvider>
44
- )
45
- }
46
-
47
- const mapUsedImageProps = (a) => [a.name, (a.regions || []).length, a.src]
48
-
49
- export default memo(ImageSelectorSidebarBox, (prevProps, nextProps) =>
50
- isEqual(
51
- prevProps.images.map(mapUsedImageProps),
52
- nextProps.images.map(mapUsedImageProps)
53
- )
54
- )
@@ -1,25 +0,0 @@
1
- // @flow
2
-
3
- const getTimeString = (ms, precision = 1) => {
4
- if (ms < 1000) {
5
- return ms + "ms"
6
- } else {
7
- const secs = ms / 1000
8
- if (secs < 60) {
9
- if (Number.isInteger(secs)) {
10
- return secs + "s"
11
- } else {
12
- return secs.toFixed(precision) + "s"
13
- }
14
- } else {
15
- const mins = secs / 60
16
- if (Number.isInteger(mins)) {
17
- return mins + "m"
18
- } else {
19
- return mins.toFixed(precision) + "m"
20
- }
21
- }
22
- }
23
- }
24
-
25
- export default getTimeString
@@ -1,223 +0,0 @@
1
- // @flow weak
2
-
3
- import React, { useMemo, useState, useEffect } from "react"
4
- import { styled } from "@mui/material/styles"
5
- import { createTheme, ThemeProvider } from "@mui/material/styles"
6
- import range from "lodash/range"
7
- import * as colors from "@mui/material/colors"
8
- import useMeasure from "react-use-measure"
9
- import useEventCallback from "use-event-callback"
10
- import { useRafState } from "react-use"
11
- import getTimeString from "./get-time-string"
12
-
13
- const theme = createTheme()
14
-
15
- const Container = styled("div")(({ theme }) => ({
16
- position: "relative",
17
- display: "flex",
18
- flexGrow: 1,
19
- minWidth: 240,
20
- height: 64,
21
- marginLeft: 16,
22
- marginRight: 16,
23
- }))
24
-
25
- const Tick = styled("div")(({ theme }) => ({
26
- position: "absolute",
27
- width: 2,
28
- marginLeft: -1,
29
- height: "100%",
30
- backgroundColor: colors.grey[300],
31
- bottom: 0,
32
- }))
33
- const TickText = styled("div")(({ theme }) => ({
34
- position: "absolute",
35
- userSelect: "none",
36
- fontSize: 10,
37
- color: colors.grey[600],
38
- fontWeight: "bold",
39
- bottom: 0,
40
- }))
41
-
42
- const PositionCursor = styled("div")(({ theme }) => ({
43
- position: "absolute",
44
- bottom: "calc(50% + 6px)",
45
- fontSize: 10,
46
- fontWeight: "bold",
47
- color: "#fff",
48
- display: "grid",
49
- placeItems: "center",
50
- width: 48,
51
- marginLeft: -24,
52
- borderRadius: 2,
53
- height: 24,
54
- backgroundColor: colors.blue[500],
55
- userSelect: "none",
56
- fontVariantNumeric: "tabular-nums",
57
-
58
- "&::before": {
59
- position: "absolute",
60
- bottom: -6,
61
- left: 24 - 8,
62
- content: '""',
63
- width: 0,
64
- height: 0,
65
- borderTop: `8px solid ${colors.blue[500]}`,
66
- borderLeft: "8px solid transparent",
67
- borderRight: "8px solid transparent",
68
- },
69
- }))
70
-
71
- const KeyframeMarker = styled("div")(({ theme }) => ({
72
- position: "absolute",
73
- bottom: 8,
74
- cursor: "pointer",
75
- opacity: 0.75,
76
- fontSize: 10,
77
- fontWeight: "bold",
78
- color: "#fff",
79
- display: "grid",
80
- placeItems: "center",
81
- width: 16,
82
- marginLeft: 0,
83
- borderTopLeftRadius: 2,
84
- borderTopRightRadius: 2,
85
- height: 12,
86
- marginLeft: -8,
87
- backgroundColor: colors.red[500],
88
- userSelect: "none",
89
- fontVariantNumeric: "tabular-nums",
90
-
91
- "&::before": {
92
- position: "absolute",
93
- bottom: -8,
94
- left: 0,
95
- content: '""',
96
- width: 0,
97
- height: 0,
98
- borderTop: `8px solid ${colors.red[500]}`,
99
- borderLeft: "8px solid transparent",
100
- borderRight: "8px solid transparent",
101
- },
102
- }))
103
-
104
- const min = 60000
105
- const displayIntervalPairs = [
106
- [50, 250],
107
- [100, 500],
108
- [250, 1000],
109
- [1000, 5000],
110
- [5000, 30000],
111
- [10000, min],
112
- [30000, min * 2],
113
- [min, min * 5],
114
- [min * 5, min * 30],
115
- [min * 10, min * 60],
116
- [min * 30, min * 60 * 3],
117
- [min * 60, min * 60 * 5],
118
- ]
119
-
120
- const getMajorInterval = (duration) => {
121
- for (const [minor, major] of displayIntervalPairs) {
122
- if (duration / major < 6 && duration / major > 2) {
123
- return [minor, major]
124
- }
125
- }
126
- return [duration / 4, duration]
127
- }
128
-
129
- export default ({
130
- currentTime = 0,
131
- duration,
132
- onChangeCurrentTime,
133
- keyframes,
134
- }) => {
135
- const [ref, bounds] = useMeasure()
136
- const [instantCurrentTime, changeInstantCurrentTime] = useState(currentTime)
137
- const [draggingTime, changeDraggingTime] = useRafState(false)
138
- const keyframeTimes = Object.keys(keyframes || {})
139
- .map((t) => parseInt(t))
140
- .filter((t) => !isNaN(t))
141
- .sort((a, b) => a - b)
142
-
143
- useEffect(() => {
144
- if (currentTime !== instantCurrentTime) {
145
- changeInstantCurrentTime(currentTime)
146
- }
147
- }, [currentTime])
148
-
149
- const [minorInterval, majorInterval] = useMemo(
150
- () => getMajorInterval(duration),
151
- [duration]
152
- )
153
-
154
- const onMouseMove = useEventCallback((e) => {
155
- if (draggingTime) {
156
- const px = (e.clientX - bounds.left) / bounds.width
157
- changeInstantCurrentTime(
158
- Math.min(duration, Math.max(0, Math.floor(px * duration)))
159
- )
160
- }
161
- })
162
-
163
- const onMouseUp = useEventCallback((e) => {
164
- changeDraggingTime(false)
165
- const px = (e.clientX - bounds.left) / bounds.width
166
- const newTime = Math.min(duration, Math.max(0, Math.floor(px * duration)))
167
- changeInstantCurrentTime(newTime)
168
- onChangeCurrentTime(newTime)
169
- })
170
-
171
- // TODO skeleton
172
- if (!duration) return null
173
-
174
- return (
175
- <ThemeProvider theme={theme}>
176
- <Container onMouseMove={onMouseMove} onMouseUp={onMouseUp} ref={ref}>
177
- {range(0, duration, majorInterval).map((a) => (
178
- <>
179
- <Tick
180
- key={a}
181
- style={{ left: (a / duration) * bounds.width, height: "50%" }}
182
- />
183
- <TickText
184
- style={{
185
- left: (a / duration) * bounds.width + 8,
186
- bottom: "calc(50% - 12px)",
187
- }}
188
- >
189
- {getTimeString(a)}
190
- </TickText>
191
- </>
192
- ))}
193
- {range(0, duration, minorInterval)
194
- .filter((a) => !Number.isInteger(a / majorInterval))
195
- .map((a) => (
196
- <Tick
197
- key={a}
198
- style={{
199
- left: (a / duration) * bounds.width,
200
- height: "25%",
201
- }}
202
- />
203
- ))}
204
- {keyframeTimes.map((kt) => (
205
- <KeyframeMarker
206
- onClick={() => onChangeCurrentTime(kt)}
207
- key={kt}
208
- style={{ left: (kt / duration) * bounds.width }}
209
- />
210
- ))}
211
- <PositionCursor
212
- onMouseDown={(e) => changeDraggingTime(true)}
213
- style={{
214
- cursor: draggingTime ? "grabbing" : "grab",
215
- left: (instantCurrentTime / duration) * bounds.width,
216
- }}
217
- >
218
- {getTimeString(instantCurrentTime)}
219
- </PositionCursor>
220
- </Container>
221
- </ThemeProvider>
222
- )
223
- }
@@ -1,93 +0,0 @@
1
- // @flow weak
2
-
3
- import React from "react"
4
- import AddLocationIcon from "@mui/icons-material/AddLocation"
5
- import SidebarBoxContainer from "../SidebarBoxContainer"
6
- import * as colors from "@mui/material/colors"
7
- import getTimeString from "../KeyframeTimeline/get-time-string.js"
8
- import TrashIcon from "@mui/icons-material/Delete"
9
- import { styled } from "@mui/material/styles"
10
- import { createTheme, ThemeProvider } from "@mui/material/styles"
11
-
12
- const theme = createTheme()
13
- const KeyframeRow = styled("div")(({ theme }) => ({
14
- cursor: "pointer",
15
- display: "flex",
16
- alignItems: "center",
17
- padding: 8,
18
- fontSize: 14,
19
- color: colors.grey[700],
20
- "&.current": {
21
- backgroundColor: colors.blue[100],
22
- },
23
- "&:hover": {
24
- backgroundColor: colors.grey[100],
25
- },
26
- "& .time": {
27
- flexGrow: 1,
28
- fontWeight: "bold",
29
- "& .regionCount": {
30
- marginLeft: 8,
31
- fontWeight: "normal",
32
- color: colors.grey[500],
33
- },
34
- },
35
- "& .trash": {
36
- "& .icon": {
37
- fontSize: 18,
38
- color: colors.grey[600],
39
- transition: "transform 80ms",
40
- "&:hover": {
41
- color: colors.grey[800],
42
- transform: "scale(1.25,1.25)",
43
- },
44
- },
45
- },
46
- }))
47
-
48
- const KeyframesSelectorSidebarBox = ({
49
- currentVideoTime,
50
- keyframes,
51
- onChangeVideoTime,
52
- onDeleteKeyframe,
53
- }) => {
54
- const keyframeTimes = Object.keys(keyframes).map((t) => parseInt(t))
55
-
56
- return (
57
- <ThemeProvider theme={theme}>
58
- <SidebarBoxContainer
59
- title="Keyframes"
60
- subTitle=""
61
- icon={<AddLocationIcon style={{ color: colors.grey[700] }} />}
62
- expandedByDefault
63
- >
64
- {keyframeTimes.map((t) => (
65
- <KeyframeRow
66
- fullWidth
67
- key={t}
68
- className={currentVideoTime === t ? "current" : ""}
69
- onClick={() => onChangeVideoTime(t)}
70
- >
71
- <div className="time">
72
- {getTimeString(t, 2)}
73
- <span className="regionCount">
74
- ({(keyframes[t]?.regions || []).length})
75
- </span>
76
- </div>
77
- <div className="trash">
78
- <TrashIcon
79
- onClick={(e) => {
80
- onDeleteKeyframe(t)
81
- e.stopPropagation()
82
- }}
83
- className="icon"
84
- />
85
- </div>
86
- </KeyframeRow>
87
- ))}
88
- </SidebarBoxContainer>
89
- </ThemeProvider>
90
- )
91
- }
92
-
93
- export default KeyframesSelectorSidebarBox
@@ -1,57 +0,0 @@
1
- # Features
2
-
3
- - Simple input/output format
4
- - Bounding Box, Point and Polygon Annotation
5
- - Zooming, Scaling, Panning
6
- - Multiple Images
7
- - Cursor Crosshair
8
-
9
- ![Screenshot of Annotator](https://user-images.githubusercontent.com/1910070/51199716-83c72080-18c5-11e9-837c-c3a89c8caef4.png)
10
-
11
- # Usage
12
-
13
- ## Installation
14
-
15
- ```bash
16
- npm install react-image-annotate
17
- ```
18
-
19
- ## Basic Example
20
-
21
- ```javascript
22
- import ReactImageAnnotate from "react-image-annotate"
23
-
24
- const App = () => (
25
- <ReactImageAnnotate
26
- selectedImage="https://example.com/image1.png"
27
- taskDescription="# Draw region around each animal."
28
- images={[{ src: "https://example.com/image1.png", name: "Image 1" }]}
29
- regionClsList={["Dog", "Cat"]}
30
- enabledTools={["create-box"]}
31
- />
32
- )
33
- ```
34
-
35
- # Props
36
-
37
- All of the following properties can be defined on the `ReactImageAnnotate` component...
38
-
39
- | Prop | Type (\* = required) | Description | Default |
40
- | ------------------------ | ------------------------------------------------ | --------------------------------------------------------------------------------------- | ------------- |
41
- | `taskDescription` | \*`string` | Markdown description for what to do in the image. | |
42
- | `allowedArea` | `{ x: number, y: number, w: number, h: number }` | Area that is available for annotation. | Entire image. |
43
- | `regionTagList` | `Array<string>` | Allowed "tags" (mutually inclusive classifications) for regions. | |
44
- | `regionClsList` | `Array<string>` | Allowed "classes" (mutually exclusive classifications) for regions. | |
45
- | `imageTagList` | `Array<string>` | Allowed tags for entire image. | |
46
- | `imageClsList` | `Array<string>` | Allowed classes for entire image. | |
47
- | `enabledTools` | `Array<string>` | Tools allowed to be used. e.g. "select", "create-point", "create-box", "create-polygon" | Everything. |
48
- | `showTags` | `boolean` | Show tags and allow tags on regions. | `true` |
49
- | `selectedImage` | `string` | URL of initially selected image. | |
50
- | `images` | `Array<Image>` | Array of images to load into annotator | |
51
- | `showPointDistances` | `boolean` | Show distances between points. | `false` |
52
- | `pointDistancePrecision` | `number` | Precision on displayed points (e.g. 3 => 0.123) | |
53
- | `onExit` | `MainLayoutState => any` | Called when "Save" is called. | |
54
-
55
- # Sponsors
56
-
57
- [![wao.ai sponsorship image](https://s3.amazonaws.com/asset.workaround.online/sponsorship-banner-1.png)](https://wao.ai)