Skip to content

svgRotateBy function ​

An order of applySvgTransforms that turns the element by an angle from its position before this order, clockwise on screen, around an anchor of itself or of another element: set(90) after set(3) gives 90° from the start, not 93°.

ts
import { svgRotateBy } from 'utils';

Signature ​

ts
export function svgRotateBy(
  angleDegrees: number,
  anchor: Anchor = 'center',
  reference?: SVGGraphicsElement,
): SvgTransformOrder<[angleDegrees: number, anchor?: Anchor, reference?: SVGGraphicsElement]>

Parameters ​

NameDescription
angleDegreesThe rotation, in degrees.
anchorThe point that stays in place. Defaults to 'center'.
referenceThe element giving the anchor, in any group. Defaults to the element itself.

Returns ​

The order, to change with set(angleDegrees, anchor, reference).

Example ​

ts
const rotation = svgRotateBy(0, 'center', hub);
applySvgTransforms(needle, [rotation]);
rotation.set(30, 'center', hub); // 30° around the hub, from where it was drawn

Tests ​

Line coverage: 100 %.

  • ✅ turns from its position before the order, not from the previous value
  • ✅ turns from the default position given by its groups
  • ✅ turns around an anchor of another element

Source ​

src/svg-transform/svg-rotate-by.ts (on GitHub)

Uses ​

  • Anchor: One of the 9 points of a box: its corners, the middles of its sides, its center.
  • getSvgAnchorPoint: Finds an anchor of the box an SVG element takes on screen: a corner, the middle of a side or the center.
  • SvgTransformOrder: An order of applySvgTransforms, created by svgRotateBy, svgRotateTo, svgFlipTo, svgScaleBy, svgTranslateBy or svgPlaceOn: keep it to change its values later with set.

Files it needs ​

src/svg-transform/svg-rotate-by.ts imports, directly or not:

Source code
ts
import type { Anchor } from './anchor';
import { getSvgAnchorPoint } from './get-svg-anchor-point';
import { createMatrix, createOrder } from './internal';
import type { SvgTransformOrder } from './svg-transform-order';

/**
 * An order of `applySvgTransforms` that turns the element by an angle from its position before this order,
 * clockwise on screen, around an anchor of itself or of another element: `set(90)` after `set(3)` gives 90°
 * from the start, not 93°.
 *
 * @param angleDegrees - The rotation, 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
 * const rotation = svgRotateBy(0, 'center', hub);
 * applySvgTransforms(needle, [rotation]);
 * rotation.set(30, 'center', hub); // 30° around the hub, from where it was drawn
 */
export function svgRotateBy(
  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 { x, y } = getSvgAnchorPoint(other ?? element, point);
    return createMatrix(element).translate(x, y).rotate(angle).translate(-x, -y);
  });
}
Test file
ts
import { applySvgTransforms } from './apply-svg-transforms';
import { svgRotateBy } from './svg-rotate-by';
import { describeOnScreen, renderSvg } from './testing';

describe(svgRotateBy, () => {
  it('turns from its position before the order, not from the previous value', () => {
    const byId = renderSvg('<rect id="flag" transform="rotate(30 50 50)" x="40" y="45" width="20" height="10" />');
    const rotation = svgRotateBy(3);
    applySvgTransforms(byId('flag'), [rotation]);
    rotation.set(90);
    expect(describeOnScreen(byId('flag'))).toMatchObject({ rotation: 120 });
  });

  it('turns from the default position given by its groups', () => {
    const byId = renderSvg(
      '<g transform="rotate(90 50 50)"><rect id="bar" x="40" y="45" width="20" height="10" /></g>',
    );
    applySvgTransforms(byId('bar'), [svgRotateBy(90)]);
    expect(describeOnScreen(byId('bar'))).toMatchObject({ x: 40, y: 45, width: 20, height: 10, rotation: 180 });
  });

  it('turns around an anchor of another element', () => {
    const byId = renderSvg(
      '<rect id="needle" x="98" y="60" width="4" height="40" /><circle id="hub" cx="100" cy="100" r="5" />',
    );
    applySvgTransforms(byId('needle'), [svgRotateBy(90, 'center', byId('hub'))]);
    expect(describeOnScreen(byId('needle'))).toMatchObject({ x: 100, y: 98, width: 40, height: 4, rotation: 90 });
  });
});

Keywords: svg, rotate, by, svg transforms, function

Generated from the JSDoc of the sources.