figspec

Unofficial static Figma frame/file viewer available as HTML CustomElement

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
import type * as figma from "../figma.js";

/**
 * Measure bounding box for nodes.
 */
export class BoundingBoxMeasurement {
  #minX = Infinity;
  #maxX = -Infinity;
  #minY = Infinity;
  #maxY = -Infinity;

  /**
   * Add a node to the measurement.
   */
  addNode(node: figma.Node & figma.HasBoundingBox): void {
    if (node.visible === false) {
      return;
    }

    const box = node.absoluteRenderBounds || node.absoluteBoundingBox;

    this.#minX = Math.min(this.#minX, box.x);
    this.#maxX = Math.max(this.#maxX, box.x + box.width);
    this.#minY = Math.min(this.#minY, box.y);
    this.#maxY = Math.max(this.#maxY, box.y + box.height);
  }

  /**
   * Returns a bounding box for added nodes.
   */
  measure(): figma.Rectangle {
    return {
      x: Number.isFinite(this.#minX) ? this.#minX : NaN,
      y: Number.isFinite(this.#minY) ? this.#minY : NaN,
      width:
        Number.isFinite(this.#maxX) && Number.isFinite(this.#minX)
          ? this.#maxX - this.#minX
          : NaN,
      height:
        Number.isFinite(this.#maxY) && Number.isFinite(this.#minY)
          ? this.#maxY - this.#minY
          : NaN,
    };
  }
}