@abidibo/react-cam-roi 0.2.3 → 0.2.4

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 (94) hide show
  1. package/README.md +0 -2
  2. package/dist/index.cjs.css +2 -0
  3. package/dist/index.cjs.css.map +1 -0
  4. package/dist/index.cjs.js +1582 -0
  5. package/dist/index.cjs.js.map +1 -0
  6. package/dist/index.esm.css +2 -0
  7. package/dist/index.esm.css.map +1 -0
  8. package/dist/index.esm.js +1576 -0
  9. package/dist/index.esm.js.map +1 -0
  10. package/package.json +17 -6
  11. package/dist/Components/BoolField/index.js +0 -13
  12. package/dist/Components/Button/index.js +0 -15
  13. package/dist/Components/EnumField/index.js +0 -16
  14. package/dist/Components/IconButton/index.js +0 -10
  15. package/dist/Components/Loader/index.js +0 -9
  16. package/dist/Components/Modal/index.js +0 -16
  17. package/dist/Components/NumberField/index.js +0 -13
  18. package/dist/Components/RoiEditor/Canvas.js +0 -30
  19. package/dist/Components/RoiEditor/ColorPicker.js +0 -12
  20. package/dist/Components/RoiEditor/Header.js +0 -14
  21. package/dist/Components/RoiEditor/Hooks.js +0 -328
  22. package/dist/Components/RoiEditor/ParameterField.js +0 -27
  23. package/dist/Components/RoiEditor/ParametersModalForm/index.js +0 -42
  24. package/dist/Components/RoiEditor/Polygon.js +0 -77
  25. package/dist/Components/RoiEditor/Polyline.js +0 -75
  26. package/dist/Components/RoiEditor/Rectangle.js +0 -73
  27. package/dist/Components/RoiEditor/RoisInfo.js +0 -43
  28. package/dist/Components/RoiEditor/ShapesList.js +0 -77
  29. package/dist/Components/RoiEditor/Toolbar.js +0 -27
  30. package/dist/Components/RoiEditor/TopBar.js +0 -21
  31. package/dist/Components/RoiEditor/Types.js +0 -23
  32. package/dist/Components/RoiEditor/Utils.js +0 -161
  33. package/dist/Components/RoiEditor/index.js +0 -99
  34. package/dist/Components/RoleField.js +0 -49
  35. package/dist/Components/TextField/index.js +0 -13
  36. package/dist/Components/Typography/index.js +0 -6
  37. package/dist/Icons/AnnotateIcon.js +0 -5
  38. package/dist/Icons/CloseIcon.js +0 -5
  39. package/dist/Icons/CopyIcon.js +0 -5
  40. package/dist/Icons/DeleteIcon.js +0 -5
  41. package/dist/Icons/EditIcon.js +0 -5
  42. package/dist/Icons/PointerIcon.js +0 -5
  43. package/dist/Icons/PolygonIcon.js +0 -5
  44. package/dist/Icons/PolylineIcon.js +0 -5
  45. package/dist/Icons/RectangleIcon.js +0 -5
  46. package/dist/Icons/SaveIcon.js +0 -5
  47. package/dist/Providers/EditorProvider.js +0 -29
  48. package/dist/Providers/UiProvider.js +0 -104
  49. package/dist/Types.js +0 -1
  50. package/dist/Utils/Dispatcher.js +0 -65
  51. package/dist/Utils/index.js +0 -16
  52. package/dist/index.js +0 -4
  53. /package/dist/{Components → types/Components}/BoolField/index.d.ts +0 -0
  54. /package/dist/{Components → types/Components}/Button/index.d.ts +0 -0
  55. /package/dist/{Components → types/Components}/EnumField/index.d.ts +0 -0
  56. /package/dist/{Components → types/Components}/IconButton/index.d.ts +0 -0
  57. /package/dist/{Components → types/Components}/Loader/index.d.ts +0 -0
  58. /package/dist/{Components → types/Components}/Modal/index.d.ts +0 -0
  59. /package/dist/{Components → types/Components}/NumberField/index.d.ts +0 -0
  60. /package/dist/{Components → types/Components}/RoiEditor/Canvas.d.ts +0 -0
  61. /package/dist/{Components → types/Components}/RoiEditor/ColorPicker.d.ts +0 -0
  62. /package/dist/{Components → types/Components}/RoiEditor/Header.d.ts +0 -0
  63. /package/dist/{Components → types/Components}/RoiEditor/Hooks.d.ts +0 -0
  64. /package/dist/{Components → types/Components}/RoiEditor/ParameterField.d.ts +0 -0
  65. /package/dist/{Components → types/Components}/RoiEditor/ParametersModalForm/index.d.ts +0 -0
  66. /package/dist/{Components → types/Components}/RoiEditor/Polygon.d.ts +0 -0
  67. /package/dist/{Components → types/Components}/RoiEditor/Polyline.d.ts +0 -0
  68. /package/dist/{Components → types/Components}/RoiEditor/Rectangle.d.ts +0 -0
  69. /package/dist/{Components → types/Components}/RoiEditor/RoisInfo.d.ts +0 -0
  70. /package/dist/{Components → types/Components}/RoiEditor/ShapesList.d.ts +0 -0
  71. /package/dist/{Components → types/Components}/RoiEditor/Toolbar.d.ts +0 -0
  72. /package/dist/{Components → types/Components}/RoiEditor/TopBar.d.ts +0 -0
  73. /package/dist/{Components → types/Components}/RoiEditor/Types.d.ts +0 -0
  74. /package/dist/{Components → types/Components}/RoiEditor/Utils.d.ts +0 -0
  75. /package/dist/{Components → types/Components}/RoiEditor/index.d.ts +0 -0
  76. /package/dist/{Components → types/Components}/RoleField.d.ts +0 -0
  77. /package/dist/{Components → types/Components}/TextField/index.d.ts +0 -0
  78. /package/dist/{Components → types/Components}/Typography/index.d.ts +0 -0
  79. /package/dist/{Icons → types/Icons}/AnnotateIcon.d.ts +0 -0
  80. /package/dist/{Icons → types/Icons}/CloseIcon.d.ts +0 -0
  81. /package/dist/{Icons → types/Icons}/CopyIcon.d.ts +0 -0
  82. /package/dist/{Icons → types/Icons}/DeleteIcon.d.ts +0 -0
  83. /package/dist/{Icons → types/Icons}/EditIcon.d.ts +0 -0
  84. /package/dist/{Icons → types/Icons}/PointerIcon.d.ts +0 -0
  85. /package/dist/{Icons → types/Icons}/PolygonIcon.d.ts +0 -0
  86. /package/dist/{Icons → types/Icons}/PolylineIcon.d.ts +0 -0
  87. /package/dist/{Icons → types/Icons}/RectangleIcon.d.ts +0 -0
  88. /package/dist/{Icons → types/Icons}/SaveIcon.d.ts +0 -0
  89. /package/dist/{Providers → types/Providers}/EditorProvider.d.ts +0 -0
  90. /package/dist/{Providers → types/Providers}/UiProvider.d.ts +0 -0
  91. /package/dist/{Types.d.ts → types/Types.d.ts} +0 -0
  92. /package/dist/{Utils → types/Utils}/Dispatcher.d.ts +0 -0
  93. /package/dist/{Utils → types/Utils}/index.d.ts +0 -0
  94. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abidibo/react-cam-roi",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "A react component for drawing ROI over images and managing metadata",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,7 +9,9 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/abidibo/react-cam-roi/issues"
