/** @jsxImportSource react */ import { BoundedObject, BoundedObjectConfig, BoundedObjectInstance } from "../svg/BoundedObject"; import { parseStyle } from "../util/parseStyle"; import { VDOM } from "../ui/Widget"; import { RenderingContext, CxChild } from "../ui/RenderingContext"; import { NumberProp, StyleProp } from "../ui/Prop"; import type { ChartRenderingContext } from "./Chart"; export interface SwimlanesConfig extends BoundedObjectConfig { /** * Name of the horizontal axis. The value should match one of the horizontal axes set * in the `axes` configuration of the parent `Chart` component. Default value is `x`. * Set to `false` to hide the grid lines in x direction. */ xAxis?: string | boolean; /** * Name of the vertical axis. The value should match one of the vertical axes set * in the `axes` configuration if the parent `Chart` component. Default value is `y`. * Set to `false` to hide the grid lines in y direction. */ yAxis?: string | boolean; /** Base CSS class to be applied to the element. Defaults to `swimlanes`. */ baseClass?: string; /** Represents a swimlane size. */ size?: NumberProp; /** * Represents a swimlane step. Define a step on which a swimlane will be rendered. (eg. step 2 will render * every second swimlane in the chart.) */ step?: NumberProp; /** Switch to vertical swimlanes. */ vertical?: boolean; /** The laneOffset property adjusts the positioning of lane elements, enhancing their alignment and readability. */ laneOffset?: NumberProp; /** Style object applied to the swimlanes. */ laneStyle?: StyleProp; } export interface SwimlanesInstance extends BoundedObjectInstance { xAxis?: any; yAxis?: any; } export class Swimlanes extends BoundedObject { declare xAxis: string; declare yAxis: string; declare anchors: string; declare baseClass: string; declare size: number; declare laneOffset: number; declare step: number; declare vertical: boolean; declare styled: boolean; declare laneStyle: any; declare CSS: any; constructor(config?: SwimlanesConfig) { super(config); } init() { this.laneStyle = parseStyle(this.laneStyle); super.init(); } declareData(...args: any[]) { super.declareData(...args, { size: undefined, step: undefined, laneOffset: undefined, laneStyle: { structured: true }, }); } explore(context: ChartRenderingContext, instance: SwimlanesInstance) { super.explore(context, instance); instance.xAxis = context.axes?.[this.xAxis]; instance.yAxis = context.axes?.[this.yAxis]; } prepare(context: RenderingContext, instance: SwimlanesInstance) { super.prepare(context, instance); let { xAxis, yAxis } = instance; if ((xAxis && xAxis.shouldUpdate) || (yAxis && yAxis.shouldUpdate)) instance.markShouldUpdate(context); } render(context: RenderingContext, instance: SwimlanesInstance, key: string): CxChild { let { data, xAxis, yAxis } = instance; const d = data as any; let { bounds } = d; let { CSS, baseClass } = this; if (d.step <= 0 || d.size <= 0) return null; let axis = this.vertical ? xAxis : yAxis; if (!axis) return null; let min: number, max: number, valueFunction: (value: number, offset: number) => [any, number]; if (axis.scale) { min = axis.scale.min; max = axis.scale.max; let clamp = (value: number): [number, number] => [Math.max(min, Math.min(max, value)), 0]; valueFunction = (value, offset) => clamp(value + offset); } else if (axis.valueList) { min = 0; max = axis.valueList.length; valueFunction = (value, offset) => [axis.valueList[value], offset]; } if (!(min! < max!)) return null; let rects: React.ReactElement[] = []; let at = Math.ceil(min! / d.step) * d.step; let index = 0; let rectClass = CSS.element(baseClass, "lane"); while (at - d.size / 2 < max!) { let c1 = axis.map(...valueFunction!(at, -d.size / 2 + d.laneOffset)); let c2 = axis.map(...valueFunction!(at, +d.size / 2 + d.laneOffset)); if (this.vertical) { rects.push( ); } else { rects.push( ); } at += d.step; } return ( {rects} ); } } Swimlanes.prototype.xAxis = "x"; Swimlanes.prototype.yAxis = "y"; Swimlanes.prototype.anchors = "0 1 1 0"; Swimlanes.prototype.baseClass = "swimlanes"; Swimlanes.prototype.size = 0.5; Swimlanes.prototype.laneOffset = 0; Swimlanes.prototype.step = 1; Swimlanes.prototype.vertical = false; Swimlanes.prototype.styled = true; BoundedObject.alias("swimlanes", Swimlanes);