import { createInjectiveInstanceFactory } from '../../injective-instance-factory.js'; import { Layout } from '../../layout.js'; import { Projection, ProjectionNode } from '../../projection-node.js'; import { ProjectionNodeBehavior } from '../../projection-node-behavior.js'; import { BorderRadiusCornerConfig } from './config.js'; import { isBorderRadiusesMeasured } from './measurement.js'; /** * A behavior that additionally calibrates the distortion of the border radius * styles of the element when projecting. * * Requires the measurement to satisfy {@link MeasurementWithBorderRadiuses}. * Throws an error otherwise. */ export class CalibrateBorderRadius extends ProjectionNodeBehavior { /** * Returns a behavior instance of the given node. * If exists, returns the previous behavior instance of this node. */ static for = createInjectiveInstanceFactory( (node: ProjectionNode) => new CalibrateBorderRadius(node), ); protected constructor(kernel: ProjectionNode) { super(kernel); } override reset(): void { super.reset(); this.element().style.borderRadius = ''; } override project(dest: Layout): Projection { const projection = super.project(dest); const { measurement } = projection; if (!isBorderRadiusesMeasured(measurement)) throw new Error('border radiuses are not measured'); const radiuses = measurement.borderRadiuses; const scaleX = projection.transformPhysical.x.scale; const scaleY = projection.transformPhysical.y.scale; const radiusStyle = (radius: BorderRadiusCornerConfig) => `${radius.x / scaleX}px ${radius.y / scaleY}px`; const element = this.element(); element.style.borderTopLeftRadius = radiusStyle(radiuses.topLeft); element.style.borderTopRightRadius = radiusStyle(radiuses.topRight); element.style.borderBottomLeftRadius = radiusStyle(radiuses.bottomLeft); element.style.borderBottomRightRadius = radiusStyle(radiuses.bottomRight); return projection; } protected override decorate(target: ProjectionNode): this { return CalibrateBorderRadius.for(target) as this; } }