@abidibo/react-cam-roi 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/README.md +279 -16
  2. package/dist/Components/Modal/Modal.module.css +85 -0
  3. package/dist/Components/Modal/index.d.ts +9 -0
  4. package/dist/Components/Modal/index.js +16 -0
  5. package/dist/Components/RoiEditor/Canvas.js +2 -4
  6. package/dist/Components/RoiEditor/Hooks.d.ts +3 -4
  7. package/dist/Components/RoiEditor/Hooks.js +64 -16
  8. package/dist/Components/RoiEditor/ParametersModalForm.d.ts +5 -0
  9. package/dist/Components/RoiEditor/ParametersModalForm.js +8 -0
  10. package/dist/Components/RoiEditor/Polygon.d.ts +3 -2
  11. package/dist/Components/RoiEditor/Polygon.js +18 -0
  12. package/dist/Components/RoiEditor/Polyline.d.ts +12 -1
  13. package/dist/Components/RoiEditor/Polyline.js +18 -0
  14. package/dist/Components/RoiEditor/Rectangle.d.ts +17 -1
  15. package/dist/Components/RoiEditor/Rectangle.js +23 -1
  16. package/dist/Components/RoiEditor/ShapesList.d.ts +2 -0
  17. package/dist/Components/RoiEditor/ShapesList.js +34 -0
  18. package/dist/Components/RoiEditor/ShapesList.module.css +36 -0
  19. package/dist/Components/RoiEditor/Toolbar.js +10 -6
  20. package/dist/Components/RoiEditor/Toolbar.module.css +28 -0
  21. package/dist/Components/RoiEditor/Types.d.ts +47 -1
  22. package/dist/Components/RoiEditor/Types.js +15 -1
  23. package/dist/Components/RoiEditor/Utils.d.ts +5 -0
  24. package/dist/Components/RoiEditor/Utils.js +37 -0
  25. package/dist/Components/RoiEditor/index.d.ts +2 -0
  26. package/dist/Components/RoiEditor/index.js +4 -5
  27. package/dist/Components/Typography/index.d.ts +3 -0
  28. package/dist/Components/Typography/index.js +3 -2
  29. package/dist/Icons/AnnotateIcon.d.ts +6 -0
  30. package/dist/Icons/AnnotateIcon.js +5 -0
  31. package/dist/Icons/CloseIcon.d.ts +6 -0
  32. package/dist/Icons/CloseIcon.js +5 -0
  33. package/dist/Icons/CopyIcon.d.ts +6 -0
  34. package/dist/Icons/CopyIcon.js +5 -0
  35. package/dist/Providers/EditorProvider.d.ts +3 -2
  36. package/dist/Providers/EditorProvider.js +2 -2
  37. package/dist/Providers/UiProvider.d.ts +21 -2
  38. package/dist/Providers/UiProvider.js +26 -2
  39. package/dist/index.d.ts +2 -1
  40. package/dist/index.js +2 -1
  41. package/package.json +7 -3
  42. package/dist/Components/RoiEditor/Metadata.d.ts +0 -2
  43. package/dist/Components/RoiEditor/Metadata.js +0 -31
  44. package/dist/Components/RoiEditor/Metadata.module.css +0 -34
package/README.md CHANGED
@@ -4,15 +4,152 @@
4
4
 
5
5
  This is a react component which lets you draw regions of interest (ROI) over images, manage metadata and import/export everything.
6
6
 
7
+ Metadata are dynamic information that can be attached to the whole image or to each ROI. The ROI that can be drawn, and the metadata are controlled through a configuration object.
8
+
9
+ ![Screenshot](./react-cam-roi.png)
10
+
11
+ It provides one component: `RoiEditor` and one provider: `UiProvider`. The editor lets you draw regions of interest over a given image (url). Each has dynamic metadata attached (configured via api).
12
+ Export and import functionality is also provided.
13
+
14
+ Features:
15
+
16
+ - Autosizing of the editor: the canvas resizes to the size of the image, but it's also responsive, so if the container width is smaller, then the canvas is resized accordingly keeping the aspect ratio.
17
+ - Draw polylines, polygons and rectangles, change dimensions and rotate them.
18
+ - Support for dynamic metadata information attached to each shape and the whole image.
19
+ - Import and export shapes and metadata in json format.
20
+ - Highly customizable: shape colors, custom components and css classes.
21
+
7
22
  ## Installation
