Repository: motion-canvas/motion-canvas
File: packages/2d/src/components/Polygon.ts (TypeScript)

Code before:
  // SpacingSignal,
} from '@motion-canvas/core/lib/types';
import {Shape, ShapeProps} from './Shape';
import {initial, signal} from '../decorators';
import {SignalValue, SimpleSignal} from '@motion-canvas/core/lib/signals';

function drawPolygon(
  path: CanvasRenderingContext2D | Path2D,
  rect: BBox,
  // width: number,
  // height: number,
  sides: number,
) {
  const width = rect.width / 2;
  const height = rect.height / 2;
  for (let i = 0; i <= sides; i += 1) {
    const theta = (i * 2 * Math.PI) / sides;
    const x = width * Math.sin(theta);
    const y = -height * Math.cos(theta);
    if (i == 0) {
      path.moveTo(x, y);
    } else {
      path.lineTo(x, y);
    }
  }
  path.closePath();
}

export interface PolygonProps extends ShapeProps {
  /**
   * {@inheritDoc Polygon.sides}
   */
  sides?: SignalValue<number>;
}

export class Polygon extends Shape {
  /**
   * Sets the number of sides of the polygon. For example, a value of 6
   * creates a hexagon.
   *
   * @remarks
   * Note that the polygon is inscribed in a circle defined by the height
   * and width. If height and width are unequal, the polygon is inscribed
   * in the resulting ellipse.
   *
   * Since the polygon is inscribed in the circle, the actual displayed
   * height and width may differ somewhat from the bounding rectangle. This
   * will be particularly noticable if the number of sides is low, e.g. for a
   * triangle.
   *
   *

Review comment (suggestion):
This is an optional suggestion, but I think the code would be a bit more readable when using vectors:
```suggestion
  const size = rect.size.scale(0.5);
  for (let i = 0; i <= sides; i++) {
    const theta = (i * 2 * Math.PI) / sides;
    const direction = Vector2.fromRadians(theta).perpendicular;
    const vertex = direction.mul(size);
    if (i == 0) {
      moveTo(path, vertex);
    } else {
      lineTo(path, vertex);
    }
  }
  path.closePath();
  ```
  since they better illustrate the math that's happening

Code after:
import {SignalValue, SimpleSignal} from '@motion-canvas/core/lib/signals';
import {drawPolygon} from '../utils';

export interface PolygonProps extends ShapeProps {
  /**
   * {@inheritDoc Polygon.sides}
   */
  sides?: SignalValue<number>;
}

/**
 * A node for drawing regular polygons.
 *
 * @remarks
 * This node can be used to render shapes such as: triangle, pentagon,
 * hexagon and more.
 *
 * Note that the polygon is inscribed in a circle defined by the height
 * and width. If height and width are unequal, the polygon is inscribed
 * in the resulting ellipse.
 *
 * Since the polygon is inscribed in the circle, the actual displayed
 * height and width may differ somewhat from the bounding rectangle. This
 * will be particularly noticable if the number of sides is low, e.g. for a
 * triangle.
 *
 * @example
 * A hexagon:
 * ```tsx
 * <Polygon
 *   sides={6}
 *   size={300}
 *   fill={'lightseagreen'}
 * />
 * ```
 * A pentagon outline:
 * ```tsx
 * <Polygon
 *   sides={5}
 *   size={300}
 *   stroke={'lightblue'}
 *   lineWidth={8}
 * />
 * ```
 */
export class Polygon extends Shape {
  /**
   * Sets the number of sides of the polygon.
   *
   * @remarks
   * For example, a value of 6 creates a hexagon.