@searpent/react-image-annotate 2.0.1 → 2.0.2

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 (173) hide show
  1. package/Annotator/index.js +161 -0
  2. package/Annotator/reducers/combine-reducers.js +14 -0
  3. package/Annotator/reducers/convert-expanding-line-to-polygon.js +73 -0
  4. package/{src/Annotator → Annotator}/reducers/fix-twisted.js +3 -5
  5. package/Annotator/reducers/general-reducer.js +1058 -0
  6. package/Annotator/reducers/get-active-image.js +27 -0
  7. package/Annotator/reducers/get-implied-video-regions.js +180 -0
  8. package/Annotator/reducers/history-handler.js +38 -0
  9. package/Annotator/reducers/image-reducer.js +20 -0
  10. package/Annotator/reducers/video-reducer.js +88 -0
  11. package/ClassSelectionMenu/index.js +135 -0
  12. package/Crosshairs/index.js +53 -0
  13. package/DebugSidebarBox/index.js +20 -0
  14. package/DemoSite/Editor.js +194 -0
  15. package/DemoSite/ErrorBoundaryDialog.js +64 -0
  16. package/DemoSite/index.js +40 -0
  17. package/FullImageSegmentationAnnotator/index.js +7 -0
  18. package/HighlightBox/index.js +99 -0
  19. package/HistorySidebarBox/index.js +71 -0
  20. package/ImageCanvas/index.js +424 -0
  21. package/ImageCanvas/region-tools.js +165 -0
  22. package/{src/ImageCanvas → ImageCanvas}/styles.js +12 -8
  23. package/ImageCanvas/use-mouse.js +180 -0
  24. package/ImageCanvas/use-project-box.js +27 -0
  25. package/ImageCanvas/use-wasd-mode.js +62 -0
  26. package/ImageMask/index.js +133 -0
  27. package/ImageMask/load-image.js +25 -0
  28. package/ImageSelectorSidebarBox/index.js +60 -0
  29. package/KeyframeTimeline/get-time-string.js +27 -0
  30. package/KeyframeTimeline/index.js +233 -0
  31. package/KeyframesSelectorSidebarBox/index.js +93 -0
  32. package/LandingPage/index.js +159 -0
  33. package/MainLayout/icon-dictionary.js +104 -0
  34. package/MainLayout/index.js +352 -0
  35. package/{src/MainLayout → MainLayout}/styles.js +6 -7
  36. package/MainLayout/types.js +0 -0
  37. package/MainLayout/use-implied-video-regions.js +13 -0
  38. package/PointDistances/index.js +73 -0
  39. package/PreventScrollToParents/index.js +51 -0
  40. package/RegionLabel/index.js +191 -0
  41. package/{src/RegionLabel → RegionLabel}/styles.js +12 -15
  42. package/RegionSelectAndTransformBoxes/index.js +167 -0
  43. package/RegionSelectorSidebarBox/index.js +248 -0
  44. package/{src/RegionSelectorSidebarBox → RegionSelectorSidebarBox}/styles.js +13 -14
  45. package/RegionShapes/index.js +274 -0
  46. package/RegionTags/index.js +138 -0
  47. package/SettingsDialog/index.js +52 -0
  48. package/SettingsProvider/index.js +53 -0
  49. package/Shortcuts/ShortcutField.js +46 -0
  50. package/Shortcuts/index.js +133 -0
  51. package/ShortcutsManager/index.js +155 -0
  52. package/Sidebar/index.js +69 -0
  53. package/SidebarBoxContainer/index.js +93 -0
  54. package/SmallToolButton/index.js +42 -0
  55. package/TagsSidebarBox/index.js +105 -0
  56. package/TaskDescriptionSidebarBox/index.js +58 -0
  57. package/Theme/index.js +30 -0
  58. package/VideoOrImageCanvasBackground/index.js +151 -0
  59. package/colors.js +14 -0
  60. package/hooks/use-event-callback.js +10 -0
  61. package/hooks/use-exclude-pattern.js +24 -0
  62. package/hooks/use-load-image.js +26 -0
  63. package/hooks/use-window-size.js +46 -0
  64. package/{src/hooks → hooks}/xpattern.js +1 -1
  65. package/index.js +3 -0
  66. package/lib.js +3 -0
  67. package/package.json +1 -1
  68. package/stories.js +5 -0
  69. package/utils/get-from-local-storage.js +7 -0
  70. package/utils/get-hotkey-help-text.js +9 -0
  71. package/utils/get-landmarks-with-transform.js +40 -0
  72. package/utils/set-in-local-storage.js +3 -0
  73. package/.babelrc +0 -6
  74. package/.env +0 -1
  75. package/.flowconfig +0 -2
  76. package/.github/workflows/release-on-master.yml +0 -32
  77. package/.github/workflows/test.yml +0 -16
  78. package/.prettierrc +0 -3
  79. package/.releaserc.js +0 -18
  80. package/.storybook/addons.js +0 -2
  81. package/.storybook/config.js +0 -16
  82. package/LICENSE +0 -21
  83. package/public/favicon.ico +0 -0
  84. package/public/index.html +0 -38
  85. package/src/Annotator/bike-pic.png +0 -0
  86. package/src/Annotator/bike-pic2.png +0 -0
  87. package/src/Annotator/dab-keyframes.story.json +0 -1
  88. package/src/Annotator/index.js +0 -211
  89. package/src/Annotator/index.story.js +0 -758
  90. package/src/Annotator/poses.story.js +0 -150
  91. package/src/Annotator/reducers/combine-reducers.js +0 -7
  92. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -53
  93. package/src/Annotator/reducers/general-reducer.js +0 -914
  94. package/src/Annotator/reducers/get-active-image.js +0 -21
  95. package/src/Annotator/reducers/get-implied-video-regions.js +0 -115
  96. package/src/Annotator/reducers/history-handler.js +0 -60
  97. package/src/Annotator/reducers/image-reducer.js +0 -23
  98. package/src/Annotator/reducers/video-reducer.js +0 -85
  99. package/src/Annotator/video.story.js +0 -51
  100. package/src/ClassSelectionMenu/index.js +0 -108
  101. package/src/Crosshairs/index.js +0 -64
  102. package/src/DebugSidebarBox/index.js +0 -36
  103. package/src/DemoSite/Editor.js +0 -235
  104. package/src/DemoSite/ErrorBoundaryDialog.js +0 -34
  105. package/src/DemoSite/index.js +0 -41
  106. package/src/DemoSite/index.story.js +0 -10
  107. package/src/DemoSite/simple-segmentation-example.json +0 -572
  108. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  109. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  110. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  111. package/src/FullImageSegmentationAnnotator/index.js +0 -7
  112. package/src/FullImageSegmentationAnnotator/index.story.js +0 -177
  113. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  114. package/src/HighlightBox/index.js +0 -143
  115. package/src/HistorySidebarBox/index.js +0 -78
  116. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  117. package/src/ImageCanvas/index.js +0 -488
  118. package/src/ImageCanvas/index.story.js +0 -214
  119. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  120. package/src/ImageCanvas/region-tools.js +0 -171
  121. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  122. package/src/ImageCanvas/use-mouse.js +0 -168
  123. package/src/ImageCanvas/use-project-box.js +0 -23
  124. package/src/ImageCanvas/use-wasd-mode.js +0 -50
  125. package/src/ImageMask/index.js +0 -127
  126. package/src/ImageMask/load-image.js +0 -32
  127. package/src/ImageSelectorSidebarBox/index.js +0 -54
  128. package/src/KeyframeTimeline/get-time-string.js +0 -25
  129. package/src/KeyframeTimeline/index.js +0 -223
  130. package/src/KeyframesSelectorSidebarBox/index.js +0 -93
  131. package/src/LandingPage/content.md +0 -57
  132. package/src/LandingPage/github-markdown.css +0 -964
  133. package/src/LandingPage/index.js +0 -147
  134. package/src/MainLayout/icon-dictionary.js +0 -79
  135. package/src/MainLayout/index.js +0 -420
  136. package/src/MainLayout/index.story.js +0 -240
  137. package/src/MainLayout/types.js +0 -156
  138. package/src/MainLayout/use-implied-video-regions.js +0 -17
  139. package/src/PointDistances/index.js +0 -90
  140. package/src/PreventScrollToParents/index.js +0 -48
  141. package/src/PreventScrollToParents/index.story.js +0 -23
  142. package/src/RegionLabel/index.js +0 -201
  143. package/src/RegionSelectAndTransformBoxes/index.js +0 -234
  144. package/src/RegionSelectorSidebarBox/index.js +0 -216
  145. package/src/RegionShapes/index.js +0 -236
  146. package/src/RegionTags/index.js +0 -130
  147. package/src/SettingsDialog/index.js +0 -58
  148. package/src/SettingsProvider/index.js +0 -44
  149. package/src/Shortcuts/ShortcutField.js +0 -44
  150. package/src/Shortcuts/index.js +0 -129
  151. package/src/ShortcutsManager/index.js +0 -162
  152. package/src/Sidebar/index.js +0 -117
  153. package/src/SidebarBoxContainer/index.js +0 -93
  154. package/src/SmallToolButton/index.js +0 -57
  155. package/src/TagsSidebarBox/index.js +0 -93
  156. package/src/TaskDescriptionSidebarBox/index.js +0 -43
  157. package/src/Theme/index.js +0 -36
  158. package/src/VideoOrImageCanvasBackground/index.js +0 -170
  159. package/src/colors.js +0 -32
  160. package/src/hooks/use-event-callback.js +0 -11
  161. package/src/hooks/use-exclude-pattern.js +0 -27
  162. package/src/hooks/use-load-image.js +0 -21
  163. package/src/hooks/use-window-size.js +0 -46
  164. package/src/hooks/xpattern.png +0 -0
  165. package/src/index.js +0 -18
  166. package/src/lib.js +0 -7
  167. package/src/screenshot.png +0 -0
  168. package/src/site.css +0 -5
  169. package/src/stories.js +0 -2
  170. package/src/utils/get-from-local-storage.js +0 -7
  171. package/src/utils/get-hotkey-help-text.js +0 -11
  172. package/src/utils/get-landmarks-with-transform.js +0 -23
  173. package/src/utils/set-in-local-storage.js +0 -6
