@abidibo/react-cam-roi 0.14.1 → 0.14.3

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.
package/dist/index.cjs.js CHANGED
@@ -122,9 +122,13 @@ var formatString = function (str, placeholders) {
122
122
  });
123
123
  return str;
124
124
  };
125
- var abs2Perc = function (value, ref) { return Math.round((value / ref) * 100 * 100) / 100; };
126
- var perc2Abs = function (value, ref) { return Math.round((ref * value * 100) / 100) / 100; };
127
- var defaultTo = function (dft) { return function (value) { return value !== null && value !== void 0 ? value : dft; }; };
125
+ var abs2Perc = function (value, ref) { return Math.round((value / ref) * 100 * 10000) / 10000; };
126
+ var perc2Abs = function (value, ref) { return Math.round((ref / 100) * value * 10000) / 10000; };
127
+ var defaultTo = function (dft) {
128
+ return function (value) {
129
+ return value !== null && value !== void 0 ? value : dft;
130
+ };
131
+ };
128
132
  var compose = function () {
129
133
  var fns = [];
130
134
  for (var _i = 0; _i < arguments.length; _i++) {
@@ -204,7 +208,7 @@ var NumberField = function (_a) {
204
208
  var onChange = _a.onChange, value = _a.value, label = _a.label, required = _a.required, helperText = _a.helperText, error = _a.error;
205
209
  var _b = React.useContext(UiContext), themeMode = _b.themeMode, Typography = _b.Typography;
206
210
  var handleChange = function (e) {
207
- onChange(parseFloat(e.target.value));
211
+ onChange(e.target.value === '' ? null : parseFloat(e.target.value));
208
212
  };
209
213
  return (jsxRuntime.jsxs("div", { className: css('number-field-wrapper', styles$9, themeMode), children: [jsxRuntime.jsx("label", { className: "".concat(css('number-field-label', styles$9, themeMode), " ").concat(error ? css('number-field-label-error', styles$9, null) : ''), children: jsxRuntime.jsxs(Typography, { children: [label, required && ' *'] }) }), jsxRuntime.jsx("input", { type: 'number', className: "".concat(css('number-field', styles$9, themeMode), " ").concat(error ? css('number-field-error', styles$9, null) : ''), onChange: handleChange, value: value !== null && value !== void 0 ? value : '' }), helperText && (jsxRuntime.jsx(Typography, { component: 'div', className: "".concat(css('number-field-helper-text', styles$9, themeMode), " ").concat(error ? css('number-field-helper-text-error', styles$9, null) : ''), children: helperText }))] }));
210
214
  };
@@ -284,11 +288,14 @@ var canDrawShape = function (configuration, shapeType, shapes, notify, message)
284
288
  }
285
289
  return false;
286
290
  };
