react-image-annotate-master-custom 0.0.1

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 (73) hide show
  1. package/Annotator/index.js +164 -0
  2. package/Annotator/reducers/combine-reducers.js +14 -0
  3. package/Annotator/reducers/convert-expanding-line-to-polygon.js +73 -0
  4. package/Annotator/reducers/fix-twisted.js +4 -0
  5. package/Annotator/reducers/general-reducer.js +1073 -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 +69 -0
  17. package/FullImageSegmentationAnnotator/index.js +7 -0
  18. package/HighlightBox/index.js +105 -0
  19. package/HistorySidebarBox/index.js +71 -0
  20. package/ImageCanvas/index.js +428 -0
  21. package/ImageCanvas/region-tools.js +165 -0
  22. package/ImageCanvas/styles.js +31 -0
  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 +359 -0
  35. package/MainLayout/styles.js +25 -0
  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/README.md +101 -0
  41. package/RegionLabel/index.js +197 -0
  42. package/RegionLabel/styles.js +48 -0
  43. package/RegionSelectAndTransformBoxes/index.js +166 -0
  44. package/RegionSelectorSidebarBox/index.js +248 -0
  45. package/RegionSelectorSidebarBox/styles.js +53 -0
  46. package/RegionShapes/index.js +275 -0
  47. package/RegionTags/index.js +138 -0
  48. package/SettingsDialog/index.js +52 -0
  49. package/SettingsProvider/index.js +53 -0
  50. package/Shortcuts/ShortcutField.js +46 -0
  51. package/Shortcuts/index.js +133 -0
  52. package/ShortcutsManager/index.js +155 -0
  53. package/Sidebar/index.js +69 -0
  54. package/SidebarBoxContainer/index.js +93 -0
  55. package/SmallToolButton/index.js +42 -0
  56. package/TagsSidebarBox/index.js +105 -0
  57. package/TaskDescriptionSidebarBox/index.js +58 -0
  58. package/Theme/index.js +30 -0
  59. package/VideoOrImageCanvasBackground/index.js +151 -0
  60. package/colors.js +14 -0
  61. package/hooks/use-event-callback.js +10 -0
  62. package/hooks/use-exclude-pattern.js +24 -0
  63. package/hooks/use-load-image.js +26 -0
  64. package/hooks/use-window-size.js +46 -0
  65. package/hooks/xpattern.js +1 -0
  66. package/index.js +3 -0
  67. package/lib.js +3 -0
  68. package/package.json +91 -0
  69. package/stories.js +5 -0
  70. package/utils/get-from-local-storage.js +7 -0
  71. package/utils/get-hotkey-help-text.js +9 -0
  72. package/utils/get-landmarks-with-transform.js +40 -0
  73. package/utils/set-in-local-storage.js +3 -0
