All files / svg-transform svg-rotate-to.ts

100% Statements 7/7
100% Branches 5/5
100% Functions 2/2
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35          6x 6x                                   8x 8x 8x 8x 8x            
import type { Anchor } from './anchor';
import { getSvgAnchorPoint } from './get-svg-anchor-point';
import { createMatrix, createOrder, isMirrored } from './internal';
import type { SvgTransformOrder } from './svg-transform-order';
 
const HALF_TURN = 180;
const DEGREES_PER_RADIAN = HALF_TURN / Math.PI;
 
/**
 * An order of `applySvgTransforms` that turns the element to an absolute angle on screen, clockwise from
 * upright, around an anchor of itself or of another element: `svgRotateTo(0)` straightens it.
 *
 * @param angleDegrees - The angle on screen, in degrees.
 * @param anchor - The point that stays in place. Defaults to `'center'`.
 * @param reference - The element giving the anchor, in any group. Defaults to the element itself.
 * @returns The order, to change with `set(angleDegrees, anchor, reference)`.
 * @example
 * applySvgTransforms(label, [svgRotateTo(0)]); // upright, whatever its groups
 */
export function svgRotateTo(
  angleDegrees: number,
  anchor: Anchor = 'center',
  reference?: SVGGraphicsElement,
): SvgTransformOrder<[angleDegrees: number, anchor?: Anchor, reference?: SVGGraphicsElement]> {
  return createOrder([angleDegrees, anchor, reference], (element, screen, angle, point, other) => {
    const sign = isMirrored(screen) ? -1 : 1;
    const current = Math.atan2(sign * screen.b, sign * screen.a) * DEGREES_PER_RADIAN;
    const { x, y } = getSvgAnchorPoint(other ?? element, point);
    return createMatrix(element)
      .translate(x, y)
      .rotate(angle - current)
      .translate(-x, -y);
  });
}