Skip to content

packages/core/src/lib/components/ellipse.ts

Read as Markdown

This is the source snapshot used to build these API details. View this revision on GitHub.

Back to reference

1 import { definePrimitive } from '../define-primitive.js';
2 import type {
3   PibblEventFocusOptions,
4   PibblEventHandlers,
5   PibblEventParticipationOptions,
6 } from '../events/types.js';
7 import type { RenderingContext2D, SystemStyle } from '../types.js';
8 import type { PibblPhysics2DPropExtension } from '../types.js';
9 import {
10   resolveLocalOffset,
11   stripLayoutParticipation,
12 } from '../style/resolve-built-in.js';
13 import { registerOpaqueStyleProperties } from '../style/resolve-dispatch.js';
14 import type {
15   BoxStyle,
16   CursorStyle,
17   LayoutItemStyle,
18   Length,
19   PaintStyle,
20   ResolvedDrawingStyle,
21 } from '../style/types.js';
22 import {
23   resolveFiniteShapeNumber,
24   resolveNonnegativeShapeLength,
25 } from './shape-style.js';
26 import { renderPath } from './path.js';
27 import { createEllipsePath } from '../geometry/ellipse.js';
28 
29 /**
30  * Authored inputs for Ellipse, including the declared data and presentation options.
31  *
32  * @see {@link PibblEventHandlers}
33  * @see {@link PibblEventParticipationOptions}
34  * @see {@link PibblPhysics2DPropExtension}
35  * @see {@link Ellipse}
36  */
37 export interface EllipseProps extends PibblEventHandlers, PibblEventFocusOptions, PibblEventParticipationOptions, PibblPhysics2DPropExtension {}
38 
39 /**
40  * Supported geometry and presentation properties for Ellipse.
41  *
42  * @see {@link SystemStyle}
43  * @see {@link PaintStyle}
44  * @see {@link CursorStyle}
45  * @see {@link BoxStyle}
46  * @see {@link LayoutItemStyle}
47  * @see {@link Length}
48  * @see {@link Ellipse}
49  */
50 export interface EllipseStyle
51   extends SystemStyle, PaintStyle, CursorStyle, BoxStyle, LayoutItemStyle {
52   /** Horizontal ellipse radius. See {@link Length}. */
53   radiusX: Exclude<Length, 'auto'>;
54   /** Vertical ellipse radius. See {@link Length}. */
55   radiusY: Exclude<Length, 'auto'>;
56   /** Horizontal coordinate of the center. See {@link Length}. */
57   cx?: Exclude<Length, 'auto'>;
58   /** Vertical coordinate of the center. See {@link Length}. */
59   cy?: Exclude<Length, 'auto'>;
60   /** Rotation applied to the containing geometry. See {@link EllipseStyle}. */
61   rotation?: number;
62   /**
63    * Width used for line hit testing independently of the visible stroke width. See
64    * {@link EllipseStyle}.
65    */
66   lineInteractionWidth?: number;
67 }
68 
69 type ResolvedEllipseStyle = ResolvedDrawingStyle<EllipseStyle> & {
70   radiusX: number;
71   radiusY: number;
72   cx: number;
73   cy: number;
74   rotation: number;
75 };
76 
77 function renderEllipse(
78   props: EllipseProps,
79   style: Readonly<ResolvedEllipseStyle>,
80   ctx: RenderingContext2D,
81 ) {
82   const { cx, cy, radiusX, radiusY, rotation, ...pathStyle } = style;
83   const path = createEllipsePath({ cx, cy, radiusX, radiusY, rotation });
84   const halfWidth = Math.sqrt(
85     (radiusX * Math.cos(rotation)) ** 2 +
86       (radiusY * Math.sin(rotation)) ** 2,
87   );
88   const halfHeight = Math.sqrt(
89     (radiusX * Math.sin(rotation)) ** 2 +
90       (radiusY * Math.cos(rotation)) ** 2,
91   );
92 
93   return renderPath({
94     ...props,
95     keyboardNavigationBounds: props.keyboardNavigationBounds ?? {
96       x: cx - halfWidth,
97       y: cy - halfHeight,
98       width: halfWidth * 2,
99       height: halfHeight * 2,
100     },
101   }, {
102     ...pathStyle,
103     d: path,
104   }, ctx);
105 }
106 
107 /**
108  * Describes an ellipse primitive for JSX or createElement authoring.
109  *
110  * @param props - Authored component inputs, supplied through JSX or createElement. See the linked
111  * props and style types.
112  * @throws When called directly; Pibbl mounts this component through JSX or createElement.
113  *
114  * @see {@link EllipseProps}
115  * @see {@link EllipseStyle}
116  */
117 export const Ellipse = definePrimitive<
118   EllipseProps,
119   EllipseStyle,
120   EllipseStyle,
121   ResolvedEllipseStyle
122 >(renderEllipse, {
123   resolveStyle: (style, context) => ({
124     ...stripLayoutParticipation(style),
125     cx: resolveLocalOffset(style.cx, context.percentageBasis.width, 'cx', context),
126     cy: resolveLocalOffset(style.cy, context.percentageBasis.height, 'cy', context),
127     radiusX: resolveNonnegativeShapeLength(
128       style.radiusX,
129       context.percentageBasis.width,
130       'radiusX',
131       context,
132     ),
133     radiusY: resolveNonnegativeShapeLength(
134       style.radiusY,
135       context.percentageBasis.height,
136       'radiusY',
137       context,
138     ),
139     rotation: resolveFiniteShapeNumber(style.rotation ?? 0, 'rotation', context),
140   }) as ResolvedEllipseStyle,
141 });
142 registerOpaqueStyleProperties(Ellipse, ['fill', 'stroke', 'cursor']);
143 

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.