@@ -0,0 +1,359 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
+ import { FullScreen, useFullScreenHandle } from "react-full-screen";
4
+ import React, { useCallback, useRef } from "react";
5
+ import { makeStyles } from "@mui/styles";
6
+ import { createTheme, ThemeProvider } from "@mui/material/styles";
7
+ import { styled } from "@mui/material/styles";
8
+ import ClassSelectionMenu from "../ClassSelectionMenu";
9
+ import DebugBox from "../DebugSidebarBox";
10
+ import HistorySidebarBox from "../HistorySidebarBox";
11
+ import ImageCanvas from "../ImageCanvas";
12
+ import ImageSelector from "../ImageSelectorSidebarBox";
13
+ import KeyframeTimeline from "../KeyframeTimeline";
14
+ import KeyframesSelector from "../KeyframesSelectorSidebarBox";
15
+ import RegionSelector from "../RegionSelectorSidebarBox";
16
+ import SettingsDialog from "../SettingsDialog";
17
+ import TagsSidebarBox from "../TagsSidebarBox";
18
+ import TaskDescription from "../TaskDescriptionSidebarBox";
19
+ import Workspace from "react-material-workspace-layout/Workspace";
20
+ import classnames from "classnames";
21
+ import getActiveImage from "../Annotator/reducers/get-active-image";
22
+ import getHotkeyHelpText from "../utils/get-hotkey-help-text";
23
+ import iconDictionary from "./icon-dictionary";
24
+ import styles from "./styles";
25
+ import { useDispatchHotkeyHandlers } from "../ShortcutsManager";
26
+ import useEventCallback from "use-event-callback";
27
+ import useImpliedVideoRegions from "./use-implied-video-regions";
28
+ import useKey from "use-key-hook";
29
+ import { useSettings } from "../SettingsProvider";
30
+ import { withHotKeys } from "react-hotkeys"; // import Fullscreen from "../Fullscreen"
31
+
32
+ var emptyArr = [];
33
+ var theme = createTheme();
34
+ var useStyles = makeStyles(function (theme) {
35
+ return styles;
36
+ });
37
+ var HotkeyDiv = withHotKeys(function (_ref) {
38
+ var hotKeys = _ref.hotKeys,
39
+ children = _ref.children,
40
+ divRef = _ref.divRef,
41
+ props = _objectWithoutProperties(_ref, ["hotKeys", "children", "divRef"]);
42
+
43
+ return React.createElement("div", Object.assign({}, _objectSpread({}, hotKeys, props), {
44
+ ref: divRef
45
+ }), children);
46
+ });
47
+ var FullScreenContainer = styled("div")(function (_ref2) {
48
+ var theme = _ref2.theme;
49
+ return {
50
+ width: "100%",
51
+ height: "100%",
52
+ "& .fullscreen": {
53
+ width: "100%",
54
+ height: "100%"
55
+ }
56
+ };
57
+ });
58
+ export var MainLayout = function MainLayout(_ref3) {
59
+ var state = _ref3.state,
60
+ dispatch = _ref3.dispatch,
61
+ _ref3$alwaysShowNextB = _ref3.alwaysShowNextButton,
62
+ alwaysShowNextButton = _ref3$alwaysShowNextB === void 0 ? false : _ref3$alwaysShowNextB,
63
+ _ref3$alwaysShowPrevB = _ref3.alwaysShowPrevButton,
64
+ alwaysShowPrevButton = _ref3$alwaysShowPrevB === void 0 ? false : _ref3$alwaysShowPrevB,
65
+ RegionEditLabel = _ref3.RegionEditLabel,
66
+ onRegionClassAdded = _ref3.onRegionClassAdded,
67
+ hideHeader = _ref3.hideHeader,
68
+ hideHeaderText = _ref3.hideHeaderText,
69
+ _ref3$hideNext = _ref3.hideNext,
70
+ hideNext = _ref3$hideNext === void 0 ? false : _ref3$hideNext,
71
+ _ref3$hidePrev = _ref3.hidePrev,
72
+ hidePrev = _ref3$hidePrev === void 0 ? false : _ref3$hidePrev,
73
+ _ref3$hideClone = _ref3.hideClone,
74
+ hideClone = _ref3$hideClone === void 0 ? false : _ref3$hideClone,
75
+ _ref3$hideRegionLabel = _ref3.hideRegionLabel,
76
+ hideRegionLabel = _ref3$hideRegionLabel === void 0 ? false : _ref3$hideRegionLabel,
77
+ _ref3$hideSettings = _ref3.hideSettings,
78
+ hideSettings = _ref3$hideSettings === void 0 ? false : _ref3$hideSettings,
79
+ _ref3$hideFullScreen = _ref3.hideFullScreen,
80
+ hideFullScreen = _ref3$hideFullScreen === void 0 ? false : _ref3$hideFullScreen,
81
+ _ref3$hideSave = _ref3.hideSave,
82
+ hideSave = _ref3$hideSave === void 0 ? false : _ref3$hideSave,
83
+ _ref3$hideRightSideba = _ref3.hideRightSidebar,
84
+ hideRightSidebar = _ref3$hideRightSideba === void 0 ? false : _ref3$hideRightSideba,
85
+ _ref3$hideLeftSidebar = _ref3.hideLeftSidebar,
86
+ hideLeftSidebar = _ref3$hideLeftSidebar === void 0 ? false : _ref3$hideLeftSidebar;
87
+ var classes = useStyles();
88
+ var settings = useSettings();
89
+ var fullScreenHandle = useFullScreenHandle();
90
+ var memoizedActionFns = useRef({});
91
+
92
+ var action = function action(type) {
93
+ for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
94
+ params[_key - 1] = arguments[_key];
95
+ }
96
+
97
+ var fnKey = "".concat(type, "(").concat(params.join(","), ")");
98
+ if (memoizedActionFns.current[fnKey]) return memoizedActionFns.current[fnKey];
99
+
100
+ var fn = function fn() {
101
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
102
+ args[_key2] = arguments[_key2];
103
+ }
104
+
105
+ return params.length > 0 ? dispatch(_objectSpread({
106
+ type: type
107
+ }, params.reduce(function (acc, p, i) {
108
+ return acc[p] = args[i], acc;
109
+ }, {}))) : dispatch(_objectSpread({
110
+ type: type
111
+ }, args[0]));
112
+ };
113
+
114
+ memoizedActionFns.current[fnKey] = fn;
115
+ return fn;
116
+ };
117
+
118
+ var _getActiveImage = getActiveImage(state),
119
+ currentImageIndex = _getActiveImage.currentImageIndex,
120
+ activeImage = _getActiveImage.activeImage;
121
+
122
+ var nextImage;
123
+
124
+ if (currentImageIndex !== null) {
125
+ nextImage = state.images[currentImageIndex + 1];
126
+ }
127
+
128
+ useKey(function () {
129
+ return dispatch({
130
+ type: "CANCEL"
131
+ });
132
+ }, {
133
+ detectKeys: [27]
134
+ });
135
+ var isAVideoFrame = activeImage && activeImage.frameTime !== undefined;
136
+ var innerContainerRef = useRef();
137
+ var hotkeyHandlers = useDispatchHotkeyHandlers({
138
+ dispatch: dispatch
139
+ });
140
+ var impliedVideoRegions = useImpliedVideoRegions(state);
141
+ var refocusOnMouseEvent = useCallback(function (e) {
142
+ if (!innerContainerRef.current) return;
143
+ if (innerContainerRef.current.contains(document.activeElement)) return;
144
+
145
+ if (innerContainerRef.current.contains(e.target)) {
146
+ innerContainerRef.current.focus();
147
+ e.target.focus();
148
+ }
149
+ }, []);
150
+ var canvas = React.createElement(ImageCanvas, Object.assign({}, settings, {
151
+ showCrosshairs: settings.showCrosshairs && !["select", "pan", "zoom"].includes(state.selectedTool),
152
+ key: state.selectedImage,
153
+ showMask: state.showMask,
154
+ fullImageSegmentationMode: state.fullImageSegmentationMode,
155
+ autoSegmentationOptions: state.autoSegmentationOptions,
156
+ showTags: state.showTags,
157
+ allowedArea: state.allowedArea,
158
+ hideRegionLabel: hideRegionLabel,
159
+ modifyingAllowedArea: state.selectedTool === "modify-allowed-area",
160
+ regionClsList: state.regionClsList,
161
+ regionTagList: state.regionTagList,
162
+ regions: state.annotationType === "image" ? activeImage.regions || [] : impliedVideoRegions,
163
+ realSize: activeImage ? activeImage.realSize : undefined,
164
+ videoPlaying: state.videoPlaying,
165
+ imageSrc: state.annotationType === "image" ? activeImage.src : null,
166
+ videoSrc: state.annotationType === "video" ? state.videoSrc : null,
167
+ pointDistancePrecision: state.pointDistancePrecision,
168
+ createWithPrimary: state.selectedTool.includes("create"),
169
+ dragWithPrimary: state.selectedTool === "pan",
170
+ zoomWithPrimary: state.selectedTool === "zoom",
171
+ showPointDistances: state.showPointDistances,
172
+ videoTime: state.annotationType === "image" ? state.selectedImageFrameTime : state.currentVideoTime,
173
+ keypointDefinitions: state.keypointDefinitions,
174
+ onMouseMove: action("MOUSE_MOVE"),
175
+ onMouseDown: action("MOUSE_DOWN"),
176
+ onMouseUp: action("MOUSE_UP"),
177
+ onChangeRegion: action("CHANGE_REGION", "region"),
178
+ onBeginRegionEdit: action("OPEN_REGION_EDITOR", "region"),
179
+ onCloseRegionEdit: action("CLOSE_REGION_EDITOR", "region"),
180
+ onDeleteRegion: action("DELETE_REGION", "region"),
181
+ onBeginBoxTransform: action("BEGIN_BOX_TRANSFORM", "box", "directions"),
182
+ onBeginMovePolygonPoint: action("BEGIN_MOVE_POLYGON_POINT", "polygon", "pointIndex"),
183
+ onBeginMoveKeypoint: action("BEGIN_MOVE_KEYPOINT", "region", "keypointId"),
184
+ onAddPolygonPoint: action("ADD_POLYGON_POINT", "polygon", "point", "pointIndex"),
185
+ onSelectRegion: action("SELECT_REGION", "region"),
186
+ onBeginMovePoint: action("BEGIN_MOVE_POINT", "point"),
187
+ onImageLoaded: action("IMAGE_LOADED", "image"),
188
+ RegionEditLabel: RegionEditLabel,
189
+ onImageOrVideoLoaded: action("IMAGE_OR_VIDEO_LOADED", "metadata"),
190
+ onChangeVideoTime: action("CHANGE_VIDEO_TIME", "newTime"),
191
+ onChangeVideoPlaying: action("CHANGE_VIDEO_PLAYING", "isPlaying"),
192
+ onRegionClassAdded: onRegionClassAdded,
193
+ allowComments: state.allowComments
194
+ }));
195
+ var onClickIconSidebarItem = useEventCallback(function (item) {
196
+ dispatch({
197
+ type: "SELECT_TOOL",
198
+ selectedTool: item.name
199
+ });
200
+ });
201
+ var onClickHeaderItem = useEventCallback(function (item) {
202
+ if (item.name === "Fullscreen") {
203
+ fullScreenHandle.enter();
204
+ } else if (item.name === "Window") {
205
+ fullScreenHandle.exit();
206
+ }
207
+
208
+ dispatch({
209
+ type: "HEADER_BUTTON_CLICKED",
210
+ buttonName: item.name
211
+ });
212
+ });
213
+ var debugModeOn = Boolean(window.localStorage.$ANNOTATE_DEBUG_MODE && state);
214
+ var nextImageHasRegions = !nextImage || nextImage.regions && nextImage.regions.length > 0;
215
+ return React.createElement(ThemeProvider, {
216
+ theme: theme
217
+ }, React.createElement(FullScreenContainer, null, React.createElement(FullScreen, {
218
+ handle: fullScreenHandle,
219
+ onChange: function onChange(open) {
220
+ if (!open) {
221
+ fullScreenHandle.exit();
222
+ action("HEADER_BUTTON_CLICKED", "buttonName")("Window");
223
+ }
224
+ }
225
+ }, React.createElement(HotkeyDiv, {
226
+ tabIndex: -1,
227
+ divRef: innerContainerRef,
228
+ onMouseDown: refocusOnMouseEvent,
229
+ onMouseOver: refocusOnMouseEvent,
230
+ allowChanges: true,
231
+ handlers: hotkeyHandlers,
232
+ className: classnames(classes.container, state.fullScreen && "Fullscreen")
233
+ }, React.createElement(Workspace, {
234
+ allowFullscreen: true,
235
+ iconDictionary: iconDictionary,
236
+ hideHeader: hideHeader,
237
+ hideHeaderText: hideHeaderText,
238
+ headerLeftSide: [state.annotationType === "video" ? React.createElement(KeyframeTimeline, {
239
+ currentTime: state.currentVideoTime,
240
+ duration: state.videoDuration,
241
+ onChangeCurrentTime: action("CHANGE_VIDEO_TIME", "newTime"),
242
+ keyframes: state.keyframes
243
+ }) : activeImage ? React.createElement("div", {
244
+ className: classes.headerTitle
245
+ }, activeImage.name) : null].filter(Boolean),
246
+ headerItems: [!hidePrev && {
247
+ name: "Prev"
248
+ }, !hideNext && {
249
+ name: "Next"
250
+ }, state.annotationType !== "video" ? null : !state.videoPlaying ? {
251
+ name: "Play"
252
+ } : {
253
+ name: "Pause"
254
+ }, !hideClone && !nextImageHasRegions && activeImage.regions && {
255
+ name: "Clone"
256
+ }, !hideSettings && {
257
+ name: "Settings"
258
+ }, !hideFullScreen && (state.fullScreen ? {
259
+ name: "Window"
260
+ } : {
261
+ name: "Fullscreen"
262
+ }), !hideSave && {
263
+ name: "Save"
264
+ }].filter(Boolean),
265
+ onClickHeaderItem: onClickHeaderItem,
266
+ onClickIconSidebarItem: onClickIconSidebarItem,
267
+ selectedTools: [state.selectedTool, state.showTags && "show-tags", state.showMask && "show-mask"].filter(Boolean),
268
+ iconSidebarItems: hideLeftSidebar ? [] : [{
269
+ name: "select",
270
+ helperText: "Select" + getHotkeyHelpText("select_tool"),
271
+ alwaysShowing: true
272
+ }, {
273
+ name: "pan",
274
+ helperText: "Drag/Pan (right or middle click)" + getHotkeyHelpText("pan_tool"),
275
+ alwaysShowing: true
276
+ }, {
277
+ name: "zoom",
278
+ helperText: "Zoom In/Out (scroll)" + getHotkeyHelpText("zoom_tool"),
279
+ alwaysShowing: false
280
+ }, {
281
+ name: "show-tags",
282
+ helperText: "Show / Hide Tags",
283
+ alwaysShowing: false
284
+ }, {
285
+ name: "create-point",
286
+ helperText: "Add Point" + getHotkeyHelpText("create_point")
287
+ }, {
288
+ name: "create-box",
289
+ helperText: "Add Bounding Box" + getHotkeyHelpText("create_bounding_box")
290
+ }, {
291
+ name: "create-polygon",
292
+ helperText: "Add Polygon" + getHotkeyHelpText("create_polygon")
293
+ }, {
294
+ name: "create-line",
295
+ helperText: "Add Line"
296
+ }, {
297
+ name: "create-expanding-line",
298
+ helperText: "Add Expanding Line"
299
+ }, {
300
+ name: "create-keypoints",
301
+ helperText: "Add Keypoints (Pose)"
302
+ }, state.fullImageSegmentationMode && {
303
+ name: "show-mask",
304
+ alwaysShowing: true,
305
+ helperText: "Show / Hide Mask"
306
+ }, {
307
+ name: "modify-allowed-area",
308
+ helperText: "Modify Allowed Area"
309
+ }].filter(Boolean).filter(function (a) {
310
+ return a.alwaysShowing || state.enabledTools.includes(a.name);
311
+ }),
312
+ rightSidebarItems: hideRightSidebar ? [] : [debugModeOn && React.createElement(DebugBox, {
313
+ state: debugModeOn,
314
+ lastAction: state.lastAction
315
+ }), state.taskDescription && React.createElement(TaskDescription, {
316
+ description: state.taskDescription
317
+ }), state.regionClsList && React.createElement(ClassSelectionMenu, {
318
+ selectedCls: state.selectedCls,
319
+ regionClsList: state.regionClsList,
320
+ onSelectCls: action("SELECT_CLASSIFICATION", "cls")
321
+ }), state.labelImages && React.createElement(TagsSidebarBox, {
322
+ currentImage: activeImage,
323
+ imageClsList: state.imageClsList,
324
+ imageTagList: state.imageTagList,
325
+ onChangeImage: action("CHANGE_IMAGE", "delta"),
326
+ expandedByDefault: true
327
+ }), // (state.images?.length || 0) > 1 && (
328
+ // <ImageSelector
329
+ // onSelect={action("SELECT_REGION", "region")}
330
+ // images={state.images}
331
+ // />
332
+ // ),
333
+ React.createElement(RegionSelector, {
334
+ regions: activeImage ? activeImage.regions : emptyArr,
335
+ onSelectRegion: action("SELECT_REGION", "region"),
336
+ onDeleteRegion: action("DELETE_REGION", "region"),
337
+ onChangeRegion: action("CHANGE_REGION", "region")
338
+ }), state.keyframes && React.createElement(KeyframesSelector, {
339
+ onChangeVideoTime: action("CHANGE_VIDEO_TIME", "newTime"),
340
+ onDeleteKeyframe: action("DELETE_KEYFRAME", "time"),
341
+ onChangeCurrentTime: action("CHANGE_VIDEO_TIME", "newTime"),
342
+ currentTime: state.currentVideoTime,
343
+ duration: state.videoDuration,
344
+ keyframes: state.keyframes
345
+ }), React.createElement(HistorySidebarBox, {
346
+ history: state.history,
347
+ onRestoreHistory: action("RESTORE_HISTORY")
348
+ })].filter(Boolean)
349
+ }, canvas), React.createElement(SettingsDialog, {
350
+ open: state.settingsOpen,
351
+ onClose: function onClose() {
352
+ return dispatch({
353
+ type: "HEADER_BUTTON_CLICKED",
354
+ buttonName: "Settings"
355
+ });
356
+ }
357
+ })))));
358
+ };
359
+ export default MainLayout;
@@ -0,0 +1,25 @@
1
+ import { grey } from "@mui/material/colors";
2
+ export default {
3
+ container: {
4
+ display: "flex",
5
+ flexGrow: 1,
6
+ flexDirection: "column",
7
+ height: "100%",
8
+ maxHeight: "100vh",
9
+ backgroundColor: "#fff",
10
+ overflow: "hidden",
11
+ "&.fullscreen": {
12
+ position: "absolute",
13
+ zIndex: 99999,
14
+ left: 0,
15
+ right: 0,
16
+ top: 0,
17
+ bottom: 0
18
+ }
19
+ },
20
+ headerTitle: {
21
+ fontWeight: "bold",
22
+ color: grey[700],
23
+ paddingLeft: 16
24
+ }
25
+ };
File without changes
@@ -0,0 +1,13 @@
1
+ import { useMemo } from "react";
2
+ import getImpliedVideoRegions from "../Annotator/reducers/get-implied-video-regions.js";
3
+ var emptyArr = [];
4
+ export default (function (state) {
5
+ if (state.annotationType !== "video") return emptyArr;
6
+ var keyframes = state.keyframes,
7
+ _state$currentVideoTi = state.currentVideoTime,
8
+ currentVideoTime = _state$currentVideoTi === void 0 ? 0 : _state$currentVideoTi; // TODO memoize
9
+
10
+ return useMemo(function () {
11
+ return getImpliedVideoRegions(keyframes, currentVideoTime);
12
+ }, [keyframes, currentVideoTime]);
13
+ });
@@ -0,0 +1,73 @@
1
+ import React, { Fragment } from "react";
2
+ import { styled } from "@mui/material/styles";
3
+ import { createTheme, ThemeProvider } from "@mui/material/styles";
4
+ var theme = createTheme();
5
+ var Svg = styled("svg")(function (_ref) {
6
+ var theme = _ref.theme;
7
+ return {
8
+ pointerEvents: "none",
9
+ position: "absolute",
10
+ zIndex: 1,
11
+ left: 0,
12
+ top: 0,
13
+ width: "100%",
14
+ height: "100%",
15
+ "& text": {
16
+ fill: "#fff"
17
+ },
18
+ "& path": {
19
+ vectorEffect: "non-scaling-stroke",
20
+ strokeWidth: 2,
21
+ opacity: 0.5,
22
+ stroke: "#FFF",
23
+ fill: "none",
24
+ strokeDasharray: 5,
25
+ animationDuration: "4s",
26
+ animationTimingFunction: "linear",
27
+ animationIterationCount: "infinite",
28
+ animationPlayState: "running"
29
+ }
30
+ };
31
+ });
32
+ export var PointDistances = function PointDistances(_ref2) {
33
+ var projectRegionBox = _ref2.projectRegionBox,
34
+ regions = _ref2.regions,
35
+ pointDistancePrecision = _ref2.pointDistancePrecision,
36
+ realSize = _ref2.realSize;
37
+ return React.createElement(ThemeProvider, {
38
+ theme: theme
39
+ }, React.createElement(Svg, null, regions.filter(function (r1) {
40
+ return r1.type === "point";
41
+ }).flatMap(function (r1, i1) {
42
+ return regions.filter(function (r2, i2) {
43
+ return i2 > i1;
44
+ }).filter(function (r2) {
45
+ return r2.type === "point";
46
+ }).map(function (r2) {
47
+ var pr1 = projectRegionBox(r1);
48
+ var pr2 = projectRegionBox(r2);
49
+ var prm = {
50
+ x: (pr1.x + pr1.w / 2 + pr2.x + pr2.w / 2) / 2,
51
+ y: (pr1.y + pr1.h / 2 + pr2.y + pr2.h / 2) / 2
52
+ };
53
+ var displayDistance;
54
+
55
+ if (realSize) {
56
+ var w = realSize.w,
57
+ h = realSize.h,
58
+ unitName = realSize.unitName;
59
+ displayDistance = Math.sqrt(Math.pow(r1.x * w - r2.x * w, 2) + Math.pow(r1.y * h - r2.y * h, 2)).toFixed(pointDistancePrecision) + unitName;
60
+ } else {
61
+ displayDistance = (Math.sqrt(Math.pow(r1.x - r2.x, 2) + Math.pow(r1.y - r2.y, 2)) * 100).toFixed(pointDistancePrecision) + "%";
62
+ }
63
+
64
+ return React.createElement(Fragment, null, React.createElement("path", {
65
+ d: "M".concat(pr1.x + pr1.w / 2, ",").concat(pr1.y + pr1.h / 2, " L").concat(pr2.x + pr2.w / 2, ",").concat(pr2.y + pr2.h / 2)
66
+ }), React.createElement("text", {
67
+ x: prm.x,
68
+ y: prm.y
69
+ }, displayDistance));
70
+ });
71
+ })));
72
+ };
73
+ export default PointDistances;
@@ -0,0 +1,51 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
+ import React, { useState } from "react";
4
+ import { RemoveScroll } from "react-remove-scroll";
5
+ import { styled } from "@mui/material/styles";
6
+ import { createTheme, ThemeProvider } from "@mui/material/styles";
7
+ import useEventCallback from "use-event-callback";
8
+ var theme = createTheme();
9
+ var Container = styled("div")(function (_ref) {
10
+ var theme = _ref.theme;
11
+ return {
12
+ "& > div": {
13
+ width: "100%",
14
+ height: "100%"
15
+ }
16
+ };
17
+ });
18
+ export var PreventScrollToParents = function PreventScrollToParents(_ref2) {
19
+ var children = _ref2.children,
20
+ otherProps = _objectWithoutProperties(_ref2, ["children"]);
21
+
22
+ var _useState = useState(false),
23
+ _useState2 = _slicedToArray(_useState, 2),
24
+ mouseOver = _useState2[0],
25
+ changeMouseOver = _useState2[1];
26
+
27
+ var onMouseMove = useEventCallback(function (e) {
28
+ if (!mouseOver) changeMouseOver(true);
29
+
30
+ if (otherProps.onMouseMove) {
31
+ otherProps.onMouseMove(e);
32
+ }
33
+ });
34
+ var onMouseLeave = useEventCallback(function (e) {
35
+ setTimeout(function () {
36
+ if (mouseOver) {
37
+ changeMouseOver(false);
38
+ }
39
+ }, 100);
40
+ });
41
+ return React.createElement(ThemeProvider, {
42
+ theme: theme
43
+ }, React.createElement(Container, Object.assign({}, otherProps, {
44
+ onMouseMove: onMouseMove,
45
+ onMouseLeave: onMouseLeave
46
+ }), React.createElement(RemoveScroll, {
47
+ enabled: mouseOver,
48
+ removeScrollBar: false
49
+ }, children)));
50
+ };
51
+ export default PreventScrollToParents;
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # React Image Annotate
2
+
3
+ [![npm version](https://badge.fury.io/js/react-image-annotate.svg)](https://badge.fury.io/js/react-image-annotate)
4
+
5
+ The best image/video annotation tool ever. [Check out the demo here](https://universaldatatool.github.io/react-image-annotate/). Or the [code sandbox here](https://codesandbox.io/s/react-image-annotate-example-38tsc?file=/src/App.js:0-403).
6
+
7
+ ## Sponsors
8
+
9
+ [![wao.ai sponsorship image](https://s3.amazonaws.com/asset.workaround.online/sponsorship-banner-1.png)](https://wao.ai)
10
+
11
+ ## Features
12
+
13
+ - Simple input/output format
14
+ - Bounding Box, Point and Polygon Annotation
15
+ - Zooming, Scaling, Panning
16
+ - Multiple Images
17
+ - Cursor Crosshair
18
+
19
+ ![Screenshot of Annotator](https://user-images.githubusercontent.com/1910070/51199716-83c72080-18c5-11e9-837c-c3a89c8caef4.png)
20
+
21
+ ## Usage
22
+
23
+ `npm install react-image-annotate`
24
+
25
+ ```javascript
26
+ import React from "react";
27
+ import ReactImageAnnotate from "react-image-annotate";
28
+
29
+ const App = () => (
30
+ <ReactImageAnnotate
31
+ labelImages
32
+ regionClsList={["Alpha", "Beta", "Charlie", "Delta"]}
33
+ regionTagList={["tag1", "tag2", "tag3"]}
34
+ images={[
35
+ {
36
+ src: "https://placekitten.com/408/287",
37
+ name: "Image 1",
38
+ regions: []
39
+ }
40
+ ]}
41
+ />
42
+ );
43
+
44
+ export default App;
45
+
46
+ ```
47
+
48
+ To get the proper fonts, make sure to import the Inter UI or Roboto font, the
49
+ following line added to a css file should suffice.
50
+
51
+ ```css
52
+ @import url("https://rsms.me/inter/inter.css");
53
+ ```
54
+
55
+ ## Props
56
+
57
+ All of the following properties can be defined on the Annotator...
58
+
59
+ | Prop | Type (\* = required) | Description | Default |
60
+ | ------------------------ | ------------------------------------------------ | --------------------------------------------------------------------------------------- | ------------- |
61
+ | `taskDescription` | \*`string` | Markdown description for what to do in the image. | |
62
+ | `allowedArea` | `{ x: number, y: number, w: number, h: number }` | Area that is available for annotation. | Entire image. |
63
+ | `regionTagList` | `Array<string>` | Allowed "tags" (mutually inclusive classifications) for regions. | |
64
+ | `regionClsList` | `Array<string>` | Allowed "classes" (mutually exclusive classifications) for regions. | |
65
+ | `imageTagList` | `Array<string>` | Allowed tags for entire image. | |
66
+ | `imageClsList` | `Array<string>` | Allowed classes for entire image. | |
67
+ | `enabledTools` | `Array<string>` | Tools allowed to be used. e.g. "select", "create-point", "create-box", "create-polygon" | Everything. |
68
+ | `showTags` | `boolean` | Show tags and allow tags on regions. | `true` |
69
+ | `selectedImage` | `string` | URL of initially selected image. | |
70
+ | `images` | `Array<Image>` | Array of images to load into annotator | |
71
+ | `showPointDistances` | `boolean` | Show distances between points. | `false` |
72
+ | `pointDistancePrecision` | `number` | Precision on displayed points (e.g. 3 => 0.123) | |
73
+ | `onExit` | `MainLayoutState => any` | Called when "Save" is called. | |
74
+ | `RegionEditLabel` | `Node` | React Node overriding the form to update the region (see [`RegionLabel`](https://github.com/waoai/react-image-annotate/blob/master/src/RegionLabel/index.js)) | |
75
+ | `allowComments` | `boolean` | Show a textarea to add comments on each annotation. | `false` |
76
+ | `hidePrev` | `boolean` | Hide `Previous Image` button from the header bar. | `false` |
77
+ | `hideNext` | `boolean` | Hide `Next Image` button from the header bar. | `false` |
78
+ | `hideClone` | `boolean` | Hide `Clone` button from the header bar. | `false` |
79
+ | `hideSettings` | `boolean` | Hide `Settings` button from the header bar. | `false` |
80
+ | `hideFullScreen` | `boolean` | Hide `FullScreen/Window` button from the header bar. | `false` |
81
+ | `hideSave` | `boolean` | Hide `Save` button from the header bar. | `false` |
82
+
83
+ ## Developers
84
+
85
+ ### Development
86
+
87
+ This project uses [react-storybook](https://storybook.js.org/). To begin developing run the following commands in the cloned repo.
88
+
89
+ 1. `yarn install`
90
+ 2. `yarn storybook`
91
+
92
+ A browser tab will automatically open with the project components.
93
+
94
+ See more details in the [contributing guidelines](https://github.com/waoai/react-image-annotate/wiki/Setup-for-Development).
95
+
96
+ ### Icons
97
+
98
+ Consult these icon repositories:
99
+
100
+ - [Material Icons](https://material.io/tools/icons/)
101
+ - [Font Awesome Icons](https://fontawesome.com/icons?d=gallery&m=free)