@eyepop.ai/eyepop-render-2d 3.15.0 → 3.15.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.
@@ -538,7 +538,7 @@ var RenderFace = class {
538
538
  let expressions = [];
539
539
  if (face.classes) {
540
540
  for (let i = 0; i < face.classes.length; i++) {
541
- if (face.classes[i].confidence > 0.95) {
541
+ if ((face.classes[i].confidence ?? 0) > 0.95) {
542
542
  const label = EXPRESSION_LABELS.get(face.classes[i].classLabel);
543
543
  if (label) {
544
544
  expressions.push(label);
@@ -3369,7 +3369,7 @@ var RenderHand = class {
3369
3369
  let minZ = -1;
3370
3370
  for (let i2 = 0; i2 < keyPoints.points.length; i2++) {
3371
3371
  const keyPoint = keyPoints.points[i2];
3372
- labelsToPoints.set(keyPoint.classLabel, keyPoint);
3372
+ labelsToPoints.set(keyPoint.classLabel ?? "<undefined>", keyPoint);
3373
3373
  if (keyPoint.z) {
3374
3374
  if (keyPoint.z > maxZ) {
3375
3375
  maxZ = keyPoint.z;
@@ -3497,7 +3497,7 @@ var RenderPose = class {
3497
3497
  let minZ = -1;
3498
3498
  for (let i2 = 0; i2 < keyPoints.points.length; i2++) {
3499
3499
  const keyPoint = keyPoints.points[i2];
3500
- labelsToPoints.set(keyPoint.classLabel, keyPoint);
3500
+ labelsToPoints.set(keyPoint.classLabel ?? "<undefined>", keyPoint);
3501
3501
  if (keyPoint.z) {
3502
3502
  if (keyPoint.z > maxZ) {
3503
3503
  maxZ = keyPoint.z;
@@ -3541,9 +3541,9 @@ var RenderPose = class {
3541
3541
  const radius = MAX_RADIUS - (z - minZ) * (MAX_RADIUS - MIN_RADIUS) / (maxZ - minZ);
3542
3542
  context.beginPath();
3543
3543
  context.arc(x, y, radius, 0, Math.PI * 2, false);
3544
- if (p.classLabel.includes("left")) {
3544
+ if (p.classLabel?.includes("left")) {
3545
3545
  context.fillStyle = style.colors.left_color;
3546
- } else if (p.classLabel.includes("right")) {
3546
+ } else if (p.classLabel?.includes("right")) {
3547
3547
  context.fillStyle = style.colors.right_color;
3548
3548
  } else {
3549
3549
  context.fillStyle = style.colors.primary_color;
@@ -3884,9 +3884,9 @@ var RenderKeyPoints = class {
3884
3884
  if (!this.showLabels) continue;
3885
3885
  let label;
3886
3886
  if (typeof p.visible == "undefined") {
3887
- label = p.classLabel;
3887
+ label = p.classLabel ?? "<undefined>";
3888
3888
  } else {
3889
- label = `${p.classLabel} (${p.visible ? "visible" : "invisible"})`;
3889
+ label = `${p.classLabel ?? "<undefined>"} (${p.visible ? "visible" : "invisible"})`;
3890
3890
  }
3891
3891
  context.font = style.font;
3892
3892
  context.fillStyle = "#ffffff";
@@ -3906,10 +3906,12 @@ var RenderText = class {
3906
3906
  this.target = DEFAULT_TARGET;
3907
3907
  this.fitToBounds = true;
3908
3908
  this.textPadding = 0.1;
3909
- const { target = "$..objects[?(@.texts)]", fitToBounds = true, textPadding = 0.1 } = options;
3909
+ this.maxLines = 12;
3910
+ const { target = "$..objects[?(@.texts)]", fitToBounds = true, textPadding = 0.1, maxLines = 12 } = options;
3910
3911
  this.target = target;
3911
3912
  this.fitToBounds = fitToBounds;
3912
3913
  this.textPadding = Math.max(0.02, Math.min(0.2, textPadding));
3914
+ this.maxLines = maxLines;
3913
3915
  }
3914
3916
  start(context, style) {
3915
3917
  this.context = context;
@@ -3931,37 +3933,74 @@ var RenderText = class {
3931
3933
  padding = Math.min(padding, w * this.textPadding, h * this.textPadding);
3932
3934
  const boundingBoxWidth = w - padding * 2;
3933
3935
  const boundingBoxHeight = h - padding * 2;
3934
- let fontSize = this.getMinFontSize(context, element, boundingBoxWidth, boundingBoxHeight, style, this.fitToBounds);
3935
- let label = "";
3936
+ const baseFontSize = parseInt(style.font.split(" ")[0]);
3936
3937
  const fontType = style.font.split(" ")[1];
3938
+ const rawLines = [];
3939
+ for (const entry of element.texts) {
3940
+ const text = entry?.text || "";
3941
+ if (!text) continue;
3942
+ rawLines.push(...text.split("\n"));
3943
+ }
3944
+ if (rawLines.length === 0) return;
3945
+ const isShortSingleLine = rawLines.length === 1 && rawLines[0].length <= 60;
3946
+ let fontSize;
3947
+ if (this.fitToBounds && isShortSingleLine) {
3948
+ fontSize = this.getMinFontSize(context, element, boundingBoxWidth, boundingBoxHeight, style, true);
3949
+ } else {
3950
+ fontSize = baseFontSize;
3951
+ if (this.fitToBounds) {
3952
+ const maxFontFromHeight = Math.floor(boundingBoxHeight * 0.12);
3953
+ fontSize = Math.min(fontSize, Math.max(maxFontFromHeight, 10));
3954
+ }
3955
+ }
3937
3956
  context.font = `${fontSize}px ${fontType}`;
3938
- let totalTextHeight = 0;
3939
- const textMetrics = [];
3940
- for (let i = 0; i < element.texts.length; i++) {
3941
- label = element.texts[i]?.text || "";
3942
- if (!label) continue;
3943
- const metrics = context.measureText(label);
3944
- const lineHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
3945
- totalTextHeight += lineHeight;
3946
- textMetrics.push({
3947
- text: label,
3948
- width: metrics.width,
3949
- height: lineHeight
3950
- });
3957
+ const wrappedLines = [];
3958
+ for (const line of rawLines) {
3959
+ const wrapped = this.wrapLine(context, line, boundingBoxWidth);
3960
+ wrappedLines.push(...wrapped);
3961
+ }
3962
+ let displayLines = wrappedLines;
3963
+ const truncated = this.maxLines > 0 && wrappedLines.length > this.maxLines;
3964
+ if (truncated) {
3965
+ displayLines = wrappedLines.slice(0, this.maxLines);
3966
+ const last = displayLines[displayLines.length - 1];
3967
+ displayLines[displayLines.length - 1] = last.replace(/\s+\S*$/, "") + "\u2026";
3951
3968
  }
3952
3969
  const spacing = fontSize * 0.2;
3953
- if (element.texts.length > 1) {
3954
- totalTextHeight += spacing * (element.texts.length - 1);
3970
+ const totalTextHeight = displayLines.length * fontSize + (displayLines.length - 1) * spacing;
3971
+ if (totalTextHeight > boundingBoxHeight && displayLines.length > 0) {
3972
+ const scaleFactor = boundingBoxHeight / totalTextHeight;
3973
+ fontSize = Math.max(8, Math.floor(fontSize * scaleFactor));
3974
+ context.font = `${fontSize}px ${fontType}`;
3955
3975
  }
3956
- let textY = element.y * yScale + yOffset + (h - totalTextHeight) / 2;
3957
- for (let i = 0; i < textMetrics.length; i++) {
3958
- const metrics = textMetrics[i];
3959
- let textX = element.x * xScale + xOffset + (w - metrics.width) / 2;
3960
- this.drawText(metrics.text, context, textX, textY, style, fontSize);
3961
- textY += metrics.height + spacing;
3976
+ const finalSpacing = fontSize * 0.2;
3977
+ const finalLineHeight = fontSize + finalSpacing;
3978
+ const finalTotalHeight = displayLines.length * finalLineHeight - finalSpacing;
3979
+ let textY = element.y * yScale + yOffset + (h - finalTotalHeight) / 2;
3980
+ const textX = element.x * xScale + xOffset + padding;
3981
+ for (const line of displayLines) {
3982
+ this.drawText(line, context, textX, textY, style, fontSize);
3983
+ textY += finalLineHeight;
3962
3984
  }
3963
3985
  }
3964
- // Draw a label on the canvas
3986
+ wrapLine(context, text, maxWidth) {
3987
+ if (!text) return [""];
3988
+ if (context.measureText(text).width <= maxWidth) return [text];
3989
+ const words = text.split(" ");
3990
+ const lines = [];
3991
+ let current = "";
3992
+ for (const word of words) {
3993
+ const candidate = current ? `${current} ${word}` : word;
3994
+ if (context.measureText(candidate).width > maxWidth && current) {
3995
+ lines.push(current);
3996
+ current = word;
3997
+ } else {
3998
+ current = candidate;
3999
+ }
4000
+ }
4001
+ if (current) lines.push(current);
4002
+ return lines.length > 0 ? lines : [text];
4003
+ }
3965
4004
  drawText(text, context, xPos, yPos, style, fontSize) {
3966
4005
  context.fillStyle = "#ffffff";
3967
4006
  context.textAlign = "left";
@@ -3973,10 +4012,9 @@ var RenderText = class {
3973
4012
  static toTitleCase(str) {
3974
4013
  if (!str) return "";
3975
4014
  return str.replace(/\w\S*/g, function(txt) {
3976
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
4015
+ return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
3977
4016
  });
3978
4017
  }
3979
- // Gets the optimal font size for all labels to fit in the bounding box
3980
4018
  getMinFontSize(context, element, width, height, style, scaleToFit = false) {
3981
4019
  const textLines = (element.texts || []).map((t) => t?.text || "").filter((t) => t);
3982
4020
  const textCount = textLines.length;