@@ -1,236 +0,0 @@
1
- // @flow
2
-
3
- import React, { memo } from "react"
4
- import colorAlpha from "color-alpha"
5
-
6
- function clamp(num, min, max) {
7
- return num <= min ? min : num >= max ? max : num
8
- }
9
-
10
- const RegionComponents = {
11
- point: memo(({ region, iw, ih }) => (
12
- <g transform={`translate(${region.x * iw} ${region.y * ih})`}>
13
- <path
14
- d={"M0 8L8 0L0 -8L-8 0Z"}
15
- strokeWidth={2}
16
- stroke={region.color}
17
- fill="transparent"
18
- />
19
- </g>
20
- )),
21
- line: memo(({ region, iw, ih }) => (
22
- <g transform={`translate(${region.x1 * iw} ${region.y1 * ih})`}>
23
- <line
24
- strokeWidth={2}
25
- x1={0}
26
- y1={0}
27
- x2={(region.x2 - region.x1) * iw}
28
- y2={(region.y2 - region.y1) * ih}
29
- stroke={colorAlpha(region.color, 0.75)}
30
- fill={colorAlpha(region.color, 0.25)}
31
- />
32
- </g>
33
- )),
34
- box: memo(({ region, iw, ih }) => (
35
- <g transform={`translate(${region.x * iw} ${region.y * ih})`}>
36
- <rect
37
- strokeWidth={2}
38
- x={0}
39
- y={0}
40
- width={Math.max(region.w * iw, 0)}
41
- height={Math.max(region.h * ih, 0)}
42
- stroke={colorAlpha(region.color, 0.75)}
43
- fill={colorAlpha(region.color, 0.25)}
44
- />
45
- </g>
46
- )),
47
- polygon: memo(({ region, iw, ih, fullSegmentationMode }) => {
48
- const Component = region.open ? "polyline" : "polygon"
49
- const alphaBase = fullSegmentationMode ? 0.5 : 1
50
- return (
51
- <Component
52
- points={region.points
53
- .map(([x, y]) => [x * iw, y * ih])
54
- .map((a) => a.join(" "))
55
- .join(" ")}
56
- strokeWidth={2}
57
- stroke={colorAlpha(region.color, 0.75)}
58
- fill={colorAlpha(region.color, 0.25)}
59
- />
60
- )
61
- }),
62
- keypoints: ({ region, iw, ih, keypointDefinitions }) => {
63
- const { points, keypointsDefinitionId } = region
64
- if (!keypointDefinitions[keypointsDefinitionId]) {
65
- throw new Error(
66
- `No definition for keypoint configuration "${keypointsDefinitionId}"`
67
- )
68
- }
69
- const { landmarks, connections } =
70
- keypointDefinitions[keypointsDefinitionId]
71
- return (
72
- <g>
73
- {Object.entries(points).map(([keypointId, { x, y }], i) => (
74
- <g key={i} transform={`translate(${x * iw} ${y * ih})`}>
75
- <path
76
- d={"M0 8L8 0L0 -8L-8 0Z"}
77
- strokeWidth={2}
78
- stroke={landmarks[keypointId].color}
79
- fill="transparent"
80
- />
81
- </g>
82
- ))}
83
- {connections.map(([kp1Id, kp2Id]) => {
84
- const kp1 = points[kp1Id]
85
- const kp2 = points[kp2Id]
86
- const midPoint = { x: (kp1.x + kp2.x) / 2, y: (kp1.y + kp2.y) / 2 }
87
-
88
- return (
89
- <g key={`${kp1.x},${kp1.y}.${kp2.x},${kp2.y}`}>
90
- <line
91
- x1={kp1.x * iw}
92
- y1={kp1.y * ih}
93
- x2={midPoint.x * iw}
94
- y2={midPoint.y * ih}
95
- strokeWidth={2}
96
- stroke={landmarks[kp1Id].color}
97
- />
98
- <line
99
- x1={kp2.x * iw}
100
- y1={kp2.y * ih}
101
- x2={midPoint.x * iw}
102
- y2={midPoint.y * ih}
103
- strokeWidth={2}
104
- stroke={landmarks[kp2Id].color}
105
- />
106
- </g>
107
- )
108
- })}
109
- </g>
110
- )
111
- },
112
- "expanding-line": memo(({ region, iw, ih }) => {
113
- let { expandingWidth = 0.005, points } = region
114
- expandingWidth = points.slice(-1)[0].width || expandingWidth
115
- const pointPairs = points.map(({ x, y, angle, width }, i) => {
116
- if (!angle) {
117
- const n = points[clamp(i + 1, 0, points.length - 1)]
118
- const p = points[clamp(i - 1, 0, points.length - 1)]
119
- angle = Math.atan2(p.x - n.x, p.y - n.y) + Math.PI / 2
120
- }
121
- const dx = (Math.sin(angle) * (width || expandingWidth)) / 2
122
- const dy = (Math.cos(angle) * (width || expandingWidth)) / 2
123
- return [
124
- { x: x + dx, y: y + dy },
125
- { x: x - dx, y: y - dy },
126
- ]
127
- })
128
- const firstSection = pointPairs.map(([p1, p2]) => p1)
129
- const secondSection = pointPairs.map(([p1, p2]) => p2).asMutable()
130
- secondSection.reverse()
131
- const lastPoint = points.slice(-1)[0]
132
- return (
133
- <>
134
- <polygon
135
- points={firstSection
136
- .concat(region.candidatePoint ? [region.candidatePoint] : [])
137
- .concat(secondSection)
138
- .map((p) => `${p.x * iw} ${p.y * ih}`)
139
- .join(" ")}
140
- strokeWidth={2}
141
- stroke={colorAlpha(region.color, 0.75)}
142
- fill={colorAlpha(region.color, 0.25)}
143
- />
144
- {points.map(({ x, y, angle }, i) => (
145
- <g
146
- key={i}
147
- transform={`translate(${x * iw} ${y * ih}) rotate(${
148
- (-(angle || 0) * 180) / Math.PI
149
- })`}
150
- >
151
- <g>
152
- <rect
153
- x={-5}
154
- y={-5}
155
- width={10}
156
- height={10}
157
- strokeWidth={2}
158
- stroke={colorAlpha(region.color, 0.75)}
159
- fill={colorAlpha(region.color, 0.25)}
160
- />
161
- </g>
162
- </g>
163
- ))}
164
- <rect
165
- x={lastPoint.x * iw - 8}
166
- y={lastPoint.y * ih - 8}
167
- width={16}
168
- height={16}
169
- strokeWidth={4}
170
- stroke={colorAlpha(region.color, 0.5)}
171
- fill={"transparent"}
172
- />
173
- </>
174
- )
175
- }),
176
- pixel: () => null,
177
- }
178
-
179
- export const WrappedRegionList = memo(
180
- ({ regions, keypointDefinitions, iw, ih, fullSegmentationMode }) => {
181
- return regions
182
- .filter((r) => r.visible !== false)
183
- .map((r) => {
184
- const Component = RegionComponents[r.type]
185
- return (
186
- <Component
187
- key={r.regionId}
188
- region={r}
189
- iw={iw}
190
- ih={ih}
191
- keypointDefinitions={keypointDefinitions}
192
- fullSegmentationMode={fullSegmentationMode}
193
- />
194
- )
195
- })
196
- },
197
- (n, p) => n.regions === p.regions && n.iw === p.iw && n.ih === p.ih
198
- )
199
-
200
- export const RegionShapes = ({
201
- mat,
202
- imagePosition,
203
- regions = [],
204
- keypointDefinitions,
205
- fullSegmentationMode,
206
- }) => {
207
- const iw = imagePosition.bottomRight.x - imagePosition.topLeft.x
208
- const ih = imagePosition.bottomRight.y - imagePosition.topLeft.y
209
- if (isNaN(iw) || isNaN(ih)) return null
210
- return (
211
- <svg
212
- width={iw}
213
- height={ih}
214
- style={{
215
- position: "absolute",
216
- zIndex: 2,
217
- left: imagePosition.topLeft.x,
218
- top: imagePosition.topLeft.y,
219
- pointerEvents: "none",
220
- width: iw,
221
- height: ih,
222
- }}
223
- >
224
- <WrappedRegionList
225
- key="wrapped-region-list"
226
- regions={regions}
227
- iw={iw}
228
- ih={ih}
229
- keypointDefinitions={keypointDefinitions}
230
- fullSegmentationMode={fullSegmentationMode}
231
- />
232
- </svg>
233
- )
234
- }
235
-
236
- export default RegionShapes
@@ -1,130 +0,0 @@
1
- // @flow weak
2
-
3
- import React from "react"
4
- import Paper from "@mui/material/Paper"
5
- import DefaultRegionLabel from "../RegionLabel"
6
- import LockIcon from "@mui/icons-material/Lock"
7
-
8
- const copyWithout = (obj, ...args) => {
9
- const newObj = { ...obj }
10
- for (const arg of args) {
11
- delete newObj[arg]
12
- }
13
- return newObj
14
- }
15
-
16
- export const RegionTags = ({
17
- regions,
18
- projectRegionBox,
19
- mouseEvents,
20
- regionClsList,
21
- regionTagList,
22
- onBeginRegionEdit,
23
- onChangeRegion,
24
- onCloseRegionEdit,
25
- onDeleteRegion,
26
- layoutParams,
27
- imageSrc,
28
- RegionEditLabel,
29
- onRegionClassAdded,
30
- allowComments,
31
- }) => {
32
- const RegionLabel =
33
- RegionEditLabel != null ? RegionEditLabel : DefaultRegionLabel
34
- return regions
35
- .filter((r) => r.visible || r.visible === undefined)
36
- .map((region) => {
37
- const pbox = projectRegionBox(region)
38
- const { iw, ih } = layoutParams.current
39
- let margin = 8
40
- if (region.highlighted && region.type === "box") margin += 6
41
- const labelBoxHeight =
42
- region.editingLabels && !region.locked ? 170 : region.tags ? 60 : 50
43
- const displayOnTop = pbox.y > labelBoxHeight
44
-
45
- const coords = displayOnTop
46
- ? {
47
- left: pbox.x,
48
- top: pbox.y - margin / 2,
49
- }
50
- : { left: pbox.x, top: pbox.y + pbox.h + margin / 2 }
51
- if (region.locked) {
52
- return (
53
- <div
54
- key={region.id}
55
- style={{
56
- position: "absolute",
57
- ...coords,
58
- zIndex: 10 + (region.editingLabels ? 5 : 0),
59
- }}
60
- >
61
- <Paper
62
- style={{
63
- position: "absolute",
64
- left: 0,
65
- ...(displayOnTop ? { bottom: 0 } : { top: 0 }),
66
- zIndex: 10,
67
- backgroundColor: "#fff",
68
- borderRadius: 4,
69
- padding: 2,
70
- paddingBottom: 0,
71
- opacity: 0.5,
72
- pointerEvents: "none",
73
- }}
74
- >
75
- <LockIcon style={{ width: 16, height: 16, color: "#333" }} />
76
- </Paper>
77
- </div>
78
- )
79
- }
80
- return (
81
- <div
82
- key={region.id}
83
- style={{
84
- position: "absolute",
85
- ...coords,
86
- zIndex: 10 + (region.editingLabels ? 5 : 0),
87
- width: 200,
88
- }}
89
- onMouseDown={(e) => e.preventDefault()}
90
- onMouseUp={(e) => e.preventDefault()}
91
- onMouseEnter={(e) => {
92
- if (region.editingLabels) {
93
- mouseEvents.onMouseUp(e)
94
- e.button = 1
95
- mouseEvents.onMouseUp(e)
96
- }
97
- }}
98
- >
99
- <div
100
- style={{
101
- position: "absolute",
102
- zIndex: 20,
103
- left: 0,
104
- ...(displayOnTop ? { bottom: 0 } : { top: 0 }),
105
- }}
106
- {...(!region.editingLabels
107
- ? copyWithout(mouseEvents, "onMouseDown", "onMouseUp")
108
- : {})}
109
- >
110
- <RegionLabel
111
- allowedClasses={regionClsList}
112
- allowedTags={regionTagList}
113
- onOpen={onBeginRegionEdit}
114
- onChange={onChangeRegion}
115
- onClose={onCloseRegionEdit}
116
- onDelete={onDeleteRegion}
117
- editing={region.editingLabels}
118
- region={region}
119
- regions={regions}
120
- imageSrc={imageSrc}
121
- onRegionClassAdded={onRegionClassAdded}
122
- allowComments={allowComments}
123
- />
124
- </div>
125
- </div>
126
- )
127
- })
128
- }
129
-
130
- export default RegionTags
@@ -1,58 +0,0 @@
1
- // @flow
2
-
3
- import React from "react"
4
- import Dialog from "@mui/material/Dialog"
5
- import DialogTitle from "@mui/material/DialogTitle"
6
- import DialogContent from "@mui/material/DialogContent"
7
- import DialogActions from "@mui/material/DialogActions"
8
- import Button from "@mui/material/Button"
9
- import Survey from "material-survey/components/Survey"
10
- import { useSettings } from "../SettingsProvider"
11
-
12
- export const SettingsDialog = ({ open, onClose }) => {
13
- const settings = useSettings()
14
- return (
15
- <Dialog open={open || false} onClose={onClose}>
16
- <DialogTitle>Settings</DialogTitle>
17
- <DialogContent style={{ minWidth: 400 }}>
18
- <Survey
19
- variant="flat"
20
- noActions
21
- defaultAnswers={settings}
22
- onQuestionChange={(q, a, answers) => settings.changeSetting(q, a)}
23
- form={{
24
- questions: [
25
- {
26
- type: "boolean",
27
- title: "Show Crosshairs",
28
- name: "showCrosshairs",
29
- },
30
- {
31
- type: "boolean",
32
- title: "Show Highlight Box",
33
- name: "showHighlightBox",
34
- },
35
- {
36
- type: "boolean",
37
- title: "WASD Mode",
38
- name: "wasdMode",
39
- },
40
- {
41
- type: "dropdown",
42
- title: "Video Playback Speed",
43
- name: "videoPlaybackSpeed",
44
- defaultValue: "1x",
45
- choices: ["0.25x", "0.5x", "1x", "2x"],
46
- },
47
- ],
48
- }}
49
- />
50
- </DialogContent>
51
- <DialogActions>
52
- <Button onClick={onClose}>Close</Button>
53
- </DialogActions>
54
- </Dialog>
55
- )
56
- }
57
-
58
- export default SettingsDialog
@@ -1,44 +0,0 @@
1
- // @flow
2
-
3
- import React, { createContext, useContext, useState } from "react"
4
-
5
- const defaultSettings = {
6
- showCrosshairs: false,
7
- showHighlightBox: true,
8
- wasdMode: true,
9
- }
10
-
11
- export const SettingsContext = createContext(defaultSettings)
12
-
13
- const pullSettingsFromLocalStorage = () => {
14
- if (!window || !window.localStorage) return {}
15
- let settings = {}
16
- for (let i = 0; i < window.localStorage.length; i++) {
17
- const key = window.localStorage.key(i)
18
- if (key.startsWith("settings_")) {
19
- try {
20
- settings[key.replace("settings_", "")] = JSON.parse(
21
- window.localStorage.getItem(key)
22
- )
23
- } catch (e) {}
24
- }
25
- }
26
- return settings
27
- }
28
-
29
- export const useSettings = () => useContext(SettingsContext)
30
-
31
- export const SettingsProvider = ({ children }) => {
32
- const [state, changeState] = useState(() => pullSettingsFromLocalStorage())
33
- const changeSetting = (setting: string, value: any) => {
34
- changeState({ ...state, [setting]: value })
35
- window.localStorage.setItem(`settings_${setting}`, JSON.stringify(value))
36
- }
37
- return (
38
- <SettingsContext.Provider value={{ ...state, changeSetting }}>
39
- {children}
40
- </SettingsContext.Provider>
41
- )
42
- }
43
-
44
- export default SettingsProvider
@@ -1,44 +0,0 @@
1
- import React from "react"
2
- import TextField from "@mui/material/TextField"
3
- import { makeStyles } from "@mui/styles"
4
- import { createTheme, ThemeProvider } from "@mui/material/styles"
5
-
6
- const theme = createTheme()
7
- const useStyles = makeStyles((theme) => ({
8
- shortcutKeyFieldWrapper: {
9
- paddingTop: 8,
10
- display: "inline-flex",
11
- width: "100%",
12
- },
13
- shortcutKeyText: {
14
- lineHeight: 0,
15
- },
16
- shortcutTextfield: {
17
- width: "100%",
18
- boxSizing: "border-box",
19
- textAlign: "center",
20
- },
21
- }))
22
-
23
- const ShortcutField = ({ actionId, actionName, keyName, onChangeShortcut }) => {
24
- const classes = useStyles()
25
-
26
- return (
27
- <ThemeProvider theme={theme}>
28
- <div className={classes.shortcutKeyFieldWrapper}>
29
- <TextField
30
- variant="outlined"
31
- label={actionName}
32
- className={classes.shortcutTextfield}
33
- value={keyName}
34
- onKeyPress={(e) => {
35
- onChangeShortcut(actionId, e.key)
36
- e.stopPropagation()
37
- }}
38
- />
39
- </div>
40
- </ThemeProvider>
41
- )
42
- }
43
-
44
- export default ShortcutField
@@ -1,129 +0,0 @@
1
- import React, { useState, useEffect } from "react"
2
- import SidebarBoxContainer from "../SidebarBoxContainer"
3
- import { setIn } from "seamless-immutable"
4
- import ShortcutField from "./ShortcutField"
5
-
6
- const defaultShortcuts = {
7
- select: {
8
- action: {
9
- type: "SELECT_TOOL",
10
- },
11
- name: "Select Region",
12
- key: "Escape",
13
- },
14
- zoom: {
15
- action: {
16
- type: "SELECT_TOOL",
17
- },
18
- name: "Zoom In/Out",
19
- key: "z",
20
- },
21
- "create-point": {
22
- action: {
23
- type: "SELECT_TOOL",
24
- },
25
- name: "Create Point",
26
- },
27
- "create-box": {
28
- action: {
29
- type: "SELECT_TOOL",
30
- },
31
- name: "Add Bounding Box",
32
- key: "b",
33
- },
34
- pan: {
35
- action: {
36
- type: "SELECT_TOOL",
37
- },
38
- name: "Pan",
39
- },
40
- "create-polygon": {
41
- action: {
42
- type: "SELECT_TOOL",
43
- },
44
- name: "Create Polygon",
45
- },
46
- "create-pixel": {
47
- action: {
48
- type: "SELECT_TOOL",
49
- },
50
- name: "Create Pixel",
51
- },
52
- "prev-image": {
53
- action: {
54
- type: "HEADER_BUTTON_CLICKED",
55
- buttonName: "Prev",
56
- },
57
- name: "Previous Image",
58
- key: "a",
59
- },
60
- "next-image": {
61
- action: {
62
- type: "HEADER_BUTTON_CLICKED",
63
- buttonName: "Next",
64
- },
65
- name: "Next Image",
66
- key: "d", //"ArrowRight"
67
- },
68
- }
69
-
70
- export default ({ onShortcutActionDispatched }) => {
71
- const [shortcuts, setShortcuts] = useState({}) // useLocalStorage
72
-
73
- useEffect(() => {
74
- const newShortcuts = { ...shortcuts }
75
- for (const actionId of Object.keys(defaultShortcuts)) {
76
- if (!newShortcuts[actionId]) {
77
- newShortcuts[actionId] = defaultShortcuts[actionId]
78
- }
79
- }
80
- setShortcuts(newShortcuts)
81
- }, [])
82
-
83
- const onChangeShortcut = (actionId, keyName) => {
84
- setShortcuts(setIn(shortcuts, [actionId, "key"], keyName))
85
- }
86
-
87
- useEffect(() => {
88
- const handleKeyPress = (e) => {
89
- for (const actionId in shortcuts) {
90
- const shortcut = shortcuts[actionId]
91
- if (!shortcut || !shortcut.key) {
92
- continue
93
- }
94
- if (e.key === shortcut.key) {
95
- onShortcutActionDispatched({
96
- ...shortcut.action,
97
- selectedTool: actionId,
98
- })
99
- }
100
- }
101
- }
102
-
103
- window.addEventListener("keypress", handleKeyPress)
104
-
105
- return () => {
106
- window.removeEventListener("keypress", handleKeyPress)
107
- document.activeElement.blur()
108
- }
109
- }, [shortcuts])
110
-
111
- return (
112
- <SidebarBoxContainer title="Shortcuts">
113
- {Object.keys(shortcuts)
114
- .map((actionId, index) => {
115
- if (!shortcuts[actionId]) return null
116
- return (
117
- <ShortcutField
118
- key={actionId}
119
- actionId={actionId}
120
- actionName={shortcuts[actionId].name}
121
- keyName={shortcuts[actionId].key || ""}
122
- onChangeShortcut={onChangeShortcut}
123
- />
124
- )
125
- })
126
- .filter(Boolean)}
127
- </SidebarBoxContainer>
128
- )
129
- }