8
23
 
9
24
  ```
10
- npm install react-cam-roi
25
+ npm install @abidibo/react-cam-roi
11
26
  ```
12
27
 
13
28
  ## Usage
14
29
 
15
- TODO
30
+ ```ts
31
+ import { RoiEditor, UiProvider } from '@abidibo/react-cam-roi'
32
+ import { Typography, IconButton, Delete } from '@mui/material'
33
+
34
+ const MyComponent: React.FC = () => {
35
+ const themMode = 'light'
36
+ const config = {} // se below
37
+
38
+ return (
39
+ <UiProvider themeMode={themeMode} IconButton={IconButton} Typography={Typography} DeleteIcon={() => <Delete />}>
40
+ <RoiEditor imageUrl={'https://placecats.com/800/600'} configuration={config} />
41
+ </UiProvider>
42
+ )
43
+ }
44
+ ```
45
+
46
+ ## Configuration
47
+
48
+ The configuration prop defines which kind and how many ROIs can be drawn, along with metadata information. Here the types definitions and an example:
49
+
50
+ ```ts
51
+ // All types can be imported:
52
+ // import { Types } from '@abidibo/react-cam-roi'
53
+ // const { ToolEnum, ShapeType, DataTypeEnum, OperatorEnum, ConfigurationParameter, RoiConfiguration, Configuration } = Types
54
+
55
+ export const enum ToolEnum {
56
+ Pointer = 'pointer',
57
+ Polyline = 'polyline',
58
+ Polygon = 'polygon',
59
+ Rectangle = 'rect',
60
+ }
61
+
62
+ export type ShapeType = ToolEnum.Polyline | ToolEnum.Polygon | ToolEnum.Rectangle
63
+
64
+ export enum DataTypeEnum {
65
+ Integer = 'int',
66
+ Float = 'float',
67
+ String = 'string',
68
+ Boolean = 'bool',
69
+ }
70
+
71
+ export enum OperatorEnum {
72
+ Lt = 'lt',
73
+ Lte = 'lte',
74
+ Gt = 'gt',
75
+ Gte = 'gte',
76
+ Eq = 'eq',
77
+ }
78
+
79
+ export type ConfigurationParameter = {
80
+ codename: string
81
+ label: string
82
+ description: string
83
+ unit: string
84
+ type: DataTypeEnum
85
+ options: { value: number | string | boolean; label: string }[]
86
+ required: boolean
87
+ value: number | string | boolean | null
88
+ }
89
+
90
+ export type RoiConfiguration = {
91
+ role: string
92
+ type: Omit<ShapeType, 'pointer'>
93
+ multiplicity: {
94
+ operator: OperatorEnum
95
+ threshold: number
96
+ }
97
+ parameters: ConfigurationParameter[]
98
+ }
99
+
100
+ export type Configuration = {
101
+ parameters: ConfigurationParameter[]
102
+ rois: RoiConfiguration[]
103
+ }
104
+
105
+ export const configuration: Configuration = {
106
+ parameters: [
107
+ {
108
+ codename: 'analytics_1', // internal code
109
+ label: 'Analytics param 1', // to be shown in interface
110
+ description: 'This is some descriptive text', // tooltip
111
+ unit: 's', // unit
112
+ type: DataTypeEnum.Integer, // int, float, string, bool
113
+ options: [
114
+ // if filled -> enum of types type
115
+ {
116
+ value: 7,
117
+ label: 'Seven',
118
+ },
119
+ {
120
+ value: 10,
121
+ label: 'Ten',
122
+ },
123
+ ],
124
+ required: true, // true | false,
125
+ value: 10, // default value
126
+ },
127
+ ],
128
+ rois: [
129
+ {
130
+ role: 'invasion_area', // analytics role, do not show in interface
131
+ type: ToolEnum.Polygon,
132
+ multiplicity: {
133
+ // how many rois of this type can/should be created
134
+ operator: OperatorEnum.Lt, // lt | lte | gt | gte | eq
135
+ threshold: 2,
136
+ },
137
+ parameters: [
138
+ {
139
+ codename: 'threshold', // internal code
140
+ label: 'Alert threshold', // to be shown in interface
141
+ description: 'Threshold used for triggering alarms', // tooltip
142
+ unit: '%', // unit
143
+ type: DataTypeEnum.Integer, // int, float, string, bool
144
+ options: [],
145
+ required: true, // true / false,
146
+ value: null, // default value
147
+ },
148
+ ],
149
+ },
150
+ ],
151
+ }
152
+ ```
16
153
 
