@eyepop.ai/eyepop-render-2d 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -97,69 +97,77 @@ Change this rendering behaviour by passing in rendering rule(s), e.g.:
97
97
  Render2d.renderer(context,[Render2.renderFace()]).draw(result);
98
98
  // ...
99
99
  ```
100
- Each rule has a `render` object and a `target` attribute. All prebuild render classes accept a
101
- JSONPath expression as `target` parameter to select which elements should be rendered from predictions.
100
+ Each rule has a `render` object and a `target` attribute. All prebuild render classes accept a JSONPath expression as `target` parameter to select which elements should be rendered from predictions.
102
101
  See [JSONPath expression](https://www.npmjs.com/package/jsonpath)
103
102
 
104
- Most prebuild render classes provide a reasonable default `target`.
103
+ Most prebuild render classes provide a reasonable defaults, as shown below.
105
104
  #### Rendering Bounding Boxes and Class Labels
105
+
106
106
  ```typescript
107
- Render2d.renderBox({target: '$.objects.*'})
108
- // or
109
- Render2d.renderBox()
107
+ Render2d.renderBox({
108
+ showClass = true,
109
+ showConfidence = false,
110
+ showTraceId = false,
111
+ showNestedClasses = false,
112
+ target = '$..objects.*'
113
+ })
110
114
  ```
111
115
  #### Render Human Body Poses (2d or 3d)
112
116
  ```typescript
113
- Render2d.renderPose({target: '$..objects[?(@.category=="person")]'})
114
- // or
115
- Render2d.renderPose()
117
+ Render2d.renderPose({
118
+ target: '$..objects[?(@.category=="person")]'
119
+ })
116
120
  ```
117
121
  #### Render Human Hand Details
118
122
  ```typescript
119
- Render2d.renderHand({target: '$..objects[?(@.classLabel=="hand circumference")]'})
120
- // or
121
- Render2d.renderHand()
123
+ Render2d.renderHand({
124
+ target: '$..objects[?(@.classLabel=="hand circumference")]'
125
+ })
122
126
  ```
123
127
  #### Render Human Faces
124
128
  ```typescript
125
- Render2d.renderFace({target: '$..objects[?(@.classLabel=="face")]'})
126
- // or
127
- Render2d.renderFace()
129
+ Render2d.renderFace({
130
+ showLabels = false,
131
+ target = '$..objects[?(@.classLabel=="face")]'
132
+ })
128
133
  ```
129
134
  #### Render Segmentation Masks
130
135
  ```typescript
131
- Render2d.renderMask({target: '$..objects[?(@.mask)]'})
132
- // or
133
- Render2d.renderMask()
136
+ Render2d.renderMask({
137
+ target: '$..objects[?(@.mask)]'
138
+ })
134
139
  ```
135
140
  #### Render Segmentation Contours
136
141
  ```typescript
137
- Render2d.renderContour({target: '$..objects[?(@.contours)]'})
138
- // or
139
- Render2d.renderContour()
142
+ Render2d.renderContour({
143
+ target: '$..objects[?(@.contours)]'
144
+ })
140
145
  ```
141
146
  #### Blur an Object (TODO does black-put instead of blur)
142
147
  ```typescript
143
- Render2d.renderBlur({target: '$..objects[?(@.classLabel=="face")]'})
148
+ Render2d.renderBlur({
149
+ target: '$..objects[?(@.classLabel=="face")]'
150
+ })
144
151
  ```
145
152
  #### Render a Trail of a traced object over time
146
153
  ```typescript
147
- Render2d.renderTrail({target: '$..objects[?(@.traceId)]', trailLengthSeconds:1})
148
- // or
149
- Render2d.renderTrail()
154
+ Render2d.renderTrail({
155
+ target: '$..objects[?(@.traceId)]',
156
+ trailLengthSeconds:1,
157
+ })
150
158
  ```
151
- By default, this traces the mid-point of the object's bounding box. Instead, one can also draw trails of
152
- sub-objects or key points of the traced object. Use the optional parameter `traceDetails` for this purpose.
159
+ By default, this traces the mid-point of the object's bounding box. Instead, one can also draw trails of sub-objects or key points of the traced object. Use the optional parameter `traceDetails` for this purpose.
153
160
  E.g. trail the nose of every traced person:
154
161
  ```typescript
