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