287
- var validateParametersForm = function (parameters, fields, setErrors, strings) {
291
+ var validateParametersForm = function (parameters, fields, setErrors, resetErrors) {
292
+ resetErrors();
288
293
  var err = {};
289
294
  parameters.forEach(function (p) {
290
- if (p.required && isEmpty(fields[p.codename])) {
291
- err[p.codename] = strings.requiredField;
295
+ if (p.required &&
296
+ (isEmpty(fields[p.codename]) ||
297
+ isNil(fields[p.codename]))) {
298
+ err[p.codename] = 'requiredField';
292
299
  }
293
300
  });
294
301
  if (Object.keys(err).length > 0) {
@@ -306,6 +313,9 @@ var isEmpty = function (v) {
306
313
  }
307
314
  return v === null || v === undefined;
308
315
  };
316
+ var isNil = function (v) {
317
+ return v === null || v === undefined;
318
+ };
309
319
  var validate$1 = function (configuration, presetName, shapes, metadata, strings) {
310
320
  var errors = [];
311
321
  // check presetName
@@ -367,9 +377,9 @@ var validate$1 = function (configuration, presetName, shapes, metadata, strings)
367
377
  });
368
378
  // check rois metadata
369
379
  Object.keys(shapes).forEach(function (shapeId) {
370
- var _a, _b;
371
- var type = shapes[shapeId].type;
372
- var confParameters = (_b = (_a = configuration.rois.find(function (r) { return r.type === type; })) === null || _a === void 0 ? void 0 : _a.parameters) !== null && _b !== void 0 ? _b : [];
380
+ var _a, _b, _c;
381
+ var role = (_a = metadata.rois.find(function (r) { return r.id === shapeId; })) === null || _a === void 0 ? void 0 : _a.role;
382
+ var confParameters = (_c = (_b = configuration.rois.find(function (r) { return r.role === role; })) === null || _b === void 0 ? void 0 : _b.parameters) !== null && _c !== void 0 ? _c : [];
373
383
  confParameters.forEach(function (p) {
374
384
  var _a, _b;
375
385
  if (p.required &&
@@ -380,7 +390,7 @@ var validate$1 = function (configuration, presetName, shapes, metadata, strings)
380
390
  });
381
391
  return [errors.length === 0, errors];
382
392
  };
383
- var fabricShapeToOutputShape = function (shape, type, imageSize) {
393
+ var fabricShapeToOutputShape = function (shape, type, canvasSize) {
384
394
  switch (type) {
385
395
  case "rect" /* ToolEnum.Rectangle */:
386
396
  return {
@@ -389,10 +399,10 @@ var fabricShapeToOutputShape = function (shape, type, imageSize) {
389
399
  scaleY: shape.scaleY,
390
400
  skewX: shape.skewX,
391
401
  skewY: shape.skewY,
392
- top: abs2Perc(shape.top, imageSize.height),
393
- left: abs2Perc(shape.left, imageSize.width),
394
- width: abs2Perc(shape.width, imageSize.width),
395
- height: abs2Perc(shape.height, imageSize.height),
402
+ top: abs2Perc(shape.top, canvasSize.height),
403
+ left: abs2Perc(shape.left, canvasSize.width),
404
+ width: abs2Perc(shape.width, canvasSize.width),
405
+ height: abs2Perc(shape.height, canvasSize.height),
396
406
  color: shape.stroke,
397
407
  };
398
408
  case "point" /* ToolEnum.Point */:
@@ -402,8 +412,8 @@ var fabricShapeToOutputShape = function (shape, type, imageSize) {
402
412
  scaleY: shape.scaleY,
403
413
  skewX: shape.skewX,
404
414
  skewY: shape.skewY,
405
- top: abs2Perc(shape.top, imageSize.height),
406
- left: abs2Perc(shape.left, imageSize.width),
415
+ top: abs2Perc(shape.top, canvasSize.height),
416
+ left: abs2Perc(shape.left, canvasSize.width),
407
417
  color: shape.stroke,
408
418
  };
409
419
  case "polygon" /* ToolEnum.Polygon */:
@@ -412,12 +422,12 @@ var fabricShapeToOutputShape = function (shape, type, imageSize) {
412
422
  points: shape.get('points').map(function (_a) {
413
423
  var x = _a.x, y = _a.y;
414
424
  return ({
415
- x: abs2Perc(x, imageSize.width),
416
- y: abs2Perc(y, imageSize.height),
425
+ x: abs2Perc(x, canvasSize.width),
426
+ y: abs2Perc(y, canvasSize.height),
417
427
  });
418
428
  }),
419
- top: abs2Perc(shape.top, imageSize.height),
420
- left: abs2Perc(shape.left, imageSize.width),
429
+ top: abs2Perc(shape.top, canvasSize.height),
430
+ left: abs2Perc(shape.left, canvasSize.width),
421
431
  color: shape.stroke,
422
432
  angle: shape.angle,
423
433
  scaleX: shape.scaleX,
@@ -463,22 +473,22 @@ function getAbsolutePoints(shape) {
463
473
  return { x: transformedPoint.x, y: transformedPoint.y };
464
474
  });
465
475
  }
466
- var fabricShapeToOutputCoords = function (shape, type, imageSize) {
476
+ var fabricShapeToOutputCoords = function (shape, type, canvasSize) {
467
477
  switch (type) {
468
478
  case "rect" /* ToolEnum.Rectangle */:
469
479
  return {
470
480
  points: getAbsoluteRectData(shape).map(function (_a) {
471
481
  var x = _a.x, y = _a.y;
472
482
  return ({
473
- x: abs2Perc(x, imageSize.width),
474
- y: abs2Perc(y, imageSize.height),
483
+ x: abs2Perc(x, canvasSize.width),
484
+ y: abs2Perc(y, canvasSize.height),
475
485
  });
476
486
  }),
477
487
  };
478
488
  case "point" /* ToolEnum.Point */:
479
489
  return {
480
- x: abs2Perc(shape.left, imageSize.width),
481
- y: abs2Perc(shape.top, imageSize.height),
490
+ x: abs2Perc(shape.left, canvasSize.width),
491
+ y: abs2Perc(shape.top, canvasSize.height),
482
492
  };
483
493
  case "polygon" /* ToolEnum.Polygon */:
484
494
  case "polyline" /* ToolEnum.Polyline */:
@@ -486,8 +496,8 @@ var fabricShapeToOutputCoords = function (shape, type, imageSize) {
486
496
  points: getAbsolutePoints(shape).map(function (_a) {
487
497
  var x = _a.x, y = _a.y;
488
498
  return ({
489
- x: abs2Perc(x, imageSize.width),
490
- y: abs2Perc(y, imageSize.height),
499
+ x: abs2Perc(x, canvasSize.width),
500
+ y: abs2Perc(y, canvasSize.height),
491
501
  });
492
502
  }),
493
503
  };
@@ -641,13 +651,6 @@ var UiProvider = function (_a) {
641
651
  return jsxRuntime.jsx(UiContext.Provider, { value: ctx, children: children });
642
652
  };
643
653
 
644
- var styles$7 = {"loader":"Loader-module_loader__6JyG7","spin":"Loader-module_spin__ZcV1b","loader-light":"Loader-module_loader-light__WlXKM","loader-dark":"Loader-module_loader-dark__mW1w5"};
645
-
646
- var Loader = function () {
647
- var themeMode = React.useContext(UiContext).themeMode;
648
- return jsxRuntime.jsx("div", { className: css('loader', styles$7, themeMode) });
649
- };
650
-
651
654
  /**
652
655
  * Event Dispatcher
653
656
  *
@@ -718,6 +721,13 @@ var Dispatcher = {
718
721
  }
719
722
  };
720
723
 
724
+ var styles$7 = {"loader":"Loader-module_loader__6JyG7","spin":"Loader-module_spin__ZcV1b","loader-light":"Loader-module_loader-light__WlXKM","loader-dark":"Loader-module_loader-dark__mW1w5"};
725
+
726
+ var Loader = function () {
727
+ var themeMode = React.useContext(UiContext).themeMode;
728
+ return jsxRuntime.jsx("div", { className: css('loader', styles$7, themeMode) });
729
+ };
730
+
721
731
  // Unique ID creation requires a high quality random # generator. In the browser we therefore
722
732
  // require the crypto API and do not support built-in fallback to lower quality random number
723
733
  // generators (like Math.random()).
@@ -782,6 +792,52 @@ function v4(options, buf, offset) {
782
792
  return stringify(rnds);
783
793
  }
784
794
 
795
+ var handleMouseDownPoint = function (event, editorId, canvas, activeColor, setOriginX, setOriginY) {
796
+ var pointer = canvas.getScenePoint(event.e);
797
+ setOriginX(pointer.x);
798
+ setOriginY(pointer.y);
799
+ var id = v4();
800
+ var newCircle = new Gn({
801
+ left: pointer.x,
802
+ top: pointer.y,
803
+ originX: 'center',
804
+ originY: 'center',
805
+ radius: 6,
806
+ fill: 'transparent',
807
+ stroke: activeColor,
808
+ strokeWidth: 2,
809
+ strokeUniform: true,
810
+ selectable: false,
811
+ hasControls: false,
812
+ hoverCursor: 'default',
813
+ id: id,
814
+ });
815
+ canvas.add(newCircle);
816
+ Dispatcher.emit("canvas:".concat(editorId, ":shapeAdded"), { id: id, type: "point" /* ToolEnum.Point */, shape: newCircle });
817
+ canvas.defaultCursor = 'default';
818
+ };
819
+ var copyPoint = function (editorId, canvas, point) {
820
+ var id = v4();
821
+ var copy = new Gn({
822
+ left: point.left + 10,
823
+ top: point.top + 10,
824
+ originX: 'center',
825
+ originY: 'center',
826
+ radius: 6,
827
+ fill: 'transparent',
828
+ stroke: point.stroke,
829
+ strokeWidth: point.strokeWidth,
830
+ strokeUniform: true,
831
+ selectable: false,
832
+ hasControls: false,
833
+ hoverCursor: 'default',
834
+ id: id,
835
+ });
836
+ canvas.add(copy);
837
+ Dispatcher.emit("canvas:".concat(editorId, ":shapeAdded"), { id: id, type: "point" /* ToolEnum.Point */, shape: copy });
838
+ return copy;
839
+ };
840
+
785
841
  var addPoint$1 = function (event, canvas, color, points, setPoints, lines, setLines) {
786
842
  var pointer = canvas.getScenePoint(event.e);
787
843
  var newPoint = { x: pointer.x, y: pointer.y };
@@ -1029,52 +1085,6 @@ var copyRectangle = function (editorId, canvas, rectangle) {
1029
1085
  return copy;
1030
1086
  };
1031
1087
 
1032
- var handleMouseDownPoint = function (event, editorId, canvas, activeColor, setOriginX, setOriginY) {
1033
- var pointer = canvas.getScenePoint(event.e);
1034
- setOriginX(pointer.x);
1035
- setOriginY(pointer.y);
1036
- var id = v4();
1037
- var newCircle = new Gn({
1038
- left: pointer.x,
1039
- top: pointer.y,
1040
- originX: 'center',
1041
- originY: 'center',
1042
- radius: 6,
1043
- fill: 'transparent',
1044
- stroke: activeColor,
1045
- strokeWidth: 2,
1046
- strokeUniform: true,
1047
- selectable: false,
1048
- hasControls: false,
1049
- hoverCursor: 'default',
1050
- id: id,
1051
- });
1052
- canvas.add(newCircle);
1053
- Dispatcher.emit("canvas:".concat(editorId, ":shapeAdded"), { id: id, type: "point" /* ToolEnum.Point */, shape: newCircle });
1054
- canvas.defaultCursor = 'default';
1055
- };
1056
- var copyPoint = function (editorId, canvas, point) {
1057
- var id = v4();
1058
- var copy = new Gn({
1059
- left: point.left + 10,
1060
- top: point.top + 10,
1061
- originX: 'center',
1062
- originY: 'center',
1063
- radius: 6,
1064
- fill: 'transparent',
1065
- stroke: point.stroke,
1066
- strokeWidth: point.strokeWidth,
1067
- strokeUniform: true,
1068
- selectable: false,
1069
- hasControls: false,
1070
- hoverCursor: 'default',
1071
- id: id,
1072
- });
1073
- canvas.add(copy);
1074
- Dispatcher.emit("canvas:".concat(editorId, ":shapeAdded"), { id: id, type: "point" /* ToolEnum.Point */, shape: copy });
1075
- return copy;
1076
- };
1077
-
1078
1088
  var useImageSize = function (imageUrl) {
1079
1089
  var _a = React.useState({ width: 0, height: 0 }), imageSize = _a[0], setImageSize = _a[1];
1080
1090
  React.useEffect(function () {
@@ -1114,7 +1124,7 @@ var useCanvasSize = function (imageUrl) {
1114
1124
  }, [imageSize, wrapperRef.current]); // eslint-disable-line
1115
1125
  return { imageSize: imageSize, canvasSize: canvasSize, wrapperRef: wrapperRef, isReady: isReady };
1116
1126
  };
1117
- var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMetadata, initialData, enableLogs) {
1127
+ var initCanvasData = function (canvasRef, canvasSize, addShapes, metadata, setMetadata, initialData, enableLogs) {
1118
1128
  log('info', enableLogs !== null && enableLogs !== void 0 ? enableLogs : false, 'Loading initial shapes data', initialData, canvasRef.current);
1119
1129
  if (initialData === null || initialData === void 0 ? void 0 : initialData.rois) {
1120
1130
  var m_1 = [];
@@ -1132,8 +1142,8 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1132
1142
  scaleY: r.shape.scaleY || 1,
1133
1143
  skewX: r.shape.skewX || 0,
1134
1144
  skewY: r.shape.skewY || 0,
1135
- left: perc2Abs(r.shape.left, imageSize.width),
1136
- top: perc2Abs(r.shape.top, imageSize.height),
1145
+ left: perc2Abs(r.shape.left, canvasSize.width),
1146
+ top: perc2Abs(r.shape.top, canvasSize.height),
1137
1147
  originX: 'center',
1138
1148
  originY: 'center',
1139
1149
  radius: 6,
@@ -1155,12 +1165,12 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1155
1165
  scaleY: r.shape.scaleY || 1,
1156
1166
  skewX: r.shape.skewX || 0,
1157
1167
  skewY: r.shape.skewY || 0,
1158
- left: perc2Abs(r.shape.left, imageSize.width),
1159
- top: perc2Abs(r.shape.top, imageSize.height),
1168
+ left: perc2Abs(r.shape.left, canvasSize.width),
1169
+ top: perc2Abs(r.shape.top, canvasSize.height),
1160
1170
  originX: 'left',
1161
1171
  originY: 'top',
1162
- width: perc2Abs(r.shape.width, imageSize.width),
1163
- height: perc2Abs(r.shape.height, imageSize.height),
1172
+ width: perc2Abs(r.shape.width, canvasSize.width),
1173
+ height: perc2Abs(r.shape.height, canvasSize.height),
1164
1174
  fill: 'transparent',
1165
1175
  stroke: r.shape.color,
1166
1176
  strokeWidth: 2,
@@ -1176,8 +1186,8 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1176
1186
  shape = new oo(r.shape.points.map(function (_a) {
1177
1187
  var x = _a.x, y = _a.y;
1178
1188
  return ({
1179
- x: perc2Abs(x, imageSize.width),
1180
- y: perc2Abs(y, imageSize.height),
1189
+ x: perc2Abs(x, canvasSize.width),
1190
+ y: perc2Abs(y, canvasSize.height),
1181
1191
  });
1182
1192
  }), {
1183
1193
  angle: r.shape.angle || 0,
@@ -1185,8 +1195,8 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1185
1195
  scaleY: r.shape.scaleY || 1,
1186
1196
  skewX: r.shape.skewX || 0,
1187
1197
  skewY: r.shape.skewY || 0,
1188
- top: perc2Abs(r.shape.top, imageSize.height),
1189
- left: perc2Abs(r.shape.left, imageSize.width),
1198
+ top: perc2Abs(r.shape.top, canvasSize.height),
1199
+ left: perc2Abs(r.shape.left, canvasSize.width),
1190
1200
  fill: 'transparent',
1191
1201
  stroke: r.shape.color,
1192
1202
  strokeWidth: 2,
@@ -1203,8 +1213,8 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1203
1213
  shape = new no(r.shape.points.map(function (_a) {
1204
1214
  var x = _a.x, y = _a.y;
1205
1215
  return ({
1206
- x: perc2Abs(x, imageSize.width),
1207
- y: perc2Abs(y, imageSize.height),
1216
+ x: perc2Abs(x, canvasSize.width),
1217
+ y: perc2Abs(y, canvasSize.height),
1208
1218
  });
1209
1219
  }), {
1210
1220
  angle: r.shape.angle || 0,
@@ -1212,8 +1222,8 @@ var initCanvasData = function (canvasRef, imageSize, addShapes, metadata, setMet
1212
1222
  scaleY: r.shape.scaleY || 1,
1213
1223
  skewX: r.shape.skewX || 0,
1214
1224
  skewY: r.shape.skewY || 0,
1215
- top: perc2Abs(r.shape.top, imageSize.height),
1216
- left: perc2Abs(r.shape.left, imageSize.width),
1225
+ top: perc2Abs(r.shape.top, canvasSize.height),
1226
+ left: perc2Abs(r.shape.left, canvasSize.width),
1217
1227
  fill: 'transparent',
1218
1228
  stroke: r.shape.color,
1219
1229
  strokeWidth: 2,
@@ -1441,17 +1451,29 @@ var useParametersForm = function (parameters) {
1441
1451
  setFields(__assign(__assign({}, fields), (_a = {}, _a[key] = value, _a)));
1442
1452
  };
1443
1453
  };
1454
+ var resetErrors = function () {
1455
+ setErrors({});
1456
+ };
1457
+ var reset = function () {
1458
+ setFields(parameters.reduce(function (acc, p) {
1459
+ var _a;
1460
+ return (__assign(__assign({}, acc), (_a = {}, _a[p.codename] = p.value, _a)));
1461
+ }, {}));
1462
+ setErrors({});
1463
+ };
1444
1464
  return {
1445
1465
  fields: fields,
1446
1466
  setField: setField,
1447
1467
  setFields: setFields,
1448
1468
  errors: errors,
1449
1469
  setErrors: setErrors,
1470
+ resetErrors: resetErrors,
1471
+ reset: reset,
1450
1472
  };
1451
1473
  };
1452
1474
 
1453
1475
  var Canvas = function (_a) {
1454
- var canvasRef = _a.canvasRef, canvasSize = _a.canvasSize, imageSize = _a.imageSize, initialData = _a.initialData;
1476
+ var canvasRef = _a.canvasRef, canvasSize = _a.canvasSize; _a.imageSize; var initialData = _a.initialData;
1455
1477
  var _b = useEditorContext(), metadata = _b.metadata, setMetadata = _b.setMetadata, addShapes = _b.addShapes, editorId = _b.editorId;
1456
1478
  var enableLogs = React.useContext(UiContext).enableLogs;
1457
1479
  var _c = React.useState(false), initialized = _c[0], setInitialized = _c[1];
@@ -1461,12 +1483,14 @@ var Canvas = function (_a) {
1461
1483
  if (canvasSize.width !== 0 && canvasSize.height !== 0 && !initialized) {
1462
1484
  canvasRef.current = new xn("react-cam-roi-canvas-".concat(editorId));
1463
1485
  canvasRef.current.setDimensions({ width: canvasSize.width, height: canvasSize.height });
1464
- initCanvasData(canvasRef, imageSize, addShapes, metadata, setMetadata, initialData, enableLogs);
1486
+ initCanvasData(canvasRef, canvasSize, addShapes, metadata, setMetadata, initialData, enableLogs);
1465
1487
  setInitialized(true);
1466
1488
  }
1467
1489
  return function () {
1468
1490
  var _a;
1469
- (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
1491
+ if (initialized) {
1492
+ (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
1493
+ }
1470
1494
  };
1471
1495
  }, [canvasSize.width, canvasSize.height]); // eslint-disable-line
1472
1496
  return (jsxRuntime.jsx("canvas", { id: "react-cam-roi-canvas-".concat(editorId), style: { width: "".concat(canvasSize.width, "px"), height: "".concat(canvasSize.height, "px") } }));
@@ -1534,7 +1558,7 @@ var RoleField = function (_a) {
1534
1558
  }
1535
1559
  });
1536
1560
  React.useEffect(function () {
1537
- if (required) {
1561
+ if (required && !value) {
1538
1562
  onChange(options[0]);
1539
1563
  }
1540
1564
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
@@ -1569,11 +1593,11 @@ var ParameterField = function (_a) {
1569
1593
  var styles$4 = {"form":"ParametersModalForm-module_form__WXebJ","fieldset":"ParametersModalForm-module_fieldset__V-ywT","legend":"ParametersModalForm-module_legend__F6CPv","legend-light":"ParametersModalForm-module_legend-light__X9tWX","legend-dark":"ParametersModalForm-module_legend-dark__isTas"};
1570
1594
 
1571
1595
  var ParametersModalForm = function (_a) {
1572
- var title = _a.title, onClose = _a.onClose, parameters = _a.parameters, data = _a.data, onSubmit = _a.onSubmit, shapeType = _a.shapeType, shapeName = _a.shapeName, shapeRole = _a.shapeRole, noModal = _a.noModal, readOnly = _a.readOnly;
1596
+ var title = _a.title, onClose = _a.onClose, parameters = _a.parameters, rolesParameters = _a.rolesParameters, data = _a.data, onSubmit = _a.onSubmit, shapeType = _a.shapeType, shapeName = _a.shapeName, shapeRole = _a.shapeRole, noModal = _a.noModal, readOnly = _a.readOnly;
1573
1597
  var _b = React.useContext(UiContext), Modal = _b.Modal, TextField = _b.TextField, strings = _b.strings, themeMode = _b.themeMode, Typography = _b.Typography;
1574
1598
  var _c = React.useState(shapeName !== null && shapeName !== void 0 ? shapeName : ''), name = _c[0], setName = _c[1];
1575
1599
  var _d = React.useState(shapeRole !== null && shapeRole !== void 0 ? shapeRole : ''), role = _d[0], setRole = _d[1];
1576
- var _e = useParametersForm(data), fields = _e.fields, setField = _e.setField, errors = _e.errors, setErrors = _e.setErrors;
1600
+ var _e = useParametersForm(data), fields = _e.fields, setField = _e.setField, errors = _e.errors, setErrors = _e.setErrors, resetErrors = _e.resetErrors, reset = _e.reset;
1577
1601
  var readonlyFields = data.reduce(function (acc, p) {
1578
1602
  var _a;
1579
1603
  return (__assign(__assign({}, acc), (_a = {}, _a[p.codename] = p.value, _a)));
@@ -1584,12 +1608,25 @@ var ParametersModalForm = function (_a) {
1584
1608
  handleSubmit();
1585
1609
  }
1586
1610
  }, [fields]);
1611
+ var currentParameters = shapeType
1612
+ ? defaultTo([])(rolesParameters === null || rolesParameters === void 0 ? void 0 : rolesParameters[role])
1613
+ : defaultTo([])(parameters);
1614
+ // add a listener in order for general save to call validate
1615
+ React.useEffect(function () {
1616
+ var validate = function () {
1617
+ validateParametersForm(currentParameters, fields, setErrors, resetErrors);
1618
+ };
1619
+ Dispatcher.register('editor:save', validate);
1620
+ return function () {
1621
+ Dispatcher.unregister('editor:save', validate);
1622
+ };
1623
+ }, [currentParameters, fields, setErrors, resetErrors]);
1587
1624
  var handleSubmit = function () {
1588
1625
  if (shapeType && name === '') {
1589
1626
  setErrors({ name: strings.requiredField });
1590
1627
  }
1591
- else if (!noModal || validateParametersForm(parameters, fields, setErrors, strings)) {
1592
- var data_1 = __spreadArray([], parameters.map(function (p) { return ({ codename: p.codename, value: fields[p.codename] }); }), true);
1628
+ else if (noModal || validateParametersForm(currentParameters, fields, setErrors, resetErrors)) {
1629
+ var data_1 = __spreadArray([], currentParameters.map(function (p) { return ({ codename: p.codename, value: fields[p.codename] }); }), true);
1593
1630
  if (shapeType) {
1594
1631
  onSubmit(data_1, { name: name, role: role });
1595
1632
  }
@@ -1599,7 +1636,7 @@ var ParametersModalForm = function (_a) {
1599
1636
  }
1600
1637
  };
1601
1638
  // group parameters by fieldset
1602
- var groupedParameters = parameters.reduce(function (acc, p) {
1639
+ var groupedParameters = currentParameters.reduce(function (acc, p) {
1603
1640
  if (acc[p.fieldSet || '']) {
1604
1641
  acc[p.fieldSet || ''].push(p);
1605
1642
  }
@@ -1608,7 +1645,7 @@ var ParametersModalForm = function (_a) {
1608
1645
  }
1609
1646
  return acc;
1610
1647
  }, {});
1611
- var form = (jsxRuntime.jsxs("div", { className: css('form', styles$4, null), children: [shapeType && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(TextField, { required: true, label: strings.name, type: "text", value: name, onChange: compose(setName, defaultTo('')), error: !!errors.name, helperText: errors.name, readOnly: readOnly }), jsxRuntime.jsx(RoleField, { required: true, value: role, onChange: compose(setRole, defaultTo('')), error: !!errors.role, helperText: errors.role, shapeType: shapeType, readOnly: readOnly, disabled: readOnly })] })), Object.keys(groupedParameters)
1648
+ var form = (jsxRuntime.jsxs("div", { className: css('form', styles$4, null), children: [shapeType && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(TextField, { required: true, label: strings.name, type: "text", value: name, onChange: compose(setName, defaultTo('')), error: !!errors.name, helperText: errors.name, readOnly: readOnly }), jsxRuntime.jsx(RoleField, { required: true, value: role, onChange: compose(reset, setRole, defaultTo('')), error: !!errors.role, helperText: errors.role, shapeType: shapeType, readOnly: readOnly, disabled: readOnly })] })), Object.keys(groupedParameters)
1612
1649
  .sort()
1613
1650
  .map(function (fieldSet) { return (jsxRuntime.jsxs("div", { className: css('fieldset', styles$4, themeMode), children: [fieldSet && (jsxRuntime.jsx(Typography, { component: "div", className: css('legend', styles$4, themeMode), children: fieldSet })), groupedParameters[fieldSet].map(function (parameter) {
1614
1651
  switch (parameter.type) {
@@ -1616,7 +1653,9 @@ var ParametersModalForm = function (_a) {
1616
1653
  return (jsxRuntime.jsx(ParameterField, { value: String((readOnly ? readonlyFields : fields)[parameter.codename]), onChange: setField(parameter.codename), parameter: parameter, errors: errors, readOnly: readOnly }, parameter.codename));
1617
1654
  case 'int':
1618
1655
  case 'float':
1619
- return (jsxRuntime.jsx(ParameterField, { value: (readOnly ? readonlyFields : fields)[parameter.codename], onChange: setField(parameter.codename), parameter: parameter, errors: errors, readOnly: readOnly }, parameter.codename));
1656
+ return (jsxRuntime.jsx(ParameterField, { value: (readOnly ? readonlyFields : fields)[parameter.codename] === ''
1657
+ ? null
1658
+ : (readOnly ? readonlyFields : fields)[parameter.codename], onChange: setField(parameter.codename), parameter: parameter, errors: errors, readOnly: readOnly }, parameter.codename));
1620
1659
  case 'bool':
1621
1660
  return (jsxRuntime.jsx(ParameterField, { value: (readOnly ? readonlyFields : fields)[parameter.codename], onChange: setField(parameter.codename), parameter: parameter, errors: errors, readOnly: readOnly }, parameter.codename));
1622
1661
  default:
@@ -1629,16 +1668,16 @@ var ParametersModalForm = function (_a) {
1629
1668
  var styles$3 = {"shapes-table":"ShapesList-module_shapes-table__sx5Xp","shapes-table-light":"ShapesList-module_shapes-table-light__TbtKn","shapes-table-dark":"ShapesList-module_shapes-table-dark__siyhV","shapes-row-selected-light":"ShapesList-module_shapes-row-selected-light__-0gaE","shapes-row-selected-dark":"ShapesList-module_shapes-row-selected-dark__bGR3a","shapes-row-even-light":"ShapesList-module_shapes-row-even-light__2eUZX","shapes-row-even-dark":"ShapesList-module_shapes-row-even-dark__eyECv","shapes-row-odd-light":"ShapesList-module_shapes-row-odd-light__vZzPj","shapes-row-odd-dark":"ShapesList-module_shapes-row-odd-dark__TWGAu","shapesTableName":"ShapesList-module_shapesTableName__9Q6i1","shapesTableColor":"ShapesList-module_shapesTableColor__Iyd33"};
1630
1669
 
1631
1670
  var ShapesList = function () {
1632
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1633
- var _l = React.useContext(UiContext), strings = _l.strings, Typography = _l.Typography, IconButton = _l.IconButton, DeleteIcon = _l.DeleteIcon, AnnotateIcon = _l.AnnotateIcon, CopyIcon = _l.CopyIcon, themeMode = _l.themeMode;
1634
- var _m = useEditorContext(), shapes = _m.shapes, removeShape = _m.removeShape, configuration = _m.configuration, metadata = _m.metadata, setMetadata = _m.setMetadata, addShape = _m.addShape, editorId = _m.editorId;
1635
- var _o = React.useState([]), selected = _o[0], setSelected = _o[1];
1636
- var _p = React.useState({
1671
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1672
+ var _j = React.useContext(UiContext), strings = _j.strings, Typography = _j.Typography, IconButton = _j.IconButton, DeleteIcon = _j.DeleteIcon, AnnotateIcon = _j.AnnotateIcon, CopyIcon = _j.CopyIcon, themeMode = _j.themeMode;
1673
+ var _k = useEditorContext(), shapes = _k.shapes, removeShape = _k.removeShape, configuration = _k.configuration, metadata = _k.metadata, setMetadata = _k.setMetadata, addShape = _k.addShape, editorId = _k.editorId;
1674
+ var _l = React.useState([]), selected = _l[0], setSelected = _l[1];
1675
+ var _m = React.useState({
1637
1676
  isOpen: false,
1638
1677
  shapeId: '',
1639
1678
  type: null,
1640
1679
  shape: null,
1641
- }), form = _p[0], setForm = _p[1];
1680
+ }), form = _m[0], setForm = _m[1];
1642
1681
  // open metadata form immediately after drawing the shape
1643
1682
  React.useEffect(function () {
1644
1683
  var openForm = function (_, _a) {
@@ -1695,7 +1734,12 @@ var ShapesList = function () {
1695
1734
  : idx % 2 === 0
1696
1735
  ? css('shapes-row-even', styles$3, themeMode)
1697
1736
  : css('shapes-row-odd', styles$3, themeMode), children: [jsxRuntime.jsx("td", { children: jsxRuntime.jsxs("div", { className: styles$3.shapesTableName, children: [jsxRuntime.jsx("div", { className: styles$3.shapesTableColor, style: { backgroundColor: shapes[id].shape.stroke } }), jsxRuntime.jsx(Typography, { children: m === null || m === void 0 ? void 0 : m.name })] }) }), jsxRuntime.jsx("td", { children: jsxRuntime.jsx(Typography, { children: (_a = configuration.rois.find(function (r) { return r.role === (m === null || m === void 0 ? void 0 : m.role); })) === null || _a === void 0 ? void 0 : _a.label }) }), jsxRuntime.jsx("td", { children: jsxRuntime.jsx(Typography, { children: strings[shapes[id].type] }) }), jsxRuntime.jsxs("td", { children: [jsxRuntime.jsx(IconButton, { onClick: handleCopyShape(id), children: jsxRuntime.jsx(CopyIcon, { color: iconColor }) }), jsxRuntime.jsx(IconButton, { onClick: handleEditShapeMetadata(id), children: jsxRuntime.jsx(AnnotateIcon, { color: iconColor }) }), jsxRuntime.jsx(IconButton, { onClick: handleRemoveShape(id), children: jsxRuntime.jsx(DeleteIcon, { color: iconColor }) })] })] }, id));
1698
- }) })] }), form.isOpen && (jsxRuntime.jsx(ParametersModalForm, { shapeType: form.type || shapes[form.shapeId].type, shapeName: (_b = (_a = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '', shapeRole: (_d = (_c = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _c === void 0 ? void 0 : _c.role) !== null && _d !== void 0 ? _d : '', shapeId: form.shapeId, parameters: (_f = (_e = configuration.rois.find(function (roi) { return roi.type === (form.type || shapes[form.shapeId].type); })) === null || _e === void 0 ? void 0 : _e.parameters) !== null && _f !== void 0 ? _f : [], data: (_k = (_h = (_g = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _g === void 0 ? void 0 : _g.parameters) !== null && _h !== void 0 ? _h : (_j = configuration.rois.find(function (roi) { return roi.type === (form.type || shapes[form.shapeId].type); })) === null || _j === void 0 ? void 0 : _j.parameters) !== null && _k !== void 0 ? _k : [], title: strings.shapeParametersMetadata, onClose: handleCloseMetadataForm, onSubmit: handleSubmitMetadata(form.shapeId) }))] }));
1737
+ }) })] }), form.isOpen && (jsxRuntime.jsx(ParametersModalForm, { shapeType: form.type || shapes[form.shapeId].type, shapeName: (_b = (_a = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '', shapeRole: (_d = (_c = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _c === void 0 ? void 0 : _c.role) !== null && _d !== void 0 ? _d : '', shapeId: form.shapeId, rolesParameters: configuration.rois
1738
+ .filter(function (roi) { return roi.type === (form.type || shapes[form.shapeId].type); })
1739
+ .reduce(function (acc, p) {
1740
+ var _a;
1741
+ return (__assign(__assign({}, acc), (_a = {}, _a[p.role] = p.parameters, _a)));
1742
+ }, {}), data: (_h = (_f = (_e = metadata.rois.find(function (roi) { return roi.id === form.shapeId; })) === null || _e === void 0 ? void 0 : _e.parameters) !== null && _f !== void 0 ? _f : (_g = configuration.rois.find(function (roi) { return roi.type === (form.type || shapes[form.shapeId].type); })) === null || _g === void 0 ? void 0 : _g.parameters) !== null && _h !== void 0 ? _h : [], title: strings.shapeParametersMetadata, onClose: handleCloseMetadataForm, onSubmit: handleSubmitMetadata(form.shapeId) }))] }));
1699
1743
  };
1700
1744
 
1701
1745
  var FullRoiIcon = function (_a) {
@@ -1741,7 +1785,7 @@ var styles$1 = {"toolbar":"Toolbar-module_toolbar__ywNcv","toolbar-light":"Toolb
1741
1785
 
1742
1786
  var Toolbar = function (_a) {
1743
1787
  var _b;
1744
- var canvasRef = _a.canvasRef, imageSize = _a.imageSize;
1788
+ var canvasRef = _a.canvasRef, canvasSize = _a.canvasSize;
1745
1789
  var _c = React.useContext(UiContext), IconButton = _c.IconButton, themeMode = _c.themeMode, primaryColor = _c.primaryColor, Typography = _c.Typography, strings = _c.strings, Tooltip = _c.Tooltip;
1746
1790
  var _d = useEditorContext(), activeTool = _d.activeTool, setActiveTool = _d.setActiveTool, configuration = _d.configuration, shapes = _d.shapes, editorId = _d.editorId, activeColor = _d.activeColor;
1747
1791
  var iconColor = function (tool) { return (tool === activeTool ? primaryColor : themeMode === 'light' ? 'black' : 'white'); };
@@ -1756,7 +1800,7 @@ var Toolbar = function (_a) {
1756
1800
  var handleRenderFullImagePolygon = function () {
1757
1801
  if (!canvasRef.current)
1758
1802
  return;
1759
- renderFullImagePolygon(editorId, canvasRef.current, activeColor, imageSize);
1803
+ renderFullImagePolygon(editorId, canvasRef.current, activeColor, canvasSize);
1760
1804
  };
1761
1805
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: css('toolbar', styles$1, themeMode), children: enableRois(configuration) && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Tooltip, { title: strings.selection, children: jsxRuntime.jsx(IconButton, { onClick: setTool("pointer" /* ToolEnum.Pointer */), children: jsxRuntime.jsx(PointerIcon, { color: iconColor("pointer" /* ToolEnum.Pointer */) }) }) }), (!hideForbiddenTools || pointEnabled) && (jsxRuntime.jsx(Tooltip, { title: strings.point, children: jsxRuntime.jsx(IconButton, { onClick: setTool("point" /* ToolEnum.Point */), disabled: !pointEnabled, children: jsxRuntime.jsx(PointIcon, { color: iconColor("point" /* ToolEnum.Point */) }) }) })), (!hideForbiddenTools || polylineEnabled) && (jsxRuntime.jsx(Tooltip, { title: strings.polyline, children: jsxRuntime.jsx(IconButton, { onClick: setTool("polyline" /* ToolEnum.Polyline */), disabled: !polylineEnabled, children: jsxRuntime.jsx(PolylineIcon, { color: iconColor("polyline" /* ToolEnum.Polyline */) }) }) })), (!hideForbiddenTools || polygonEnabled) && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Tooltip, { title: strings.polygon, children: jsxRuntime.jsx(IconButton, { onClick: setTool("polygon" /* ToolEnum.Polygon */), disabled: !polygonEnabled, children: jsxRuntime.jsx(PolygonIcon, { color: iconColor("polygon" /* ToolEnum.Polygon */) }) }) }), jsxRuntime.jsx(Tooltip, { title: strings.fullImage, children: jsxRuntime.jsx(IconButton, { onClick: handleRenderFullImagePolygon, disabled: !polygonEnabled, children: jsxRuntime.jsx(FullRoiIcon, { color: iconColor("polygon" /* ToolEnum.Polygon */) }) }) })] })), (!hideForbiddenTools || rectangleEnabled) && (jsxRuntime.jsx(Tooltip, { title: strings.rect, children: jsxRuntime.jsx(IconButton, { onClick: setTool("rect" /* ToolEnum.Rectangle */), disabled: !rectangleEnabled, children: jsxRuntime.jsx(RectangleIcon, { color: iconColor("rect" /* ToolEnum.Rectangle */) }) }) })), jsxRuntime.jsx(ColorPicker, { style: { marginLeft: 'auto', marginRight: '.5rem' } })] })) }), enableRois(configuration) && (jsxRuntime.jsx("div", { className: css('toolbar-helper', styles$1, themeMode), children: jsxRuntime.jsxs(Typography, { children: [strings[activeTool], ": ", strings["".concat(activeTool, "HelpText")]] }) }))] }));
1762
1806
  };
@@ -1834,12 +1878,12 @@ var RoiEditor = function (_a) {
1834
1878
  role: (_g = (_f = metadata.rois.find(function (r) { return r.id === shapeId; })) === null || _f === void 0 ? void 0 : _f.role) !== null && _g !== void 0 ? _g : '',
1835
1879
  type: shapes[shapeId].type,
1836
1880
  id: shapeId,
1837
- shape: fabricShapeToOutputShape(shapes[shapeId].shape, shapes[shapeId].type, imageSize),
1838
- coords: fabricShapeToOutputCoords(shapes[shapeId].shape, shapes[shapeId].shape.type, imageSize),
1881
+ shape: fabricShapeToOutputShape(shapes[shapeId].shape, shapes[shapeId].type, canvasSize),
1882
+ coords: fabricShapeToOutputCoords(shapes[shapeId].shape, shapes[shapeId].shape.type, canvasSize),
1839
1883
  });
1840
1884
  }),
1841
1885
  };
1842
- }, [imageSize.width, imageSize.height, canvasRef]);
1886
+ }, [canvasSize.width, canvasSize.height, canvasRef]);
1843
1887
  React.useEffect(function () {
1844
1888
  // do not run on first update
1845
1889
  if (firstUpdate.current < 3) {
@@ -1852,6 +1896,7 @@ var RoiEditor = function (_a) {
1852
1896
  }
1853
1897
  }, [metadata, shapes, onUpdate, prepareOutput]);
1854
1898
  var handleSubmit = React.useCallback(function () {
1899
+ Dispatcher.emit('editor:save');
1855
1900
  var _a = validate$1(configuration, presetName, shapes, metadata, strings), isValid = _a[0], errors = _a[1];
1856
1901
  if (isValid) {
1857
1902
  onSubmit(prepareOutput(metadata, shapes, presetName, presetDescription));
@@ -1865,11 +1910,13 @@ var RoiEditor = function (_a) {
1865
1910
  }, [onSubmit, configuration, shapes, metadata, prepareOutput, strings, notify, presetName, presetDescription]);
1866
1911
  log('info', enableLogs, 'react-cam-roi', 'active tool', activeTool);
1867
1912
  log('info', enableLogs, 'react-cam-roi', 'canvas size', canvasSize);
1913
+ log('info', enableLogs, 'react-cam-roi', 'image size', imageSize);
1868
1914
  log('info', enableLogs, 'react-cam-roi', 'metadata', metadata);
1915
+ log('info', enableLogs, 'react-cam-roi', 'shapes', shapes);
1869
1916
  if (!isReady) {
1870
1917
  return jsxRuntime.jsx(Loader, {});
1871
1918
  }
1872
- return (jsxRuntime.jsx(EditorProvider, { editorId: editorId, hideForbiddenTools: (_f = (_e = configuration.options) === null || _e === void 0 ? void 0 : _e.hideForbiddenTools) !== null && _f !== void 0 ? _f : false, activeTool: activeTool, setActiveTool: setActiveTool, activeColor: activeColor, setActiveColor: setActiveColor, presetName: presetName, setPresetName: setPresetName, presetDescription: presetDescription, setPresetDescription: setPresetDescription, shapes: shapes, setShapes: setShapes, addShape: addShape, addShapes: addShapes, removeShape: removeShape, configuration: configuration, metadata: metadata, setMetadata: setMetadata, onSubmit: handleSubmit, children: jsxRuntime.jsxs("div", { style: { maxWidth: '100%', width: "".concat(imageSize.width, "px") }, ref: wrapperRef, children: [jsxRuntime.jsx(TopBar, {}), configuration.rois && configuration.rois.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(slots === null || slots === void 0 ? void 0 : slots.roiAbove) && slots.roiAbove, jsxRuntime.jsxs("div", { className: css('rois-wrapper', styles$5, themeMode), children: [jsxRuntime.jsx(Header, {}), jsxRuntime.jsx(Toolbar, { canvasRef: canvasRef, imageSize: imageSize }), jsxRuntime.jsx("div", { className: css('canvas-wrapper', styles$5, themeMode), style: {
1919
+ return (jsxRuntime.jsx(EditorProvider, { editorId: editorId, hideForbiddenTools: (_f = (_e = configuration.options) === null || _e === void 0 ? void 0 : _e.hideForbiddenTools) !== null && _f !== void 0 ? _f : false, activeTool: activeTool, setActiveTool: setActiveTool, activeColor: activeColor, setActiveColor: setActiveColor, presetName: presetName, setPresetName: setPresetName, presetDescription: presetDescription, setPresetDescription: setPresetDescription, shapes: shapes, setShapes: setShapes, addShape: addShape, addShapes: addShapes, removeShape: removeShape, configuration: configuration, metadata: metadata, setMetadata: setMetadata, onSubmit: handleSubmit, children: jsxRuntime.jsxs("div", { style: { maxWidth: '100%', width: "".concat(imageSize.width, "px") }, ref: wrapperRef, children: [jsxRuntime.jsx(TopBar, {}), configuration.rois && configuration.rois.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(slots === null || slots === void 0 ? void 0 : slots.roiAbove) && slots.roiAbove, jsxRuntime.jsxs("div", { className: css('rois-wrapper', styles$5, themeMode), children: [jsxRuntime.jsx(Header, {}), jsxRuntime.jsx(Toolbar, { canvasRef: canvasRef, canvasSize: canvasSize }), jsxRuntime.jsx("div", { className: css('canvas-wrapper', styles$5, themeMode), style: {
1873
1920
  width: "".concat(canvasSize.width, "px"),
1874
1921
  height: "".concat(canvasSize.height, "px"),
1875
1922
  backgroundImage: "url(".concat(imageUrl, ")"),