155
162
  Render2d.renderTrail({
156
- target: '$..objects[?(@.traceId)]',
157
- trailLengthSeconds:1,
163
+ target: '$..objects[?(@.traceId)]',
164
+ trailLengthSeconds:1,
158
165
  traceDetails:'$..keyPoints[?(@.category=="3d-body-points")].points[?(@.classLabel.includes("nose"))]'
159
166
  })
160
167
  ```
161
168
  #### Custom render implementation
162
- To implement custom rendering rules, create a custom class as follows:
169
+ To implement custom rendering rules,
170
+ create a custom class as follows:
163
171
  ```typescript
164
172
  import { PredictedObject, StreamTime } from '@eyepop.ai/eyepop'
165
173
 
@@ -15,6 +15,8 @@ declare class Style {
15
15
  font: string;
16
16
  colors: Colors;
17
17
  scale: number;
18
+ cornerWidth: number;
19
+ cornerPadding: number;
18
20
  private static defaultColors;
19
21
  constructor(context: CanvasRenderingContext2D);
20
22
  private calculateFont;
@@ -29,20 +31,57 @@ interface Render extends RenderTarget {
29
31
  draw(element: any, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime): void;
30
32
  }
31
33
 
34
+ type RenderBlurOptions = {} & RenderTarget;
35
+
36
+ type RenderBoxOptions = {
37
+ showText: boolean;
38
+ showClass: boolean;
39
+ showNestedClasses: boolean;
40
+ showConfidence: boolean;
41
+ showTraceId: boolean;
42
+ } & RenderTarget;
43
+
44
+ type RenderFaceOptions = {
45
+ showLabels: boolean;
46
+ } & RenderTarget;
47
+
48
+ type RenderHandOptions = {} & RenderTarget;
49
+
50
+ type RenderPoseOptions = {} & RenderTarget;
51
+
52
+ type RenderTrailOptions = {
53
+ trailLengthSeconds: number;
54
+ traceDetails?: string | undefined;
55
+ } & RenderTarget;
56
+
57
+ type RenderMaskOptions = {} & RenderTarget;
58
+
59
+ type RenderContourOptions = {} & RenderTarget;
60
+
61
+ type RenderKeyPointsOptions = {
62
+ showLabels: boolean;
63
+ } & RenderTarget;
64
+
65
+ type RenderTextOptions = {
66
+ showText: boolean;
67
+ fitToBounds: boolean;
68
+ } & RenderTarget;
69
+
32
70
  interface Renderer extends RenderTarget {
33
71
  draw(p: Prediction): void;
34
72
  }
35
73
  declare namespace Render2d {
36
74
  function renderer(context: CanvasRenderingContext2D, rules?: Render[] | undefined): Renderer;
37
- function renderBlur(target: string): Render;
38
- function renderBox(showClass?: boolean, showText?: boolean, showConfidence?: boolean, showTraceId?: boolean, showNestedClasses?: boolean, target?: string): Render;
39
- function renderMask(target?: string): Render;
40
- function renderContour(target?: string): Render;
41
- function renderFace(target?: string): Render;
42
- function renderKeypoints(target?: string): Render;
43
- function renderHand(target?: string): Render;
44
- function renderPose(target?: string): Render;
45
- function renderTrail(trailLengthSeconds?: number, traceDetails?: string | undefined, target?: string): Render;
75
+ function renderBlur(options?: Partial<RenderBlurOptions>): Render;
76
+ function renderBox(options?: Partial<RenderBoxOptions>): Render;
77
+ function renderMask(options?: Partial<RenderMaskOptions>): Render;
78
+ function renderContour(options?: Partial<RenderContourOptions>): Render;
79
+ function renderFace(options?: Partial<RenderFaceOptions>): Render;
80
+ function renderKeypoints(options?: Partial<RenderKeyPointsOptions>): Render;
81
+ function renderHand(options?: Partial<RenderHandOptions>): Render;
82
+ function renderPose(options?: Partial<RenderPoseOptions>): Render;
83
+ function renderText(options?: Partial<RenderTextOptions>): Render;
84
+ function renderTrail(options?: Partial<RenderTrailOptions>): Render;
46
85
  }
47
86
 
48
87
  export { Render2d, type Renderer, Render2d as default };
@@ -15,6 +15,8 @@ declare class Style {
15
15
  font: string;
16
16
  colors: Colors;
17
17
  scale: number;
18
+ cornerWidth: number;
19
+ cornerPadding: number;
18
20
  private static defaultColors;
19
21
  constructor(context: CanvasRenderingContext2D);
20
22
  private calculateFont;
@@ -29,20 +31,57 @@ interface Render extends RenderTarget {
29
31
  draw(element: any, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime): void;
30
32
  }
31
33
 
34
+ type RenderBlurOptions = {} & RenderTarget;
35
+
36
+ type RenderBoxOptions = {
37
+ showText: boolean;
38
+ showClass: boolean;
39
+ showNestedClasses: boolean;
40
+ showConfidence: boolean;
41
+ showTraceId: boolean;
42
+ } & RenderTarget;
43
+
44
+ type RenderFaceOptions = {
45
+ showLabels: boolean;
46
+ } & RenderTarget;
47
+
48
+ type RenderHandOptions = {} & RenderTarget;
49
+
50
+ type RenderPoseOptions = {} & RenderTarget;
51
+
52
+ type RenderTrailOptions = {
53
+ trailLengthSeconds: number;
54
+ traceDetails?: string | undefined;
55
+ } & RenderTarget;
56
+
57
+ type RenderMaskOptions = {} & RenderTarget;
58
+
59
+ type RenderContourOptions = {} & RenderTarget;
60
+
61
+ type RenderKeyPointsOptions = {
62
+ showLabels: boolean;
63
+ } & RenderTarget;
64
+
65
+ type RenderTextOptions = {
66
+ showText: boolean;
67
+ fitToBounds: boolean;
68
+ } & RenderTarget;
69
+
32
70
  interface Renderer extends RenderTarget {
33
71
  draw(p: Prediction): void;
34
72
  }
35
73
  declare namespace Render2d {
36
74
  function renderer(context: CanvasRenderingContext2D, rules?: Render[] | undefined): Renderer;
37
- function renderBlur(target: string): Render;
38
- function renderBox(showClass?: boolean, showText?: boolean, showConfidence?: boolean, showTraceId?: boolean, showNestedClasses?: boolean, target?: string): Render;
39
- function renderMask(target?: string): Render;
40
- function renderContour(target?: string): Render;
41
- function renderFace(target?: string): Render;
42
- function renderKeypoints(target?: string): Render;
43
- function renderHand(target?: string): Render;
44
- function renderPose(target?: string): Render;
45
- function renderTrail(trailLengthSeconds?: number, traceDetails?: string | undefined, target?: string): Render;
75
+ function renderBlur(options?: Partial<RenderBlurOptions>): Render;
76
+ function renderBox(options?: Partial<RenderBoxOptions>): Render;
77
+ function renderMask(options?: Partial<RenderMaskOptions>): Render;
78
+ function renderContour(options?: Partial<RenderContourOptions>): Render;
79
+ function renderFace(options?: Partial<RenderFaceOptions>): Render;
80
+ function renderKeypoints(options?: Partial<RenderKeyPointsOptions>): Render;
81
+ function renderHand(options?: Partial<RenderHandOptions>): Render;
82
+ function renderPose(options?: Partial<RenderPoseOptions>): Render;
83
+ function renderText(options?: Partial<RenderTextOptions>): Render;
84
+ function renderTrail(options?: Partial<RenderTrailOptions>): Render;
46
85
  }
47
86
 
48
87
  export { Render2d, type Renderer, Render2d as default };
@@ -40,6 +40,8 @@ var import_resize_observer = require("@juggle/resize-observer");
40
40
  var _Style = class _Style {
41
41
  constructor(context) {
42
42
  this.scale = 1;
43
+ this.cornerWidth = 0.2;
44
+ this.cornerPadding = 0.05;
43
45
  this.colors = _Style.defaultColors;
44
46
  if ("document" in globalThis && "implementation" in globalThis.document) {
45
47
  const resizeObserver = new import_resize_observer.ResizeObserver((entries) => {
@@ -82,11 +84,10 @@ var DEFAULT_TARGET = "$..objects[?(@.category=='person')]";
82
84
  var RenderBox = class _RenderBox {
83
85
  constructor(options = {}) {
84
86
  this.target = DEFAULT_TARGET;
85
- const { showClass = true, showText = true, showConfidence = false, showTraceId = false, showNestedClasses = false, target = DEFAULT_TARGET } = options;
87
+ const { showClass = true, showConfidence = false, showTraceId = false, showNestedClasses = false, target = "$..objects.*" } = options;
86
88
  this.target = target;
87
89
  this.showClass = showClass;
88
90
  this.showNestedClasses = showNestedClasses;
89
- this.showText = showText;
90
91
  this.showConfidence = showConfidence;
91
92
  this.showTraceId = showTraceId;
92
93
  }
@@ -104,15 +105,21 @@ var RenderBox = class _RenderBox {
104
105
  const y = yOffset + element.y * yScale;
105
106
  const w = element.width * xScale;
106
107
  const h = element.height * yScale;
108
+ if (element.objects) {
109
+ element.objects.sort((a, b) => {
110
+ if (!a.category || !b.category) return 0;
111
+ return a.category.localeCompare(b.category);
112
+ });
113
+ }
114
+ const scale = style.scale;
107
115
  context.beginPath();
108
116
  context.rect(x, y, w, h);
109
- context.lineWidth = style.scale;
117
+ context.lineWidth = scale * 2;
110
118
  context.strokeStyle = style.colors.opacity_color;
111
119
  context.fillStyle = style.colors.opacity_color;
112
120
  context.fill();
113
121
  context.stroke();
114
- const scale = style.scale;
115
- const desiredPercentage = 0.25;
122
+ const desiredPercentage = style.cornerPadding;
116
123
  let canvasDimension = Math.min(context.canvas.width, context.canvas.height);
117
124
  let cornerSize = Math.min(w / 4, canvasDimension * desiredPercentage);
118
125
  var corners = [
@@ -131,10 +138,10 @@ var RenderBox = class _RenderBox {
131
138
  context.lineTo(corner[1].x, corner[1].y);
132
139
  context.lineTo(corner[2].x, corner[2].y);
133
140
  context.strokeStyle = style.colors.primary_color;
134
- context.lineWidth = style.scale;
141
+ context.lineWidth = scale * 2;
135
142
  context.stroke();
136
143
  });
137
- const padding = Math.max(Math.min(w / 25, canvasDimension * (desiredPercentage / 4)), scale * 2);
144
+ const padding = Math.max(Math.min(w / 25, canvasDimension * style.cornerWidth), scale * 2);
138
145
  cornerSize = cornerSize - padding;
139
146
  var corners2 = [
140
147
  //2nd top left corner
@@ -164,7 +171,7 @@ var RenderBox = class _RenderBox {
164
171
  context.lineTo(corner[1].x, corner[1].y);
165
172
  context.lineTo(corner[2].x, corner[2].y);
166
173
  context.strokeStyle = style.colors.secondary_color;
167
- context.lineWidth = style.scale;
174
+ context.lineWidth = scale * 2;
168
175
  context.stroke();
169
176
  });
170
177
  const boundingBoxWidth = element.width * xScale - 3 * padding;
@@ -175,14 +182,6 @@ var RenderBox = class _RenderBox {
175
182
  label = _RenderBox.toTitleCase(label);
176
183
  yOffset += this.drawLabel(label, context, element, yScale, xScale, yOffset, xOffset, style, boundingBoxWidth, padding, false, fontSize);
177
184
  }
178
- if (this.showText && element.labels) {
179
- fontSize = this.getMinFontSize(context, element, boundingBoxWidth, style, true);
180
- for (let i = 0; i < element.labels.length; i++) {
181
- label = element.labels[i]?.label;
182
- if (!label) continue;
183
- yOffset += this.drawLabel(label, context, element, yScale, xScale, yOffset, xOffset, style, boundingBoxWidth, padding, true, fontSize);
184
- }
185
- }
186
185
  if (this.showNestedClasses && element?.classes) {
187
186
  for (let i = 0; i < element.classes.length; i++) {
188
187
  label = element.classes[i]?.classLabel;
@@ -192,7 +191,7 @@ var RenderBox = class _RenderBox {
192
191
  }
193
192
  }
194
193
  if (this.showTraceId && element.traceId) {
195
- label = "Id" + element.traceId;
194
+ label = "ID: " + element.traceId;
196
195
  label = _RenderBox.toTitleCase(label);
197
196
  yOffset += this.drawLabel(label, context, element, yScale, xScale, yOffset, xOffset, style, boundingBoxWidth, padding, false, fontSize);
198
197
  }
@@ -239,16 +238,6 @@ var RenderBox = class _RenderBox {
239
238
  // Gets the largest label from all the labels to be displayed
240
239
  getMinFontSize(context, element, width, style, scaleToWidth = false) {
241
240
  let largestLabel = "";
242
- if (this.showText && element.labels) {
243
- for (let i = 0; i < element.labels.length; i++) {
244
- const label = element.labels[i].label;
245
- if (!label) continue;
246
- const formattedLabel = `${_RenderBox.toTitleCase(label)}`;
247
- if (formattedLabel.length > largestLabel.length) {
248
- largestLabel = formattedLabel;
249
- }
250
- }
251
- }
252
241
  if (this.showClass && element.classLabel) {
253
242
  const label = element.classLabel;
254
243
  const formattedLabel = `${_RenderBox.toTitleCase(label)}`;
@@ -374,8 +363,10 @@ var RenderBlur = class {
374
363
  var RenderFace = class {
375
364
  constructor(options = {}) {
376
365
  this.target = DEFAULT_TARGET;
377
- const { target = DEFAULT_TARGET } = options;
366
+ this.showLabels = false;
367
+ const { showLabels = false, target = '$..objects[?(@.classLabel=="face")]' } = options;
378
368
  this.target = target;
369
+ this.showLabels = showLabels;
379
370
  }
380
371
  start(context, style) {
381
372
  this.context = context;
@@ -427,12 +418,14 @@ var RenderFace = class {
427
418
  context.fillRect(x, y, tw.width + padding * 2, 24);
428
419
  }
429
420
  context.fill();
430
- context.fillStyle = style.colors.secondary_color;
431
- context.fillText(
432
- label,
433
- Math.max(0, x) + padding,
434
- Math.max(0, y)
435
- );
421
+ if (this.showLabels) {
422
+ context.fillStyle = style.colors.secondary_color;
423
+ context.fillText(
424
+ label,
425
+ Math.max(0, x) + padding,
426
+ Math.max(0, y)
427
+ );
428
+ }
436
429
  context.closePath();
437
430
  }
438
431
  }
@@ -501,7 +494,7 @@ var FACE_LANDMARKS_TESSELATION = [[127, 34], [34, 139], [139, 127], [11, 0], [0,
501
494
  var RenderHand = class {
502
495
  constructor(options = {}) {
503
496
  this.target = DEFAULT_TARGET;
504
- const { target = DEFAULT_TARGET } = options;
497
+ const { target = '$..objects[?(@.classLabel=="hand circumference")]' } = options;
505
498
  this.target = target;
506
499
  }
507
500
  start(context, style) {
@@ -628,7 +621,7 @@ var HAND_CONNECTIONS = [
628
621
  var RenderPose = class {
629
622
  constructor(options = {}) {
630
623
  this.target = DEFAULT_TARGET;
631
- const { target = DEFAULT_TARGET } = options;
624
+ const { target = '$..objects[?(@.category=="person")]' } = options;
632
625
  this.target = target;
633
626
  }
634
627
  start(context, style) {
@@ -679,7 +672,7 @@ var RenderPose = class {
679
672
  const x2 = xOffset + point2.x * xScale;
680
673
  const y2 = yOffset + point2.y * yScale;
681
674
  context.beginPath();
682
- context.lineWidth = style.scale;
675
+ context.lineWidth = style.scale * 3;
683
676
  context.strokeStyle = style.colors.primary_color;
684
677
  context.fillStyle = style.colors.primary_color;
685
678
  context.moveTo(x1, y1);
@@ -770,7 +763,7 @@ var TRIM_INTERVAL = 1e3 * 1e3 * 1e3 * 10;
770
763
  var RenderTrail = class {
771
764
  constructor(options = {}) {
772
765
  this.target = DEFAULT_TARGET;
773
- const { target = DEFAULT_TARGET, trailLengthSeconds = 1, traceDetails } = options;
766
+ const { target = "$..objects[?(@.traceId)]", trailLengthSeconds = 1, traceDetails } = options;
774
767
  this.target = target;
775
768
  this.trailLengthNanos = trailLengthSeconds * 1e3 * 1e3 * 1e3;
776
769
  this.traceDetails = traceDetails;
@@ -863,7 +856,7 @@ var RenderTrail = class {
863
856
  var RenderMask = class {
864
857
  constructor(options = {}) {
865
858
  this.target = DEFAULT_TARGET;
866
- const { target = DEFAULT_TARGET } = options;
859
+ const { target = "$..objects[?(@.mask)]" } = options;
867
860
  this.target = target;
868
861
  }
869
862
  start(context, style) {
@@ -923,7 +916,7 @@ var RenderMask = class {
923
916
  var RenderContour = class {
924
917
  constructor(options = {}) {
925
918
  this.target = DEFAULT_TARGET;
926
- const { target = DEFAULT_TARGET } = options;
919
+ const { target = "$..objects[?(@.contours)]" } = options;
927
920
  this.target = target;
928
921
  }
929
922
  start(context, style) {
@@ -982,8 +975,10 @@ var RenderContour = class {
982
975
  var RenderKeyPoints = class {
983
976
  constructor(options = {}) {
984
977
  this.target = DEFAULT_TARGET;
985
- const { target = DEFAULT_TARGET } = options;
978
+ this.showLabels = false;
979
+ const { showLabels = false, target = "$..objects[?(@.keyPoints)]" } = options;
986
980
  this.target = target;
981
+ this.showLabels = showLabels;
987
982
  }
988
983
  start(context, style) {
989
984
  this.context = context;
@@ -1035,6 +1030,7 @@ var RenderKeyPoints = class {
1035
1030
  context.fill();
1036
1031
  context.strokeStyle = style.colors.secondary_color;
1037
1032
  context.stroke();
1033
+ if (!this.showLabels) continue;
1038
1034
  let label;
1039
1035
  if (typeof p.visible == "undefined") {
1040
1036
  label = p.classLabel;
@@ -1053,6 +1049,102 @@ var RenderKeyPoints = class {
1053
1049
  }
1054
1050
  };
1055
1051
 
1052
+ // render-text.ts
1053
+ var RenderText = class {
1054
+ constructor(options = {}) {
1055
+ this.target = DEFAULT_TARGET;
1056
+ this.fitToBounds = true;
1057
+ const { target = '$..objects[?(@.classLabel=="text")]', fitToBounds = true } = options;
1058
+ this.target = target;
1059
+ this.fitToBounds = fitToBounds;
1060
+ }
1061
+ start(context, style) {
1062
+ this.context = context;
1063
+ this.style = style;
1064
+ }
1065
+ draw(element, xOffset, yOffset, xScale, yScale, streamTime) {
1066
+ const context = this.context;
1067
+ const style = this.style;
1068
+ if (!context || !style) {
1069
+ throw new Error("render() called before start()");
1070
+ }
1071
+ const scale = style.scale;
1072
+ const w = element.width * xScale;
1073
+ let canvasDimension = Math.min(context.canvas.width, context.canvas.height);
1074
+ const padding = Math.max(Math.min(w / 25, canvasDimension * style.cornerWidth), scale * 2);
1075
+ const boundingBoxWidth = element.width * xScale - 3 * padding;
1076
+ if (!element.labels) return;
1077
+ let fontSize = this.getMinFontSize(context, element, boundingBoxWidth, style, true);
1078
+ let label = "";
1079
+ for (let i = 0; i < element.labels.length; i++) {
1080
+ label = element.labels[i]?.label;
1081
+ if (!label) continue;
1082
+ yOffset += this.drawLabel(label, context, element, yScale, xScale, yOffset, xOffset, style, boundingBoxWidth, padding, this.fitToBounds, fontSize);
1083
+ }
1084
+ }
1085
+ // Draw a label on the canvas, scaling the font size to fit the bounding box
1086
+ drawLabel(label, context, element, yScale, xScale, yOffset, xOffset, style, boundingBoxWidth, padding, scaleToBounds = false, fontSize) {
1087
+ context.fillStyle = "#ffffff";
1088
+ context.textAlign = "left";
1089
+ context.textBaseline = "top";
1090
+ context.font = style.font;
1091
+ let textDetails = context.measureText(label);
1092
+ let scaleFactor = boundingBoxWidth / textDetails.width;
1093
+ let fontType = style.font.split(" ")[1];
1094
+ if (fontSize) {
1095
+ context.font = `${fontSize}px ` + fontType;
1096
+ } else {
1097
+ let fontSize2 = parseInt(style.font.split(" ")[0]);
1098
+ if (scaleToBounds) {
1099
+ fontSize2 *= scaleFactor;
1100
+ } else {
1101
+ fontSize2 = Math.min(fontSize2, fontSize2 * scaleFactor);
1102
+ }
1103
+ context.font = `${fontSize2}px ${fontType}`;
1104
+ }
1105
+ textDetails = context.measureText(label);
1106
+ let xPos = element.x * xScale + xOffset + 1.5 * padding;
1107
+ let yPos = element.y * yScale + yOffset + 1.5 * padding;
1108
+ context.fillText(label, xPos, yPos);
1109
+ const boxSize = padding + textDetails.actualBoundingBoxAscent + textDetails.actualBoundingBoxDescent;
1110
+ yPos += boxSize;
1111
+ return padding + textDetails.actualBoundingBoxDescent;
1112
+ }
1113
+ static toTitleCase(str) {
1114
+ if (!str) return "";
1115
+ return str.replace(/\w\S*/g, function(txt) {
1116
+ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
1117
+ });
1118
+ }
1119
+ // Gets the largest label from all the labels to be displayed
1120
+ getMinFontSize(context, element, width, style, scaleToWidth = false) {
1121
+ let largestLabel = "";
1122
+ for (let i = 0; i < element.labels.length; i++) {
1123
+ const label = element.labels[i].label;
1124
+ if (!label) continue;
1125
+ if (label.length > largestLabel.length) {
1126
+ largestLabel = label;
1127
+ }
1128
+ }
1129
+ let fontSize = this.getFontSize(largestLabel, context, style, width, scaleToWidth);
1130
+ return fontSize;
1131
+ }
1132
+ getFontSize(label, context, style, boundingBoxWidth, scaleToWidth = false) {
1133
+ context.textAlign = "left";
1134
+ context.textBaseline = "top";
1135
+ context.font = style.font;
1136
+ let textDetails = context.measureText(label);
1137
+ let scaleFactor = boundingBoxWidth / textDetails.width;
1138
+ let fontSize = parseInt(style.font.split(" ")[0]);
1139
+ if (scaleToWidth) {
1140
+ fontSize *= scaleFactor;
1141
+ } else {
1142
+ fontSize = Math.min(fontSize, fontSize * scaleFactor);
1143
+ }
1144
+ return fontSize;
1145
+ }
1146
+ };
1147
+
1056
1148
  // index.ts
1057
1149
  var Render2d;
1058
1150
  ((Render2d2) => {
@@ -1060,40 +1152,44 @@ var Render2d;
1060
1152
  return new Renderer2d({ context, rules });
1061
1153
  }
1062
1154
  Render2d2.renderer = renderer;
1063
- function renderBlur(target) {
1064
- return new RenderBlur({ target });
1155
+ function renderBlur(options = {}) {
1156
+ return new RenderBlur(options);
1065
1157
  }
1066
1158
  Render2d2.renderBlur = renderBlur;
1067
- function renderBox(showClass = true, showText = false, showConfidence = false, showTraceId = false, showNestedClasses = false, target = "$..objects.*") {
1068
- return new RenderBox({ target, showClass, showText, showConfidence, showTraceId, showNestedClasses });
1159
+ function renderBox(options = {}) {
1160
+ return new RenderBox(options);
1069
1161
  }
1070
1162
  Render2d2.renderBox = renderBox;
1071
- function renderMask(target = "$..objects[?(@.mask)]") {
1072
- return new RenderMask({ target });
1163
+ function renderMask(options = {}) {
1164
+ return new RenderMask(options);
1073
1165
  }
1074
1166
  Render2d2.renderMask = renderMask;
1075
- function renderContour(target = "$..objects[?(@.contours)]") {
1076
- return new RenderContour({ target });
1167
+ function renderContour(options = {}) {
1168
+ return new RenderContour(options);
1077
1169
  }
1078
1170
  Render2d2.renderContour = renderContour;
1079
- function renderFace(target = '$..objects[?(@.classLabel=="face")]') {
1080
- return new RenderFace({ target });
1171
+ function renderFace(options = {}) {
1172
+ return new RenderFace(options);
1081
1173
  }
1082
1174
  Render2d2.renderFace = renderFace;
1083
- function renderKeypoints(target = "$..objects[?(@.keyPoints)]") {
1084
- return new RenderKeyPoints({ target });
1175
+ function renderKeypoints(options = {}) {
1176
+ return new RenderKeyPoints(options);
1085
1177
  }
1086
1178
  Render2d2.renderKeypoints = renderKeypoints;
1087
- function renderHand(target = '$..objects[?(@.classLabel=="hand circumference")]') {
1088
- return new RenderHand({ target });
1179
+ function renderHand(options = {}) {
1180
+ return new RenderHand(options);
1089
1181
  }
1090
1182
  Render2d2.renderHand = renderHand;
1091
- function renderPose(target = '$..objects[?(@.category=="person")]') {
1092
- return new RenderPose({ target });
1183
+ function renderPose(options = {}) {
1184
+ return new RenderPose(options);
1093
1185
  }
1094
1186
  Render2d2.renderPose = renderPose;
1095
- function renderTrail(trailLengthSeconds = 1, traceDetails = void 0, target = "$..objects[?(@.traceId)]") {
1096
- return new RenderTrail({ target, traceDetails, trailLengthSeconds });
1187
+ function renderText(options = {}) {
1188
+ return new RenderText(options);
1189
+ }
1190
+ Render2d2.renderText = renderText;
1191
+ function renderTrail(options = {}) {
1192
+ return new RenderTrail(options);
1097
1193
  }
1098
1194
  Render2d2.renderTrail = renderTrail;
1099
1195
  })(Render2d || (Render2d = {}));