11
11
  },
12
- "main": "dist/index.js",
12
+ "main": "dist/index.cjs.js",
13
+ "module": "dist/index.esm.js",
14
+ "types": "dist/types/index.d.ts",
13
15
  "type": "module",
14
16
  "files": [
15
17
  "dist"
@@ -19,14 +21,17 @@
19
21
  },
20
22
  "exports": {
21
23
  ".": {
22
- "types": "./dist/index.d.ts",
23
- "default": "./dist/index.js"
24
- }
24
+ "import": "./dist/index.esm.js",
25
+ "require": "./dist/index.cjs.js",
26
+ "types": "./dist/types/index.d.ts",
27
+ "style": "./dist/index.esm.css"
28
+ },
29
+ "./dist/index.esm.css": "./dist/index.esm.css"
25
30
  },
26
31
  "scripts": {
27
32
  "clean": "rimraf dist",
28
33
  "prebuild": "npm run clean",
29
- "build": "tsc",
34
+ "build": "rollup -c",
30
35
  "postbuild": "npm run copy-files",
31
36
  "copy-files": "copyfiles -u 1 src/**/*.module.css dist/",
32
37
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -66,6 +71,9 @@
66
71
  "@eslint/js": "^9.18.0",
67
72
  "@fontsource/roboto": "^5.1.1",
68
73
  "@mui/material": "^6.4.3",
74
+ "@rollup/plugin-commonjs": "^28.0.3",
75
+ "@rollup/plugin-node-resolve": "^16.0.1",
76
+ "@rollup/plugin-typescript": "^12.1.2",
69
77
  "@semantic-release/changelog": "^6.0.3",
70
78
  "@semantic-release/git": "^10.0.1",
71
79
  "@storybook/addon-essentials": "^8.4.7",
@@ -86,6 +94,9 @@
86
94
  "globals": "^15.14.0",
87
95
  "prettier": "^3.4.2",
88
96
  "rimraf": "^6.0.1",
97
+ "rollup": "^4.40.0",
98
+ "rollup-plugin-peer-deps-external": "^2.2.4",
99
+ "rollup-plugin-postcss": "^4.0.2",
89
100
  "semantic-release": "^24.2.2",
90
101
  "storybook": "^8.4.7",
91
102
  "typescript": "^5.7.3",
@@ -1,13 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from "react";
3
- import { UiContext } from "../../Providers/UiProvider";
4
- import { css } from "../../Utils";
5
- import styles from './BoolField.module.css';
6
- const BoolField = ({ onChange, value, label, helperText, error, readOnly = false, disabled = false, required = false, }) => {
7
- const { themeMode, Typography } = useContext(UiContext);
8
- const handleChange = (e) => {
9
- onChange(e.target.checked);
10
- };
11
- return (_jsxs("div", { className: css('bool-field-wrapper', styles, themeMode), children: [_jsx("label", { className: `${css('bool-field-label', styles, themeMode)} ${error ? css('bool-field-label-error', styles, null) : ''}`, children: _jsxs(Typography, { children: [label, required && ' *'] }) }), _jsx("input", { type: 'checkbox', className: `${css('bool-field', styles, themeMode)} ${error ? css('bool-field-error', styles, null) : ''}`, onChange: handleChange, checked: value, readOnly: readOnly, disabled: disabled }), helperText && (_jsx(Typography, { component: 'div', className: `${css('bool-field-helper-text', styles, themeMode)} ${error ? css('bool-field-helper-text-error', styles, null) : ''}`, children: helperText }))] }));
12
- };
13
- export default BoolField;
@@ -1,15 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- import { css } from '../../Utils';
5
- import styles from './Button.module.css';
6
- const Button = ({ onClick, primary, disabled, children }) => {
7
- const { themeMode, primaryColor } = useContext(UiContext);
8
- const style = {};
9
- if (primary) {
10
- style.backgroundColor = primaryColor;
11
- style.color = 'white';
12
- }
13
- return (_jsx("button", { className: `${css('button', styles, themeMode)}${disabled ? ` ${css('button-disabled', styles, themeMode)}` : ''}`, style: style, onClick: onClick, disabled: disabled, children: children }));
14
- };
15
- export default Button;
@@ -1,16 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- import { css } from '../../Utils';
5
- import styles from './EnumField.module.css';
6
- const EnumField = ({ onChange, value, label, helperText, error, options, disabled = false, required = false, multiple = false }) => {
7
- const { themeMode, Typography } = useContext(UiContext);
8
- const handleChange = (e) => {
9
- const selectedValues = Array.from(e.target.selectedOptions, (option) => {
10
- return isNaN(Number(option.value)) ? option.value : Number(option.value);
11
- });
12
- onChange(multiple ? selectedValues : selectedValues[0]);
13
- };
14
- return (_jsxs("div", { className: css('enum-field-wrapper', styles, themeMode), children: [_jsx("label", { className: `${css('enum-field-label', styles, themeMode)} ${error ? css('enum-field-label-error', styles, null) : ''}`, children: _jsxs(Typography, { children: [label, required && ' *'] }) }), _jsxs("select", { className: `${css('enum-field', styles, themeMode)} ${error ? css('enum-field-error', styles, null) : ''}`, onChange: handleChange, value: value, disabled: disabled, multiple: multiple, children: [!required && _jsx("option", { value: '' }), options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] }), helperText && (_jsx(Typography, { component: 'div', className: `${css('enum-field-helper-text', styles, themeMode)} ${error ? css('enum-field-helper-text-error', styles, null) : ''}`, children: helperText }))] }));
15
- };
16
- export default EnumField;
@@ -1,10 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- import { css } from '../../Utils';
5
- import styles from './IconButton.module.css';
6
- const IconButton = ({ children, disabled, onClick }) => {
7
- const { themeMode } = useContext(UiContext);
8
- return (_jsx("div", { className: `${css('icon-button', styles, themeMode)} ${disabled ? css('icon-button-disabled', styles, themeMode) : ''}`, onClick: disabled ? undefined : onClick, children: children }));
9
- };
10
- export default IconButton;
@@ -1,9 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- import styles from './Loader.module.css';
5
- import { css } from '../../Utils';
6
- export const Loader = () => {
7
- const { themeMode } = useContext(UiContext);
8
- return _jsx("div", { className: css('loader', styles, themeMode) });
9
- };
@@ -1,16 +0,0 @@
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, maxWidth, onSubmit }) => {
9
- const { themeMode, IconButton, Typography, Button, strings } = 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-${maxWidth}`, 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, _jsxs("div", { className: css('modal-footer', styles, themeMode), children: [_jsx(Button, { onClick: onClose, children: strings.cancel }), onSubmit && _jsx(Button, { primary: true, onClick: onSubmit, children: strings.save })] })] }) }), document.body);
15
- };
16
- export default Modal;
@@ -1,13 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- import { css } from '../../Utils';
5
- import styles from './NumberField.module.css';
6
- const NumberField = ({ onChange, value, label, required, helperText, error }) => {
7
- const { themeMode, Typography } = useContext(UiContext);
8
- const handleChange = (e) => {
9
- onChange(parseFloat(e.target.value));
10
- };
11
- return (_jsxs("div", { className: css('number-field-wrapper', styles, themeMode), children: [_jsx("label", { className: `${css('number-field-label', styles, themeMode)} ${error ? css('number-field-label-error', styles, null) : ''}`, children: _jsxs(Typography, { children: [label, required && ' *'] }) }), _jsx("input", { type: 'number', className: `${css('number-field', styles, themeMode)} ${error ? css('number-field-error', styles, null) : ''}`, onChange: handleChange, value: value !== null && value !== void 0 ? value : '' }), helperText && (_jsx(Typography, { component: 'div', className: `${css('number-field-helper-text', styles, themeMode)} ${error ? css('number-field-helper-text-error', styles, null) : ''}`, children: helperText }))] }));
12
- };
13
- export default NumberField;
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import * as fabric from 'fabric';
3
- import { useRef, useEffect, useState, useContext } from 'react';
4
- import { useEditorContext } from '../../Providers/EditorProvider';
5
- import { UiContext } from '../../Providers/UiProvider';
6
- import { initCanvasData, useDispatcherEvents, useTool } from './Hooks';
7
- const Canvas = ({ canvasSize, imageSize, initialData }) => {
8
- const { metadata, setMetadata, addShapes, editorId } = useEditorContext();
9
- const { enableLogs } = useContext(UiContext);
10
- const [initialized, setInitialized] = useState(false);
11
- console.log('before canvas ref');
12
- const canvasRef = useRef(null);
13
- console.log('after canvas ref');
14
- useTool(canvasRef.current);
15
- useDispatcherEvents(canvasRef.current);
16
- useEffect(() => {
17
- if (canvasSize.width !== 0 && canvasSize.height !== 0 && !initialized) {
18
- canvasRef.current = new fabric.Canvas(`react-cam-roi-canvas-${editorId}`);
19
- canvasRef.current.setDimensions({ width: canvasSize.width, height: canvasSize.height });
20
- initCanvasData(canvasRef, imageSize, addShapes, metadata, setMetadata, initialData, enableLogs);
21
- setInitialized(true);
22
- }
23
- return () => {
24
- var _a;
25
- (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
26
- };
27
- }, [canvasSize.width, canvasSize.height]); // eslint-disable-line
28
- return (_jsx("canvas", { id: `react-cam-roi-canvas-${editorId}`, style: { width: `${canvasSize.width}px`, height: `${canvasSize.height}px` } }));
29
- };
30
- export default Canvas;
@@ -1,12 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { useEditorContext } from '../../Providers/EditorProvider';
4
- import { UiContext } from '../../Providers/UiProvider';
5
- import { css } from '../../Utils';
6
- import styles from './ColorPicker.module.css';
7
- const ColorPicker = ({ style }) => {
8
- const { pickerColors, themeMode } = useContext(UiContext);
9
- const { activeColor, setActiveColor } = useEditorContext();
10
- return (_jsx("div", { style: style, className: styles.colorpickerWrapper, children: pickerColors.map((color) => (_jsx("div", { onClick: () => setActiveColor(color), className: `${css('colorpicker-button', styles, themeMode)} ${activeColor === color ? css('colorpicker-button-active', styles, themeMode) : ''}`, style: { backgroundColor: color } }, color))) }));
11
- };
12
- export default ColorPicker;
@@ -1,14 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { useEditorContext } from '../../Providers/EditorProvider';
4
- import { UiContext } from '../../Providers/UiProvider';
5
- import { css } from '../../Utils';
6
- import styles from './Header.module.css';
7
- import RoisInfo from './RoisInfo';
8
- const Header = () => {
9
- var _a;
10
- const { themeMode, Typography } = useContext(UiContext);
11
- const { configuration } = useEditorContext();
12
- return (_jsx("div", { className: css('header', styles, themeMode), children: _jsxs("div", { className: css('header-info', styles, themeMode), children: [((_a = configuration.options) === null || _a === void 0 ? void 0 : _a.description) && _jsx(Typography, { children: configuration.options.description }), _jsx(RoisInfo, {})] }) }));
13
- };
14
- export default Header;
@@ -1,328 +0,0 @@
1
- import * as fabric from 'fabric';
2
- import { useCallback, useContext, useEffect, useRef, useState } from 'react';
3
- import { useEditorContext } from '../../Providers/EditorProvider';
4
- import { UiContext } from '../../Providers/UiProvider';
5
- import { log, perc2Abs } from '../../Utils';
6
- import Dispatcher from '../../Utils/Dispatcher';
7
- import { copyPolygon, handleDoubleClickPolygon, handleMouseDownPolygon, handleMouseMovePolygon } from './Polygon';
8
- import { copyPolyline, handleDoubleClickPolyline, handleMouseDownPolyline, handleMouseMovePolyline } from './Polyline';
9
- import { copyRectangle, handleMouseDownRect, handleMouseMoveRect, handleMouseUpRect } from './Rectangle';
10
- import { canDrawShape } from './Utils';
11
- export const useImageSize = (imageUrl) => {
12
- const [imageSize, setImageSize] = useState({ width: 0, height: 0 });
13
- useEffect(() => {
14
- const image = new Image();
15
- image.src = imageUrl;
16
- image.onload = () => {
17
- setImageSize({ width: image.width, height: image.height });
18
- };
19
- }, [imageUrl]);
20
- return { imageSize, isReady: imageSize.width > 0 };
21
- };
22
- export const useCanvasSize = (imageUrl) => {
23
- console.log('before wrapper ref');
24
- const wrapperRef = useRef(null);
25
- console.log('after wrapper ref');
26
- const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
27
- const { imageSize, isReady } = useImageSize(imageUrl);
28
- useEffect(() => {
29
- if (wrapperRef.current) {
30
- const update = () => {
31
- const availableWidth = wrapperRef.current.offsetWidth;
32
- if (availableWidth < imageSize.width) {
33
- setCanvasSize({
34
- width: availableWidth,
35
- height: availableWidth * (imageSize.height / imageSize.width),
36
- });
37
- }
38
- else {
39
- setCanvasSize({
40
- width: imageSize.width,
41
- height: imageSize.height,
42
- });
43
- }
44
- };
45
- if (imageSize.width > 0 && wrapperRef.current) {
46
- update();
47
- }
48
- }
49
- }, [imageSize, wrapperRef.current]); // eslint-disable-line
50
- return { imageSize, canvasSize, wrapperRef, isReady };
51
- };
52
- export const initCanvasData = (canvasRef, imageSize, addShapes, metadata, setMetadata, initialData, enableLogs) => {
53
- log('info', enableLogs !== null && enableLogs !== void 0 ? enableLogs : false, 'Loading initial shapes data', initialData, canvasRef.current);
54
- if (initialData === null || initialData === void 0 ? void 0 : initialData.rois) {
55
- const m = [];
56
- const s = [];
57
- initialData.rois.forEach((r) => {
58
- var _a, _b, _c;
59
- log('info', enableLogs !== null && enableLogs !== void 0 ? enableLogs : false, 'Loading initial shape', r);
60
- const id = r.id;
61
- let shape;
62
- switch (r.type) {
63
- case "rect" /* ToolEnum.Rectangle */:
64
- shape = new fabric.Rect({
65
- left: perc2Abs(r.shape.left, imageSize.width),
66
- top: perc2Abs(r.shape.top, imageSize.height),
67
- originX: 'left',
68
- originY: 'top',
69
- width: perc2Abs(r.shape.width, imageSize.width),
70
- height: perc2Abs(r.shape.height, imageSize.height),
71
- fill: 'transparent',
72
- stroke: r.shape.color,
73
- strokeWidth: 2,
74
- strokeUniform: true,
75
- selectable: false,
76
- hasControls: true,
77
- hoverCursor: 'default',
78
- id,
79
- });
80
- (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.add(shape);
81
- break;
82
- case "polygon" /* ToolEnum.Polygon */:
83
- shape = new fabric.Polygon(r.shape.points.map(({ x, y }) => ({
84
- x: perc2Abs(x, imageSize.width),
85
- y: perc2Abs(y, imageSize.height),
86
- })), {
87
- top: perc2Abs(r.shape.top, imageSize.height),
88
- left: perc2Abs(r.shape.left, imageSize.width),
89
- fill: 'transparent',
90
- stroke: r.shape.color,
91
- strokeWidth: 2,
92
- selectable: false,
93
- hasControls: true,
94
- hoverCursor: 'default',
95
- // @ts-expect-error id is not included in types but the property is added and it works
96
- id,
97
- });
98
- (_b = canvasRef.current) === null || _b === void 0 ? void 0 : _b.add(shape);
99
- break;
100
- case "polyline" /* ToolEnum.Polyline */:
101
- shape = new fabric.Polyline(r.shape.points.map(({ x, y }) => ({
102
- x: perc2Abs(x, imageSize.width),
103
- y: perc2Abs(y, imageSize.height),
104
- })), {
105
- top: perc2Abs(r.shape.top, imageSize.height),
106
- left: perc2Abs(r.shape.left, imageSize.width),
107
- fill: 'transparent',
108
- stroke: r.shape.color,
109
- strokeWidth: 2,
110
- selectable: false,
111
- hasControls: true,
112
- hoverCursor: 'default',
113
- id,
114
- });
115
- (_c = canvasRef.current) === null || _c === void 0 ? void 0 : _c.add(shape);
116
- break;
117
- }
118
- m.push({ id, parameters: r.parameters, name: r.name, role: r.role });
119
- s.push({ id, type: r.type, shape });
120
- });
121
- addShapes(s);
122
- setMetadata(Object.assign(Object.assign({}, metadata), { rois: m }));
123
- }
124
- };
125
- export const useTool = (canvas) => {
126
- const { editorId, configuration, activeTool, activeColor, shapes, addShape } = useEditorContext();
127
- const { notify, strings } = useContext(UiContext);
128
- const [isDrawing, setIsDrawing] = useState(false);
129
- const [shape, setShape] = useState(null);
130
- const [originX, setOriginX] = useState(0);
131
- const [originY, setOriginY] = useState(0);
132
- const [startPos] = useState({ x: 0, y: 0 });
133
- const [points, setPoints] = useState([]);
134
- const [lines, setLines] = useState([]);
135
- // Handler for object selected event to update style settings
136
- const handleObjectSelected = useCallback((event) => {
137
- var _a;
138
- Dispatcher.emit(`canvas:${editorId}:shapeSelected`, (_a = event.selected) !== null && _a !== void 0 ? _a : null);
139
- }, [editorId]);
140
- // Handler for selection cleared event to reset selected shapes state
141
- const handleSelectionCleared = useCallback(() => {
142
- Dispatcher.emit(`canvas:${editorId}:shapeSelected`, null);
143
- }, [editorId]);
144
- useEffect(() => {
145
- if (!canvas) {
146
- return;
147
- }
148
- if (activeTool === "pointer" /* ToolEnum.Pointer */) {
149
- // enable selection
150
- canvas.selection = true;
151
- canvas.getObjects().forEach((object) => {
152
- object.selectable = true;
153
- });
154
- canvas.renderAll();
155
- }
156
- else {
157
- // disable selection
158
- canvas.selection = false;
159
- canvas.discardActiveObject();
160
- Dispatcher.emit(`canvas:${editorId}:shapeSelected`, null);
161
- canvas.renderAll();
162
- }
163
- const handleMouseDown = (event) => {
164
- switch (activeTool) {
165
- case "rect" /* ToolEnum.Rectangle */:
166
- if (!canDrawShape(configuration, "rect" /* ToolEnum.Rectangle */, shapes, notify, strings.cannotDrawMoreRectangles))
167
- return;
168
- handleMouseDownRect(event, canvas, activeColor, setOriginX, setOriginY, setShape, setIsDrawing);
169
- break;
170
- case "polygon" /* ToolEnum.Polygon */:
171
- if (!canDrawShape(configuration, "polygon" /* ToolEnum.Polygon */, shapes, notify, strings.cannotDrawMorePolygons))
172
- return;
173
- handleMouseDownPolygon(event, canvas, activeColor, setIsDrawing, points, setPoints, lines, setLines);
174
- break;
175
- case "polyline" /* ToolEnum.Polyline */:
176
- if (!canDrawShape(configuration, "polyline" /* ToolEnum.Polyline */, shapes, notify, strings.cannotDrawMorePolylines))
177
- return;
178
- handleMouseDownPolyline(event, canvas, activeColor, setIsDrawing, points, setPoints, lines, setLines);
179
- break;
180
- default:
181
- break;
182
- }
183
- };
184
- const handleMouseMove = (event) => {
185
- switch (activeTool) {
186
- case "rect" /* ToolEnum.Rectangle */:
187
- handleMouseMoveRect(event, canvas, originX, originY, shape, isDrawing);
188
- break;
189
- case "polygon" /* ToolEnum.Polygon */:
190
- handleMouseMovePolygon(event, canvas, isDrawing, lines);
191
- break;
192
- case "polyline" /* ToolEnum.Polyline */:
193
- handleMouseMovePolyline(event, canvas, isDrawing, lines);
194
- break;
195
- default:
196
- break;
197
- }
198
- };
199
- const handleMouseUp = () => {
200
- switch (activeTool) {
201
- case "rect" /* ToolEnum.Rectangle */:
202
- handleMouseUpRect(editorId, canvas, setIsDrawing, shape, setShape);
203
- break;
204
- default:
205
- break;
206
- }
207
- };
208
- const handleDoubleClick = () => {
209
- switch (activeTool) {
210
- case "polygon" /* ToolEnum.Polygon */:
211
- handleDoubleClickPolygon(editorId, canvas, activeColor, setIsDrawing, points, setPoints, lines, setLines);
212
- break;
213
- case "polyline" /* ToolEnum.Polyline */:
214
- handleDoubleClickPolyline(editorId, canvas, activeColor, setIsDrawing, points, setPoints, lines, setLines);
215
- break;
216
- default:
217
- break;
218
- }
219
- };
220
- canvas.on('mouse:down', handleMouseDown);
221
- canvas.on('mouse:move', handleMouseMove);
222
- canvas.on('mouse:up', handleMouseUp);
223
- canvas.on('mouse:dblclick', handleDoubleClick);
224
- canvas.on('selection:created', handleObjectSelected);
225
- canvas.on('selection:updated', handleObjectSelected);
226
- canvas.on('selection:cleared', handleSelectionCleared);
227
- return () => {
228
- canvas.off('mouse:down', handleMouseDown);
229
- canvas.off('mouse:move', handleMouseMove);
230
- canvas.off('mouse:up', handleMouseUp);
231
- canvas.off('mouse:dblclick', handleDoubleClick);
232
- canvas.off('selection:created', handleObjectSelected);
233
- canvas.off('selection:updated', handleObjectSelected);
234
- canvas.off('selection:cleared', handleSelectionCleared);
235
- };
236
- }, [
237
- activeTool,
238
- activeColor,
239
- isDrawing,
240
- shape,
241
- originX,
242
- originY,
243
- startPos,
244
- lines,
245
- points,
246
- canvas,
247
- addShape,
248
- handleObjectSelected,
249
- handleSelectionCleared,
250
- configuration,
251
- notify,
252
- strings,
253
- shapes,
254
- editorId,
255
- ]);
256
- };
257
- export const useDispatcherEvents = (canvas) => {
258
- const { configuration, shapes, addShape, setActiveTool, editorId } = useEditorContext();
259
- const { notify, strings } = useContext(UiContext);
260
- useEffect(() => {
261
- const removeShape = (_, id) => {
262
- const obj = canvas === null || canvas === void 0 ? void 0 : canvas.getObjects().find((s) => s.id === id);
263
- if (obj) {
264
- canvas === null || canvas === void 0 ? void 0 : canvas.remove(obj);
265
- }
266
- };
267
- const copyShape = (_, id) => {
268
- const obj = canvas === null || canvas === void 0 ? void 0 : canvas.getObjects().find((s) => s.id === id);
269
- let copy;
270
- switch (obj === null || obj === void 0 ? void 0 : obj.type) {
271
- case "polygon" /* ToolEnum.Polygon */:
272
- if (!canDrawShape(configuration, "polygon" /* ToolEnum.Polygon */, shapes, notify, strings.cannotDrawMorePolygons))
273
- return;
274
- copy = copyPolygon(editorId, canvas, obj);
275
- // @ts-expect-error id exists but his stupid ts does not know
276
- Dispatcher.emit(`canvas:${editorId}:selectShape`, copy.id);
277
- break;
278
- case "polyline" /* ToolEnum.Polyline */:
279
- if (!canDrawShape(configuration, "polyline" /* ToolEnum.Polyline */, shapes, notify, strings.cannotDrawMorePolylines))
280
- return;
281
- copy = copyPolyline(editorId, canvas, obj);
282
- // @ts-expect-error id exists but his stupid ts does not know
283
- Dispatcher.emit(`canvas:${editorId}:selectShape`, copy.id);
284
- break;
285
- case "rect" /* ToolEnum.Rectangle */:
286
- if (!canDrawShape(configuration, "rect" /* ToolEnum.Rectangle */, shapes, notify, strings.cannotDrawMoreRectangles))
287
- return;
288
- copy = copyRectangle(editorId, canvas, obj);
289
- // @ts-expect-error id exists but his stupid ts does not know
290
- Dispatcher.emit(`canvas:${editorId}:selectShape`, copy.id);
291
- break;
292
- default:
293
- break;
294
- }
295
- };
296
- const selectShape = (_, id) => {
297
- const obj = canvas === null || canvas === void 0 ? void 0 : canvas.getObjects().find((s) => s.id === id);
298
- if (obj) {
299
- canvas === null || canvas === void 0 ? void 0 : canvas.discardActiveObject();
300
- canvas === null || canvas === void 0 ? void 0 : canvas.setActiveObject(obj);
301
- canvas === null || canvas === void 0 ? void 0 : canvas.requestRenderAll();
302
- setActiveTool("pointer" /* ToolEnum.Pointer */);
303
- }
304
- };
305
- Dispatcher.register(`canvas:${editorId}:removeShape`, removeShape);
306
- Dispatcher.register(`canvas:${editorId}:copyShape`, copyShape);
307
- Dispatcher.register(`canvas:${editorId}:selectShape`, selectShape);
308
- return () => {
309
- Dispatcher.unregister(`canvas:${editorId}:removeShape`, removeShape);
310
- Dispatcher.unregister(`canvas:${editorId}:copyShape`, copyShape);
311
- Dispatcher.unregister(`canvas:${editorId}:selectShape`, selectShape);
312
- };
313
- }, [setActiveTool, canvas, addShape, configuration, shapes, notify, strings, editorId]);
314
- };
315
- export const useParametersForm = (parameters) => {
316
- const [errors, setErrors] = useState({});
317
- const [fields, setFields] = useState(parameters.reduce((acc, p) => (Object.assign(Object.assign({}, acc), { [p.codename]: p.value })), {}));
318
- const setField = (key) => (value) => {
319
- setFields(Object.assign(Object.assign({}, fields), { [key]: value }));
320
- };
321
- return {
322
- fields,
323
- setField,
324
- setFields,
325
- errors,
326
- setErrors,
327
- };
328
- };
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { UiContext } from '../../Providers/UiProvider';
4
- const ParameterField = ({ value, onChange, parameter, errors }) => {
5
- var _a, _b;
6
- const { TextField, NumberField, BoolField, EnumField, strings } = useContext(UiContext);
7
- const props = {
8
- required: parameter.required,
9
- label: `${parameter.label}${parameter.unit ? ` (${parameter.unit})` : ''}`,
10
- error: !!errors[parameter.codename],
11
- helperText: errors[parameter.codename]
12
- ? strings[errors[parameter.codename]]
13
- : parameter.description,
14
- };
15
- switch (parameter.type) {
16
- case 'string':
17
- return ((_a = parameter.options) === null || _a === void 0 ? void 0 : _a.length) ? (_jsx(EnumField, Object.assign({ value: value, onChange: (v) => onChange(v), options: parameter.options, multiple: parameter.multiple }, props))) : (_jsx(TextField, Object.assign({ type: "text", value: value, onChange: (v) => onChange(v) }, props)));
18
- case 'int':
19
- case 'float':
20
- return ((_b = parameter.options) === null || _b === void 0 ? void 0 : _b.length) ? (_jsx(EnumField, Object.assign({ value: value, onChange: (v) => onChange(v), options: parameter.options, multiple: parameter.multiple }, props))) : (_jsx(NumberField, Object.assign({ value: value, onChange: (v) => onChange(v) }, props)));
21
- case 'bool':
22
- return _jsx(BoolField, Object.assign({ value: value, onChange: (v) => onChange(v) }, props));
23
- default:
24
- return null;
25
- }
26
- };
27
- export default ParameterField;
@@ -1,42 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useContext, useState } from 'react';
3
- import { UiContext } from '../../../Providers/UiProvider';
4
- import { css } from '../../../Utils';
5
- import RoleField from '../../RoleField';
6
- import { useParametersForm } from '../Hooks';
7
- import ParameterField from '../ParameterField';
8
- import { validateParametersForm } from '../Utils';
9
- import styles from './ParametersModalForm.module.css';
10
- const ParametersModalForm = ({ title, onClose, parameters, data, onSubmit, shapeType, shapeName, shapeRole, }) => {
11
- const { Modal, TextField, strings } = useContext(UiContext);
12
- const [name, setName] = useState(shapeName !== null && shapeName !== void 0 ? shapeName : '');
13
- const [role, setRole] = useState(shapeRole !== null && shapeRole !== void 0 ? shapeRole : '');
14
- const { fields, setField, errors, setErrors } = useParametersForm(data);
15
- const handleSubmit = () => {
16
- if (validateParametersForm(parameters, fields, setErrors)) {
17
- const data = [
18
- ...parameters.map((p) => ({ codename: p.codename, value: fields[p.codename] })),
19
- ];
20
- if (shapeType) {
21
- onSubmit(data, { name, role });
22
- }
23
- else {
24
- onSubmit(data);
25
- }
26
- }
27
- };
28
- return (_jsx(Modal, { onClose: onClose, title: title, isOpen: true, maxWidth: "sm", onSubmit: handleSubmit, children: _jsxs("div", { className: css('form', styles, null), children: [shapeType && (_jsxs(_Fragment, { children: [_jsx(TextField, { required: true, label: strings.name, type: "text", value: name, onChange: setName, error: !!errors.name, helperText: errors.name }), _jsx(RoleField, { required: true, value: role, onChange: setRole, error: !!errors.name, helperText: errors.name, shapeType: shapeType })] })), parameters.map((parameter) => {
29
- switch (parameter.type) {
30
- case 'string':
31
- return (_jsx(ParameterField, { value: String(fields[parameter.codename]), onChange: setField(parameter.codename), parameter: parameter, errors: errors }, parameter.codename));
32
- case 'int':
33
- case 'float':
34
- return (_jsx(ParameterField, { value: fields[parameter.codename], onChange: setField(parameter.codename), parameter: parameter, errors: errors }, parameter.codename));
35
- case 'bool':
36
- return (_jsx(ParameterField, { value: fields[parameter.codename], onChange: setField(parameter.codename), parameter: parameter, errors: errors }, parameter.codename));
37
- default:
38
- return null;
39
- }
40
- })] }) }));
41
- };
42
- export default ParametersModalForm;