svgRotateTo function
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.
ts
import { svgRotateTo } from 'utils';Signature
ts
export function svgRotateTo(
angleDegrees: number,
anchor: Anchor = 'center',
reference?: SVGGraphicsElement,
): SvgTransformOrder<[angleDegrees: number, anchor?: Anchor, reference?: SVGGraphicsElement]>Parameters
| Name | Description |
|---|---|
angleDegrees | The angle on screen, in degrees. |
anchor | The point that stays in place. Defaults to 'center'. |
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
ts
applySvgTransforms(label, [svgRotateTo(0)]); // upright, whatever its groupsTests
Line coverage: 100 %.
- ✅ straightens rotate(30 50 50) in place with 0
- ✅ straightens rotate(30 50 50) scale(-1 1) translate(-100 0) in place with 0
- ✅ turns to an absolute angle around an anchor
- ✅ turns around an anchor of another element
Source
src/svg-transform/svg-rotate-to.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 ofapplySvgTransforms, created bysvgRotateBy,svgRotateTo,svgFlipTo,svgScaleBy,svgTranslateByorsvgPlaceOn: keep it to change its values later withset.
Files it needs
src/svg-transform/svg-rotate-to.ts imports, directly or not:
src/svg-transform/anchor.tssrc/svg-transform/get-svg-anchor-point.tssrc/svg-transform/internal/create-matrix.tssrc/svg-transform/internal/create-order.tssrc/svg-transform/internal/get-anchor-point.tssrc/svg-transform/internal/get-owner-svg.tssrc/svg-transform/internal/is-mirrored.tssrc/svg-transform/internal/order-states.tssrc/svg-transform/svg-transform-order.ts
Source code
ts
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);
});
}Test file
ts
import { applySvgTransforms } from './apply-svg-transforms';
import { svgRotateTo } from './svg-rotate-to';
import { describeOnScreen, renderSvg } from './testing';
describe(svgRotateTo, () => {
it.for([
['rotate(30 50 50)', false],
['rotate(30 50 50) scale(-1 1) translate(-100 0)', true],
] as const)('straightens %s in place with 0', ([transform, isFlipped]) => {
const byId = renderSvg(
`<g transform="rotate(20 50 50)"><rect id="symbol" transform="${transform}" x="40" y="45" width="20" height="10" /></g>`,
);
applySvgTransforms(byId('symbol'), [svgRotateTo(0)]);
expect(describeOnScreen(byId('symbol'))).toMatchObject({
x: 40,
y: 45,
width: 20,
height: 10,
rotation: 0,
isFlipped,
});
});
it('turns to an absolute angle around an anchor', () => {
const byId = renderSvg('<rect id="flag" transform="rotate(45 40 40)" x="40" y="40" width="20" height="10" />');
applySvgTransforms(byId('flag'), [svgRotateTo(90, 'top-left')]);
expect(describeOnScreen(byId('flag'))).toMatchObject({ rotation: 90 });
});
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'), [svgRotateTo(90, 'center', byId('hub'))]);
expect(describeOnScreen(byId('needle'))).toMatchObject({ x: 100, y: 98, width: 40, height: 4, rotation: 90 });
});
});Keywords: svg, rotate, to, svg transforms, function