17
154
  ## Customization
18
155
 
@@ -20,14 +157,14 @@ You can customize many aspects of this library by using the `UiProvider`.
20
157
 
21
158
  - You can customize both the styles and the components use in this library. The library provides default components with an interface compatible witu mui components.
22
159
  - You can override them by using the `UiProvider`. But you can also use the default ones and just add your styling.
23
- - You can pass a theme mode which is used by the default components to determine the color scheme. It is also used to define custom classes you can use for styling.
160
+ - You can pass a theme mode which is used by the default components to determine the color scheme. It is also used to define custom classes you can use for styling.
24
161
  - You can define a primary color which is used for color or background of active elements.
25
162
  - You can define custom strings used here and there.
26
163
  - You can enable logs in the console by setting the `enableLogs` option to `true`.
27
164
 
28
- ``` tsx
29
- import { UiProvider, RoiEditor } from 'react-cam-roi'
165
+ ```tsx
30
166
  import IconButton from '@mui/material/IconButton'
167
+ import { UiProvider, RoiEditor } from 'react-cam-roi'
31
168
 
32
169
  const MyView: React.FC = () => {
33
170
  return (
@@ -40,19 +177,35 @@ const MyView: React.FC = () => {
40
177
 
41
178
  ### UiProvider
42
179
 
43
- ```ts
180
+ Props and types are defined later in this document.
181
+
182
+ ```ts
44
183
  type UiContextType = {
45
184
  children?: React.ReactNode
46
185
  enableLogs: boolean
47
186
  themeMode: 'light' | 'dark'
48
187
  primaryColor: string
49
188
  Typography: React.FC<TypographyProps>
189
+ Modal: React.FC<ModalProps>
50
190
  IconButton: React.FC<IconButtonProps>
51
191
  DeleteIcon: React.FC<DeleteIconProps>
52
192
  EditIcon: React.FC<EditIconProps>
53
193
  SelectIcon: React.FC<SelectIconProps>
194
+ notify: INotify
54
195
  strings: {
196
+ cannotDrawMorePolygons: string
197
+ cannotDrawMorePolylines: string
198
+ cannotDrawMoreRectangles: string
55
199
  id: string
200
+ mainParametersMetadata: string
201
+ polygon: string
202
+ polygonHelpText: string
203
+ polyline: string
204
+ polylineHelpText: string
205
+ rect: string
206
+ rectHelpText: string
207
+ pointer: string
208
+ pointerHelpText: string
56
209
  type: string
57
210
  }
58
211
  }
@@ -66,22 +219,55 @@ Here comes the list of components you can override using the `UiProvider`.
66
219
 
67
220
  ##### Interface
68
221
 
69
- ``` ts
222
+ ```ts
70
223
  type LoaderProps = {}
71
224
  ```
72
225
 
73
226
  ##### Classes
227
+
74
228
  - `react-cam-roi-loader`
75
229
  - `react-cam-roi-loader-light`
76
230
  - `react-cam-roi-loader-dark`
77
231
 
232
+ #### Modal
233
+
234
+ ##### Interface
235
+
236
+ ```ts
237
+ type ModalProps = {
238
+ children?: React.ReactNode
239
+ title: string
240
+ onClose: () => void
241
+ isOpen: boolean
242
+ size: 'xs' | 'sm' | 'md' | 'lg'
243
+ }
244
+ ```
245
+
246
+ ##### Classes
247
+
248
+ - `react-cam-roi-modal`
249
+ - `react-cam-roi-modal-light`
250
+ - `react-cam-roi-modal-dark`
251
+ - `react-cam-roi-modal-overlay`
252
+ - `react-cam-roi-modal-overlay-light`
253
+ - `react-cam-roi-modal-overlay-dark`
254
+ - `react-cam-roi-modal-header`
255
+ - `react-cam-roi-modal-header-light`
256
+ - `react-cam-roi-modal-header-dark`
257
+ - `react-cam-roi-modal-title`
258
+ - `react-cam-roi-modal-title-light`
259
+ - `react-cam-roi-modal-title-dark`
260
+
78
261
  #### Typography
79
262
 
80
263
  ##### Interface
81
264
 
82
- ``` ts
265
+ ```ts
83
266
  type TypographyProps = {
84
267
  children?: React.ReactNode
268
+ variant?: any // compatible with mui
269
+ component?: any // compatible with mui
270
+ className?: string
85
271
  }
86
272
  ```
87
273
 
@@ -89,7 +275,7 @@ type TypographyProps = {
89
275
 
90
276
  ##### Interface
91
277
 
92
- ``` ts
278
+ ```ts
93
279
  type IconButtonProps = {
94
280
  children?: React.ReactNode
95
281
  onClick?: (event: React.MouseEvent) => void
@@ -100,7 +286,7 @@ type IconButtonProps = {
100
286
 
101
287
  ##### Interface
102
288
 
103
- ``` ts
289
+ ```ts
104
290
  type DeleteIconProps = {
105
291
  color?: string
106
292
  style?: React.CSSProperties
@@ -111,7 +297,7 @@ type DeleteIconProps = {
111
297
 
112
298
  ##### Interface
113
299
 
114
- ``` ts
300
+ ```ts
115
301
  type EditIconProps = {
116
302
  color?: string
117
303
  style?: React.CSSProperties
@@ -122,13 +308,45 @@ type EditIconProps = {
122
308
 
123
309
  ##### Interface
124
310
 
125
- ``` ts
311
+ ```ts
126
312
  type SelectIconProps = {
127
313
  color?: string
128
314
  style?: React.CSSProperties
129
315
  }
130
316
  ```
131
317
 
318
+ #### CopyIcon
319
+
320
+ ##### Interface
321
+
322
+ ```ts
323
+ type CopyIconProps = {
324
+ color?: string
325
+ style?: React.CSSProperties
326
+ }
327
+ ```
328
+
329
+ #### AnnotateIcon
330
+
331
+ ##### Interface
332
+
333
+ ````ts
334
+ type AnnotateIconProps = {
335
+ color?: string
336
+ style?: React.CSSProperties
337
+ }
338
+
339
+ ### Functions
340
+
341
+ ``` ts
342
+ type INotify = { // compatible with toast (react-toastify)
343
+ info: (message: string) => void
344
+ warn: (message: string) => void
345
+ error: (message: string) => void
346
+ success: (message: string) => void
347
+ }
348
+ ````
349
+
132
350
  ### Styles
133
351
 
134
352
  There are components that cannot be overridden. But still you can use classes to style them.
@@ -145,11 +363,21 @@ There are components that cannot be overridden. But still you can use classes to
145
363
  - `react-cam-roi-toolbar-light`
146
364
  - `react-cam-roi-toolbar-dark`
147
365
 
148
- #### Metadata table
366
+ - `react-cam-roi-toolbar-spacer`
367
+ - `react-cam-roi-toolbar-spacer-light`
368
+ - `react-cam-roi-toolbar-spacer-dark`
369
+
370
+ #### Toolbar help text
371
+
372
+ - `react-cam-roi-toolbar-helper`
373
+ - `react-cam-roi-toolbar-helper-light`
374
+ - `react-cam-roi-toolbar-helper-dark`
149
375
 
150
- - `react-cam-roi-metadata-table`
151
- - `react-cam-roi-metadata-table-light`
152
- - `react-cam-roi-metadata-table-dark`
376
+ #### Shapes list
377
+
378
+ - `react-cam-roi-shapes-table`
379
+ - `react-cam-roi-shapes-table-light`
380
+ - `react-cam-roi-shapes-table-dark`
153
381
 
154
382
  #### Colorpicker button
155
383
 
@@ -160,3 +388,38 @@ There are components that cannot be overridden. But still you can use classes to
160
388
  - `react-cam-roi-colorpicker-button-active`
161
389
  - `react-cam-roi-colorpicker-button-active-light`
162
390
  - `react-cam-roi-colorpicker-button-active-dark`
391
+
392
+ ## Development
393
+
394
+ After cloning the repository and install dependencies (`yarn install`), you can run the following commands:
395
+
396
+ | Command | Description |
397
+ | ---------------- | --------------------- |
398
+ | `yarn clean` | Clean the dist folder |
399
+ | `yarn build` | Build the library |
400
+ | `yarn storybook` | Run storybook |
401
+
402
+ In order to start developing just run the storybook, then make changes to code and the storybook will be updated.
403
+
404
+ In order to test the library in onother local react project you can:
405
+
406
+ ```bash
407
+ $ cd react-cam-roi
408
+ $ yarn link
409
+ $ cd ../my-project
410
+ $ yarn link @abidibo/react-cam-roi
411
+ ```
412
+
413
+ Then rebuild this library to see your changes in the project.
414
+
415
+ ## CI
416
+
417
+ A github action pipeline is provided, it will publish the package to npm when a new tag is pushed. You need to add the `NPM_TOKEN` secret to your repository settings.
418
+
419
+ Example of deployment:
420
+
421
+ ```bash
422
+ $ npm version patch
423
+ $ git push
424
+ $ git push --tags
425
+ ```
@@ -0,0 +1,85 @@
1
+ .modal-overlay {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ display: flex;
8
+ justify-content: center;
9
+ align-items: center;
10
+ z-index: 9000;
11
+ }
12
+
13
+ .modal-overlay-light {
14
+ background-color: rgba(255, 255, 255, 0.7);
15
+ }
16
+
17
+ .modal-overlay-dark {
18
+ background-color: rgba(0, 0, 0, 0.7);
19
+ }
20
+
21
+ .modal {
22
+ max-width: 80%;
23
+ max-height: 80%;
24
+ overflow: auto;
25
+ padding: 20px;
26
+ border-radius: 5px;
27
+ }
28
+
29
+ .modal:focus-visible {
30
+ outline: none;
31
+ }
32
+
33
+ .modal-light {
34
+ background-color: #fff;
35
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
36
+ color: #000;
37
+ }
38
+
39
+ .modal-dark {
40
+ background-color: #333;
41
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
42
+ color: #fff;
43
+ }
44
+
45
+ .modal-xs {
46
+ width: 400px;
47
+ }
48
+
49
+ .modal-sm {
50
+ width: 600px;
51
+ }
52
+
53
+ .modal-md {
54
+ width: 800px;
55
+ }
56
+
57
+ .modal-lg {
58
+ width: 1000px;
59
+ }
60
+
61
+ .modal-xl {
62
+ width: 1200px;
63
+ }
64
+
65
+ .modal-header {
66
+ display: flex;
67
+ justify-content: space-between;
68
+ align-items: center;
69
+ margin-bottom: 1rem;
70
+ }
71
+
72
+ .modal-title {
73
+ font-size: 1.5rem;
74
+ font-weight: bold;
75
+ margin: 0;
76
+ }
77
+
78
+ .modal-title-light {
79
+ color: #000;
80
+ }
81
+
82
+ .modal-title-dark {
83
+ color: #fff;
84
+ }
85
+
@@ -0,0 +1,9 @@
1
+ import { PropsWithChildren } from 'react';
2
+ export type ModalProps = {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ title: string;
6
+ size: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
7
+ };
8
+ declare const Modal: React.FC<PropsWithChildren<ModalProps>>;
9
+ export default Modal;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createPortal } from 'react-dom';
3
+ import { useContext } from 'react';
4
+ import CloseIcon from '../../Icons/CloseIcon';
5
+ import { UiContext } from '../../Providers/UiProvider';
6
+ import { css } from '../../Utils';
7
+ import styles from './Modal.module.css';
8
+ const Modal = ({ isOpen, onClose, children, title, size }) => {
9
+ const { themeMode, IconButton, Typography } = useContext(UiContext);
10
+ const iconColor = themeMode === 'light' ? 'black' : 'white';
11
+ if (!isOpen) {
12
+ return null;
13
+ }
14
+ return createPortal(_jsx("div", { className: css('modal-overlay', styles, themeMode), children: _jsxs("div", { className: `${css('modal', styles, themeMode)} ${css(`modal-${size}`, styles, themeMode)}`, children: [_jsxs("div", { className: css('modal-header', styles, themeMode), children: [_jsx(Typography, { component: 'h6', className: css('modal-title', styles, themeMode), children: title }), _jsx(IconButton, { onClick: onClose, children: _jsx(CloseIcon, { color: iconColor }) })] }), children] }) }), document.body);
15
+ };
16
+ export default Modal;
@@ -1,13 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useRef, useEffect } from 'react';
3
3
  import * as fabric from 'fabric';
4
- import { useEditorContext } from '../../Providers/EditorProvider';
5
4
  import { useDispatcherEvents, useTool } from './Hooks';
6
5
  const Canvas = ({ canvasSize }) => {
7
- const { activeTool, setActiveTool, activeColor, addShape } = useEditorContext();
8
6
  const canvasRef = useRef(null);
9
- useTool(activeTool, activeColor, addShape, canvasRef.current);
10
- useDispatcherEvents(canvasRef.current, setActiveTool);
7
+ useTool(canvasRef.current);
8
+ useDispatcherEvents(canvasRef.current);
11
9
  useEffect(() => {
12
10
  canvasRef.current = new fabric.Canvas('react-cam-roi-canvas');
13
11
  canvasRef.current.setDimensions({ width: canvasSize.width, height: canvasSize.height });
@@ -1,5 +1,4 @@
1
1
  import * as fabric from 'fabric';
2
- import { Shape, ShapeType, ToolEnum } from './Types';
3
2
  export declare const useImageSize: (imageUrl: string) => {
4
3
  imageSize: {
5
4
  width: number;
@@ -16,8 +15,8 @@ export declare const useCanvasSize: (imageUrl: string) => {
16
15
  width: number;
17
16
  height: number;
18
17
  };
19
- wrapperRef: import("react").RefObject<HTMLDivElement | null>;
18
+ wrapperRef: import("react").RefObject<HTMLDivElement>;
20
19
  isReady: boolean;
21
20
  };
22
- export declare const useTool: (tool: ToolEnum, activeColor: string, addShape: (id: string, type: ShapeType, shape: Shape) => void, canvas: fabric.Canvas | null) => void;
23
- export declare const useDispatcherEvents: (canvas: fabric.Canvas | null, setActiveTool: (tool: ToolEnum) => void) => void;
21
+ export declare const useTool: (canvas: fabric.Canvas | null) => void;
22
+ export declare const useDispatcherEvents: (canvas: fabric.Canvas | null) => void;