import type {PossibleVector2, SignalValue, Vector2Signal} from '@revideo/core'; import {BBox, transformVectorAsPoint} from '@revideo/core'; import type {CurveProfile} from '../curves'; import {LineSegment} from '../curves'; import {nodeName, vector2Signal} from '../decorators'; import {arc, drawLine, drawPivot} from '../utils'; import type {CurveProps} from './Curve'; import {Curve} from './Curve'; export interface RayProps extends CurveProps { /** * {@inheritDoc Ray.from} */ from?: SignalValue; fromX?: SignalValue; fromY?: SignalValue; /** * {@inheritDoc Ray.to} */ to?: SignalValue; toX?: SignalValue; toY?: SignalValue; } /** * A node for drawing an individual line segment. * * @preview * ```tsx editor * import {makeScene2D} from '@revideo/2d'; * import {Ray} from '@revideo/2d'; * import {createRef} from '@revideo/core'; * * export default makeScene2D(function* (view) { * const ray = createRef(); * * view.add( * , * ); * * yield* ray().start(1, 1); * yield* ray().start(0).end(0).start(1, 1); * }); * ``` */ @nodeName('Ray') export class Ray extends Curve { /** * The starting point of the ray. */ @vector2Signal('from') public declare readonly from: Vector2Signal; /** * The ending point of the ray. */ @vector2Signal('to') public declare readonly to: Vector2Signal; public constructor(props: RayProps) { super(props); } protected override childrenBBox() { return BBox.fromPoints(this.from(), this.to()); } public override profile(): CurveProfile { const segment = new LineSegment(this.from(), this.to()); return { arcLength: segment.arcLength, minSin: 1, segments: [segment], }; } public override drawOverlay( context: CanvasRenderingContext2D, matrix: DOMMatrix, ) { const box = this.childrenBBox().transformCorners(matrix); const size = this.computedSize(); const offsetVector = size.mul(this.offset()).scale(0.5); const offset = transformVectorAsPoint(offsetVector, matrix); const from = transformVectorAsPoint(this.from(), matrix); const to = transformVectorAsPoint(this.to(), matrix); context.fillStyle = 'white'; context.strokeStyle = 'black'; context.lineWidth = 1; context.beginPath(); arc(context, from, 4); context.fill(); context.stroke(); context.beginPath(); arc(context, to, 4); context.fill(); context.stroke(); context.strokeStyle = 'white'; context.beginPath(); drawLine(context, [from, to]); context.stroke(); context.beginPath(); drawPivot(context, offset); context.stroke(); context.beginPath(); drawLine(context, box); context.closePath(); context.stroke(); } }