@oicl/openbridge-webcomponents 2.0.0-next.94 → 2.0.0-next.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/openbridge-webcomponents.bundle.js +153 -23
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +66 -49
- package/dist/building-blocks/chart-line/chart-line-base.d.ts +95 -33
- package/dist/building-blocks/chart-line/chart-line-base.d.ts.map +1 -1
- package/dist/building-blocks/chart-line/chart-line-base.js +88 -23
- package/dist/building-blocks/chart-line/chart-line-base.js.map +1 -1
- package/dist/charthelpers/index.d.ts +1 -0
- package/dist/charthelpers/index.d.ts.map +1 -1
- package/dist/charthelpers/index.js +4 -0
- package/dist/charthelpers/index.js.map +1 -1
- package/dist/charthelpers/x-value.d.ts +72 -0
- package/dist/charthelpers/x-value.d.ts.map +1 -0
- package/dist/charthelpers/x-value.js +60 -0
- package/dist/charthelpers/x-value.js.map +1 -0
- package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts +16 -1
- package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts.map +1 -1
- package/dist/navigation-instruments/gauge-trend/gauge-trend.js +12 -0
- package/dist/navigation-instruments/gauge-trend/gauge-trend.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-line-base.js","sources":["../../../src/building-blocks/chart-line/chart-line-base.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, query} from 'lit/decorators.js';\nimport componentStyle from './chart-line-base.css?inline';\nimport chartCommonStyle from '../../charthelpers/chart-common.css?inline';\nimport chartDebugStyle from '../../charthelpers/chart-debug.css?inline';\nimport chartLegendStyle from '../../charthelpers/chart-legend.css?inline';\nimport {\n Chart,\n LineController,\n LineElement,\n PointElement,\n ArcElement,\n Tooltip,\n CategoryScale,\n LinearScale,\n TimeScale,\n Filler,\n} from 'chart.js';\nimport type {ChartOptions, ChartDataset, ChartConfiguration} from 'chart.js';\nimport {\n InstrumentState,\n FrameStyle,\n BorderRadiusPosition,\n Priority,\n} from '../../navigation-instruments/types.js';\nimport {\n CHART_SECTOR_DEFAULT_COLORS,\n CHART_SECTOR_ENHANCED_COLORS,\n RECTANGULAR_CHART_DIMENSIONS,\n LINE_GRAPH_LABEL_CONFIG,\n LINE_GRAPH_GRID_CONFIG,\n CHART_DIMENSIONS,\n CHART_AREA_BACKGROUND_COLOR_VAR,\n getCssVariableValue,\n getChartColorsOrDefault,\n observeThemeChanges,\n formatNumericValue,\n getChartTooltipOptions,\n generateLegendHTML,\n applyAlphaToColor,\n} from '../../charthelpers/index.js';\nimport {\n EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR,\n readExternalScaleBorderRadiusPx,\n startExternalScaleBorderRadiusObserver,\n ScaleType,\n} from '../external-scale/external-scale.js';\n\n// Register Chart.js components used by the line graph (scales, elements, plugins)\nChart.register(\n LineController,\n LineElement,\n PointElement,\n ArcElement,\n CategoryScale,\n LinearScale,\n TimeScale,\n Filler,\n Tooltip\n);\n\n/**\n * Dimension information reported by external scale components.\n * Dispatched via 'scale-dimensions-changed' event from slotted scale elements.\n */\nexport interface ExternalScaleDimensions {\n /** Which side this scale is positioned on */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Natural thickness in pixels (width for vertical, height for horizontal) */\n thickness: number;\n}\n\n/**\n * Type guard to check if an element is an external scale component\n */\ninterface ExternalScaleElement extends HTMLElement {\n minValue?: number;\n maxValue?: number;\n height?: number;\n width?: number;\n paddingTop?: number;\n paddingBottom?: number;\n paddingLeft?: number;\n paddingRight?: number;\n paddingStart?: number;\n paddingEnd?: number;\n primaryTickmarkInterval?: number;\n showLabels?: boolean;\n fixedAspectRatio?: boolean;\n scaleReferenceSize?: number;\n state?: InstrumentState;\n priority?: Priority;\n frameStyle?: FrameStyle;\n borderRadiusPosition?: BorderRadiusPosition;\n}\n\nexport enum XAxisType {\n category = 'category',\n time = 'time',\n}\n\nexport enum YAxisPosition {\n left = 'left',\n right = 'right',\n}\n\nexport enum LineMode {\n smooth = 'smooth',\n straight = 'straight',\n stepped = 'stepped',\n}\n\nexport enum TimeDisplay {\n minutes = 'minutes',\n date = 'date',\n}\n\nexport type ChartLineDataItem = {\n label: string;\n value: number;\n};\n\nexport type ChartLineYAxisConfig = {\n id?: string;\n position?: 'left' | 'right';\n min?: number;\n max?: number;\n grid?: boolean;\n};\n\nconst LINE_GRAPH_WATCHED_PROP_NAMES = [\n 'data',\n 'datasets',\n 'labels',\n 'colors',\n 'xAxisType',\n 'yAxisPosition',\n 'yAxes',\n 'showGrid',\n 'showGridX',\n 'showGridY',\n 'showTickMarks',\n 'showPoints',\n 'lineMode',\n 'unit', // Used in tooltip display\n 'timeDisplay',\n 'xTicksLimit',\n 'xStepSize',\n 'yTicksLimit',\n 'yStepSize',\n 'priority', // Triggers color palette change\n 'borderRadiusPosition', // Triggers border styling update\n 'borderRadiusPositionExternalScales', // Triggers external scale border styling update\n // legend only affects HTML; do not use it to drive chart updates\n 'width',\n 'height',\n 'fixedAspectRatioScaling', // Triggers responsive mode change\n 'hasLabelPadding', // Toggles edge-to-edge rendering and label visibility\n] as const;\n\nconst LINE_GRAPH_RECREATE_PROP_NAMES = [\n 'showDebugOverlay',\n 'width',\n 'height',\n 'fixedAspectRatioScaling',\n] as const;\n\n/**\n * Abstract base class for line and area chart components built on Chart.js.\n *\n * ## Features\n * - **Single or multi-series**: Use `data` for simple single-series or `datasets` for multi-series charts\n * - **Time and category axes**: Supports `category` x-axis (labels) and `time` x-axis (ISO dates or timestamps)\n * - **Line styles**: Choose `smooth` (curved), `straight`, or `stepped` line rendering\n * - **Fill modes**: Area fills with `semitransparent`, `solid`, or `threshold` (red/blue above/below midpoint)\n * - **Stacked charts**: Enable `stacked` for multi-series datasets to stack values on y-axis\n * - **Flexible axes**: Single y-axis via `yAxisPosition` or multi-axis via `yAxes` for complex charts\n * - **Theme-aware**: Automatically updates colors on theme changes using CSS variables\n * - **Responsive sizing**: Fixed height with 1.5:1 aspect ratio (e.g., 320px height → 480px width)\n * - **Grid & ticks**: Toggle grid lines (`showGrid`, `showGridX`, `showGridY`) and tick marks (`showTickMarks`)\n * - **Legend support**: Optional HTML legend showing series labels with `legend` property\n * - **External axis support**: via slots\n * - **Color priority**: Set `priority` to `Priority.enhanced` to use the blue/enhanced\n * color palette instead of the default gray/regular palette (default: `Priority.regular`)\n *\n * ## Size Behavior\n * - Above 192px: Shows labels, tick marks, and grid lines with standard padding\n * - Below 192px: Hides labels/ticks and uses edge-to-edge rendering for compact display\n *\n * ## Examples\n *\n * Basic single-series with category axis:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.data = [\n * {label: 'Jan', value: 10},\n * {label: 'Feb', value: 14},\n * {label: 'Mar', value: 12}\n * ];\n * chart.unit = 'kW';\n * chart.height = 256;\n * </script>\n * ```\n *\n * Multi-series with time axis and legend:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.xAxisType = 'time';\n * chart.timeDisplay = 'date';\n * chart.legend = true;\n * chart.datasets = [\n * {label: 'Temperature', data: [{x: '2025-01-01', y: 20}, {x: '2025-01-02', y: 22}]},\n * {label: 'Humidity', data: [{x: '2025-01-01', y: 65}, {x: '2025-01-02', y: 68}]}\n * ];\n * </script>\n * ```\n *\n * Stacked area chart with solid fill:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.datasets = [\n * {label: 'Series A', data: [2, 3, 4, 3, 5]},\n * {label: 'Series B', data: [1, 2, 3, 2, 4]},\n * {label: 'Series C', data: [3, 2, 1, 2, 3]}\n * ];\n * chart.fill = true;\n * chart.fillMode = 'solid';\n * chart.stacked = true;\n * chart.legend = true;\n * </script>\n * ```\n *\n * Threshold fill (single-series only):\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.data = [{label: '1', value: 20}, {label: '2', value: 45}, {label: '3', value: 35}];\n * chart.fill = true;\n * chart.fillMode = 'threshold';\n * </script>\n * ```\n *\n * Multi-axis chart with right-side y-axis:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.yAxes = [\n * {id: 'y-temp', position: 'left', min: 0, max: 100},\n * {id: 'y-pressure', position: 'right', min: 0, max: 10}\n * ];\n * chart.datasets = [\n * {label: 'Temperature', data: [20, 25, 30], yAxisID: 'y-temp'},\n * {label: 'Pressure', data: [2, 3, 2.5], yAxisID: 'y-pressure'}\n * ];\n * </script>\n * ```\n *\n * @property {Array<{label: string, value: number}>} data - Single-series data array. Each object must have `label` (string) and `value` (number). Used when `datasets` is not provided.\n * @property {ChartDataset<'line', (number | {x: string|number|Date; y: number})[]>[]} datasets - Multi-series Chart.js datasets. Takes precedence over `data`. Each dataset can have `label`, `data` (numeric array or `{x, y}` points), and visual properties like `borderColor`, `backgroundColor`, `fill`, etc.\n * @property {(string|number)[]} labels - Explicit labels for category x-axis. If omitted, labels are derived from `data` property or dataset x-values.\n * @property {string[]} colors - Custom color palette (CSS variable names or color strings). Falls back to theme default colors if not provided.\n * @property {'category'|'time'} xAxisType - X-axis mode. `'category'` for labeled data points, `'time'` for time-based data (ISO strings or timestamps). Default: `'category'`.\n * @property {'minutes'|'date'} timeDisplay - Time axis label format when `xAxisType='time'`. `'date'` shows full date/time, `'minutes'` shows minutes relative to first data point. Default: `'date'`.\n * @property {'left'|'right'} yAxisPosition - Single y-axis position. Use this for simple charts with one y-axis. For multiple y-axes, use `yAxes` property instead. Default: `'left'`.\n * @property {Array<{id?: string; position?: 'left'|'right'; min?: number; max?: number; grid?: boolean}>} yAxes - Multiple y-axis definitions for complex charts. Each axis can specify `id` (referenced by dataset `yAxisID`), `position`, `min`/`max` range, and `grid` visibility.\n * @property {boolean} showGrid - Show vertical grid lines (x-axis). When combined with `showGridX` and `showGridY`, controls full grid visibility. Default: `false`.\n * @property {boolean} showGridX - Show vertical grid lines (x-axis). Set to `false` to hide only vertical lines while keeping horizontal lines. Default: `false`.\n * @property {boolean} showGridY - Show horizontal grid lines (y-axis). Set to `false` to hide only horizontal lines while keeping vertical lines. Default: `false`.\n * @property {boolean} showTickMarks - Show axis tick marks and labels. Automatically hidden below 192px height threshold. Default: `false`.\n * @property {boolean} showPoints - Show point markers on data points. Default: `false`.\n * @property {boolean} fill - Enable area fill under/between lines. Use with `fillMode` to control fill style. Default: `false`.\n * @property {'semitransparent'|'solid'|'threshold'} fillMode - Fill rendering mode. `'semitransparent'` uses 50% alpha, `'solid'` uses opaque fill, `'threshold'` (single-series only) fills above/below midpoint with red/blue gradient. Default: `'semitransparent'`.\n * @property {'smooth'|'straight'|'stepped'} lineMode - Line drawing style. `'smooth'` applies bezier curve tension, `'straight'` draws straight lines, `'stepped'` creates step-like lines. Default: `'smooth'`.\n * @property {boolean} stacked - Stack multi-series datasets vertically on y-axis. Ignored for single-series and threshold fill mode. Default: `false`.\n * @property {string} unit - Unit label displayed in tooltips (e.g., 'kW', 'kg', '%'). Default: empty string.\n * @property {number} xTicksLimit - Maximum number of x-axis ticks/grid lines. Useful for matching external axes. Optional.\n * @property {number} xStepSize - Force specific interval between x-axis ticks (e.g., 1, 2, 5). Useful for matching external axes. Optional.\n * @property {number} yTicksLimit - Maximum number of y-axis ticks/grid lines. Useful for matching external axes. Optional.\n * @property {number} yStepSize - Force specific interval between y-axis ticks (e.g., 2, 5, 10). Useful for matching external axes. Optional.\n * @property {boolean} legend - Show HTML legend below chart with series labels and colors. Default: `false`.\n * @property {number} height - Chart height in pixels. Determines chart size with 1.5:1 aspect ratio (width = height × 1.5). Default: `320`.\n * @property {boolean} showDebugOverlay - Development mode: show visual debug overlay with dimension guides. Shows blue border around canvas (axis area) and red border around chart grid (data area). Default: `false`.\n *\n * @ignore This is an abstract base class. Use concrete implementations like ObcLineGraph or ObcAreaGraph instead.\n * @experimental\n */\nexport class ObcChartLineBase extends LitElement {\n /** Simple single-series data (array of {label, value}). */\n @property({type: Array, attribute: false})\n data: ChartLineDataItem[] = [];\n\n /** Chart.js-style datasets for multi-series use. If provided, takes precedence over `data`. */\n @property({type: Array, attribute: false})\n datasets?: ChartDataset<\n 'line',\n (number | {x: string | number | Date; y: number})[]\n >[] = undefined;\n\n /** Optional explicit labels for the x-axis (category mode). If omitted labels are derived from `data` */\n @property({type: Array, attribute: false})\n labels?: (string | number)[] = undefined;\n\n /** Custom color palette (CSS variable names or color strings). */\n @property({type: Array, attribute: false})\n colors: string[] = [];\n\n /** Show HTML legend below chart with series labels and colors. */\n @property({type: Boolean, reflect: true})\n legend = false;\n\n /** Development mode: show visual debug overlay with dimension guides. */\n @property({type: Boolean, reflect: true})\n showDebugOverlay = false;\n\n /** Width of the chart in pixels. Default: 480. */\n @property({type: Number, reflect: true})\n width = 480;\n\n /** Height of the chart in pixels. Default: 320. */\n @property({type: Number, reflect: true})\n height = 320;\n\n /**\n * Enable fixed aspect ratio scaling mode.\n * When true, width/height properties define the aspect ratio (not actual pixels).\n * The component fills 100% of parent width and calculates height from aspect ratio.\n * When false (default), width/height are used as actual pixel dimensions.\n */\n @property({type: Boolean, reflect: true})\n fixedAspectRatioScaling = false;\n\n /**\n * Reference size for external scales when using fixedAspectRatioScaling.\n * This value is passed down to external scales to determine their 1:1 Figma design size.\n * At this reference size, scales render at native size; above/below they scale proportionally.\n * Default: 384 (matches Figma design baseline).\n */\n @property({type: Number})\n scaleReferenceSize = 384;\n\n /** X-axis mode: 'category' for labeled data points, 'time' for time-based data. */\n @property({type: String})\n xAxisType: XAxisType = XAxisType.category;\n\n /** Single y-axis position ('left' or 'right'). For multiple y-axes, use yAxes instead. */\n @property({type: String})\n yAxisPosition: YAxisPosition = YAxisPosition.left;\n\n /** Multiple y-axis definitions for complex multi-axis charts. */\n @property({type: Array, attribute: false})\n yAxes?: ChartLineYAxisConfig[] = undefined;\n\n /** Show grid lines. */\n @property({type: Boolean})\n showGrid = false;\n\n /**\n * Show vertical grid lines (x-axis). Default: false.\n * @availableWhen showGrid==true\n */\n @property({type: Boolean})\n showGridX = false;\n\n /**\n * Show horizontal grid lines (y-axis). Default: false.\n * @availableWhen showGrid==true\n */\n @property({type: Boolean})\n showGridY = false;\n\n /** Show axis tick marks and labels. */\n @property({type: Boolean})\n showTickMarks = false;\n\n /**\n * Reserve canvas padding for axis tick labels on sides without an external scale.\n *\n * When `true` (default), the chart leaves room for tick labels and renders them\n * (subject to `showTickMarks` and the 192px auto-compact threshold).\n *\n * When `false`, the chart renders edge-to-edge on sides without a slotted external\n * scale AND axis tick labels are force-hidden so they cannot be clipped. This also\n * suppresses the automatic edge-to-edge switch that normally happens below the\n * 192px threshold, eliminating the visible padding \"jump\" when crossing it.\n *\n * Useful when embedding the chart inside another component that owns framing\n * and never wants to show axis labels (e.g. `obc-automation-tank`).\n *\n * Defaults to `true` to preserve existing behavior. Declared with `attribute: false`\n * because a `true`-default boolean cannot work as an HTML boolean attribute.\n */\n @property({type: Boolean, attribute: false})\n hasLabelPadding = true;\n\n // Internal default tension used when `lineMode` is 'smooth'. Not exposed as a property.\n private readonly DEFAULT_TENSION = 0.4;\n\n // Internal default point radius when points are shown.\n private readonly POINT_RADIUS = 3;\n\n /** Show point markers on data points. Default: false. */\n @property({type: Boolean})\n showPoints = false;\n\n /** Line drawing style: 'smooth' (curved), 'straight', or 'stepped'. */\n @property({type: String})\n lineMode: LineMode = LineMode.smooth;\n\n /** Unit label displayed in tooltips (e.g., 'kW', 'kg', '%'). */\n @property({type: String})\n unit = '';\n\n /**\n * Time axis label format: 'date' (full date/time) or 'minutes' (relative).\n * @availableWhen xAxisType==time\n */\n @property({type: String})\n timeDisplay: TimeDisplay = TimeDisplay.date;\n\n /** Max number of x-axis ticks/grid lines. Useful for matching external axes. */\n @property({type: Number})\n xTicksLimit?: number = undefined;\n\n /** Force x-axis tick interval. Useful for matching external axes. */\n @property({type: Number})\n xStepSize?: number = undefined;\n\n /** Max number of y-axis ticks/grid lines. Useful for matching external axes. */\n @property({type: Number})\n yTicksLimit?: number = undefined;\n\n /** Force y-axis tick interval. Useful for matching external axes. */\n @property({type: Number})\n yStepSize?: number = undefined;\n\n /** Instrument state affecting colors of external scales. */\n @property({type: String})\n state: InstrumentState = InstrumentState.active;\n\n /** Color priority: enhanced uses blue palette instead of default gray. */\n @property({type: String})\n priority: Priority = Priority.regular;\n\n /** Frame style for chart and external scales. */\n @property({type: String})\n frameStyle: FrameStyle = FrameStyle.regular;\n\n /** Border radius position for the chart's own border. */\n @property({type: String})\n borderRadiusPosition?: BorderRadiusPosition = undefined;\n\n /** Border radius position for external scales based on layout. */\n @property({type: String})\n borderRadiusPositionExternalScales?: BorderRadiusPosition = undefined;\n\n /**\n * When true, the chart is used inside an instrument (e.g., gauge-trend).\n * In this mode, only label font size responds to .obc-component-size-* CSS classes.\n * Border radius uses the explicit `borderRadius` property value (or defaults to 8px),\n * rather than reading from CSS variables.\n * @default false\n */\n @property({type: Boolean})\n instrumentMode = false;\n\n /**\n * Explicit border radius value in pixels.\n * When instrumentMode=true, this value is used directly (defaults to 8px).\n * When instrumentMode=false, this is ignored and border radius is read from CSS variable.\n * @availableWhen instrumentMode==true\n */\n @property({type: Number})\n borderRadius?: number = undefined;\n\n /** @internal */\n @query('canvas') private canvasEl?: HTMLCanvasElement;\n\n /** @internal */\n @query('.legend') private legendDiv?: HTMLDivElement;\n\n /** @internal - Slot elements for external scales */\n @query('slot[name=\"top-scale\"]') private topScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"bottom-scale\"]') private bottomScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"left-scale\"]') private leftScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"right-scale\"]') private rightScaleSlot?: HTMLSlotElement;\n\n /** @internal */\n private chart?: Chart;\n\n /** @internal */\n private themeObserver?: MutationObserver;\n\n /** @internal - ResizeObserver for tracking height threshold crossings (e.g. MIN_HEIGHT_WITH_LABELS = 192px) */\n private resizeObserver?: ResizeObserver;\n\n /** @internal - Track previous state to detect threshold crossing */\n private wasAboveThreshold = false;\n\n /** @internal - Track external scale dimensions */\n private externalScaleDimensions: Map<string, number> = new Map();\n\n /** @internal - Debounce timer for dimension updates */\n private dimensionUpdateTimer?: ReturnType<typeof setTimeout>;\n\n /** @internal - Flag to prevent infinite update loops */\n private isUpdatingScales = false;\n\n /** @internal - Border radius observer for theme/size changes */\n private borderRadiusObserver?: MutationObserver;\n\n /** @internal - Current computed border radius in pixels */\n private currentBorderRadiusPx = 8;\n\n /** @internal - ResizeObserver for aspect ratio scaling */\n private aspectRatioResizeObserver?: ResizeObserver;\n\n /** @internal - Computed actual width when using fixed aspect ratio scaling */\n private computedWidth = 480;\n\n /** @internal - Computed actual height when using fixed aspect ratio scaling */\n private computedHeight = 320;\n\n /**\n * Should fill be applied to this chart?\n * Line graph returns false, area graph returns true.\n * Must be implemented in subclass.\n */\n protected shouldApplyFill(): boolean {\n throw new Error('shouldApplyFill() must be implemented in subclass');\n }\n\n /**\n * Get fill mode for area rendering.\n * Line graph returns undefined, area graph returns 'semitransparent' | 'solid' | 'threshold'.\n * Must be implemented in subclass.\n */\n protected getFillMode(): string | undefined {\n throw new Error('getFillMode() must be implemented in subclass');\n }\n\n /**\n * Should multi-series datasets be stacked?\n * Line graph returns false, area graph returns stacked property value.\n * Must be implemented in subclass.\n */\n protected shouldStack(): boolean {\n throw new Error('shouldStack() must be implemented in subclass');\n }\n\n /**\n * Compute which corners should be rounded based on borderRadiusPosition and\n * which external scales are present.\n *\n * Logic:\n * - Opposite scales (left+right OR top+bottom) → no rounding (middleChild behavior)\n * - Perpendicular scales (e.g., right+bottom):\n * - innerFirstChild → round corner adjacent to both scales\n * - outerLastChild → round free corner opposite to scales\n * - Single-side scales:\n * - When external scale is on RIGHT, chart is on LEFT\n * - innerFirstChild → round LEFT corners (top-left + bottom-left)\n * - outerLastChild → round RIGHT corners (top-right + bottom-right)\n * - When external scale is on LEFT, chart is on RIGHT (opposite)\n * - When external scale is on TOP, chart is on BOTTOM\n * - innerFirstChild → round BOTTOM corners (bottom-left + bottom-right)\n * - outerLastChild → round TOP corners (top-left + top-right)\n * - When external scale is on BOTTOM, chart is on TOP (opposite)\n * - middleChild → no rounding\n */\n\n /**\n * Check if a slotted scale element is actually visible (renders content).\n * For bar-vertical/bar-horizontal elements, checks hasBar and hasScale properties.\n */\n private hasVisibleScale(side: 'left' | 'right' | 'top' | 'bottom'): boolean {\n const slotMap = {\n left: this.leftScaleSlot,\n right: this.rightScaleSlot,\n top: this.topScaleSlot,\n bottom: this.bottomScaleSlot,\n };\n\n const slot = slotMap[side];\n const elements = slot?.assignedElements() ?? [];\n\n return elements.some((el: Element) => {\n const barEl = el as HTMLElement & {\n hasBar?: boolean;\n hasScale?: boolean;\n };\n\n // If it has hasBar and hasScale properties, check if at least one is true\n if ('hasBar' in barEl && 'hasScale' in barEl) {\n return barEl.hasBar === true || barEl.hasScale === true;\n }\n\n // Otherwise assume it's visible\n return true;\n });\n }\n\n private computeRoundedCorners(): {\n topLeft: boolean;\n topRight: boolean;\n bottomLeft: boolean;\n bottomRight: boolean;\n } {\n if (!this.borderRadiusPosition) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n if (this.borderRadiusPosition === BorderRadiusPosition.middleChild) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n // middleRoundedChild → round ALL corners (standalone instrument mode)\n if (this.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild) {\n return {\n topLeft: true,\n topRight: true,\n bottomLeft: true,\n bottomRight: true,\n };\n }\n\n // Determine which external scales are VISIBLE (not just present in slots)\n const hasLeft = this.hasVisibleScale('left');\n const hasRight = this.hasVisibleScale('right');\n const hasTop = this.hasVisibleScale('top');\n const hasBottom = this.hasVisibleScale('bottom');\n\n // If scales exist on opposite sides, behave like middleChild (no rounding)\n if ((hasLeft && hasRight) || (hasTop && hasBottom)) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n const result = {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n\n const isInner =\n this.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n const isOuter =\n this.borderRadiusPosition === BorderRadiusPosition.outerLastChild;\n\n // Handle perpendicular scale configurations (e.g., right + bottom)\n if (hasRight && hasBottom) {\n // Chart is in top-left position\n if (isInner) {\n result.bottomRight = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.topLeft = true; // Free corner\n }\n } else if (hasRight && hasTop) {\n // Chart is in bottom-left position\n if (isInner) {\n result.topRight = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.bottomLeft = true; // Free corner\n }\n } else if (hasLeft && hasBottom) {\n // Chart is in top-right position\n if (isInner) {\n result.bottomLeft = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.topRight = true; // Free corner\n }\n } else if (hasLeft && hasTop) {\n // Chart is in bottom-right position\n if (isInner) {\n result.topLeft = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.bottomRight = true; // Free corner\n }\n }\n // Handle single-side horizontal scales (left OR right, but not both)\n else if (hasRight && !hasLeft) {\n // Chart is on the left side of composition\n if (isInner) {\n result.topLeft = true;\n result.bottomLeft = true;\n } else if (isOuter) {\n result.topRight = true;\n result.bottomRight = true;\n }\n } else if (hasLeft && !hasRight) {\n // Chart is on the right side of composition\n if (isInner) {\n result.topRight = true;\n result.bottomRight = true;\n } else if (isOuter) {\n result.topLeft = true;\n result.bottomLeft = true;\n }\n }\n // Handle single-side vertical scales (top OR bottom, but not both)\n else if (hasBottom && !hasTop) {\n // Chart is on the top of composition\n if (isInner) {\n result.topLeft = true;\n result.topRight = true;\n } else if (isOuter) {\n result.bottomLeft = true;\n result.bottomRight = true;\n }\n } else if (hasTop && !hasBottom) {\n // Chart is on the bottom of composition\n if (isInner) {\n result.bottomLeft = true;\n result.bottomRight = true;\n } else if (isOuter) {\n result.topLeft = true;\n result.topRight = true;\n }\n }\n\n return result;\n }\n\n /**\n * Read current border radius from CSS variable and update state.\n * The chart will be recreated when needed through the normal update mechanism.\n * In instrument mode, uses explicit borderRadius value instead of CSS variable.\n */\n private updateBorderRadius = () => {\n if (!this.canvasEl) return;\n\n // In instrument mode, use explicit value or default (8px)\n // Skip CSS variable reading entirely\n let next: number;\n if (this.instrumentMode) {\n next = this.borderRadius ?? 8;\n } else {\n next = readExternalScaleBorderRadiusPx(\n this.canvasEl,\n ScaleType.regular,\n EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR\n );\n }\n\n if (this.currentBorderRadiusPx !== next) {\n this.currentBorderRadiusPx = next;\n // Trigger chart recreation to update border plugin\n if (this.chart) {\n this.chart.destroy();\n this.createChart();\n }\n }\n };\n\n /**\n * Create a Chart.js plugin that draws a border around the chart area with selective corner rounding\n * and clips content to that border.\n */\n private createBorderPlugin() {\n const corners = this.computeRoundedCorners();\n const radius = this.currentBorderRadiusPx;\n\n let didApplyClip = false;\n\n const buildRoundedRectPath = (\n ctx: CanvasRenderingContext2D,\n rect: {x: number; y: number; width: number; height: number},\n cornerRadius: number\n ) => {\n const {x, y, width, height} = rect;\n\n // Guard: Avoid invalid paths\n if (width <= 0 || height <= 0) return;\n\n const r = Math.max(\n 0,\n Math.min(cornerRadius, Math.min(width, height) / 2)\n );\n\n // Start at top-left corner (accounting for radius)\n ctx.moveTo(x + (corners.topLeft ? r : 0), y);\n\n // Top edge\n ctx.lineTo(x + width - (corners.topRight ? r : 0), y);\n\n // Top-right corner\n if (corners.topRight) {\n ctx.arcTo(x + width, y, x + width, y + r, r);\n }\n\n // Right edge\n ctx.lineTo(x + width, y + height - (corners.bottomRight ? r : 0));\n\n // Bottom-right corner\n if (corners.bottomRight) {\n ctx.arcTo(x + width, y + height, x + width - r, y + height, r);\n }\n\n // Bottom edge\n ctx.lineTo(x + (corners.bottomLeft ? r : 0), y + height);\n\n // Bottom-left corner\n if (corners.bottomLeft) {\n ctx.arcTo(x, y + height, x, y + height - r, r);\n }\n\n // Left edge\n ctx.lineTo(x, y + (corners.topLeft ? r : 0));\n\n // Top-left corner\n if (corners.topLeft) {\n ctx.arcTo(x, y, x + r, y, r);\n }\n };\n\n return {\n id: 'chartAreaBorder',\n beforeDatasetsDraw: (chart: Chart) => {\n const ctx = chart.ctx;\n const chartArea = chart.chartArea;\n\n if (!chartArea) return;\n\n // Draw/clip behavior should match CSS border-box:\n // - The border stroke must be fully INSIDE the chartArea.\n // - The stroke's OUTER edge should align to the chartArea boundary.\n // Reserve space by clipping content inside the border thickness.\n const borderWidthPx = 1;\n const clipInset = borderWidthPx;\n\n const {top, right, bottom, left} = chartArea;\n const rect = {\n x: left + clipInset,\n y: top + clipInset,\n width: right - left - clipInset * 2,\n height: bottom - top - clipInset * 2,\n };\n\n const clipRadius = Math.max(0, radius - clipInset);\n\n ctx.save();\n didApplyClip = true;\n\n // Create clipping path with selective corner rounding\n ctx.beginPath();\n\n buildRoundedRectPath(ctx as CanvasRenderingContext2D, rect, clipRadius);\n ctx.closePath();\n\n // Fill chart area background when in instrument mode\n if (this.instrumentMode) {\n const backgroundColor = getCssVariableValue(\n this,\n CHART_AREA_BACKGROUND_COLOR_VAR\n );\n ctx.fillStyle = backgroundColor;\n ctx.fill();\n }\n\n // Apply clipping\n ctx.clip();\n },\n afterDraw: (chart: Chart) => {\n const ctx = chart.ctx;\n const chartArea = chart.chartArea;\n\n if (!chartArea) return;\n\n const borderWidthPx = 1;\n const strokeInset = borderWidthPx / 2;\n\n const {top, right, bottom, left} = chartArea;\n const rect = {\n x: left + strokeInset,\n y: top + strokeInset,\n width: right - left - strokeInset * 2,\n height: bottom - top - strokeInset * 2,\n };\n\n const strokeRadius = Math.max(0, radius - strokeInset);\n\n // Check which sides have visible scales (edges to skip)\n const skipTop = this.hasVisibleScale('top');\n const skipRight = this.hasVisibleScale('right');\n const skipBottom = this.hasVisibleScale('bottom');\n const skipLeft = this.hasVisibleScale('left');\n\n // Get border color from CSS variable\n const borderColor = getCssVariableValue(\n this,\n '--instrument-frame-tertiary-color'\n );\n\n ctx.save();\n ctx.strokeStyle = borderColor;\n ctx.lineWidth = borderWidthPx;\n\n const {x, y, width, height} = rect;\n const r = Math.max(\n 0,\n Math.min(strokeRadius, Math.min(width, height) / 2)\n );\n\n // Draw border segments, skipping edges that have visible external scales\n if (!skipTop && !skipRight && !skipBottom && !skipLeft) {\n // No scales - draw full border path\n ctx.beginPath();\n buildRoundedRectPath(\n ctx as CanvasRenderingContext2D,\n rect,\n strokeRadius\n );\n ctx.closePath();\n ctx.stroke();\n } else {\n // Draw border in segments, skipping edges with visible scales\n // Each segment is drawn as a continuous path for proper corner rendering\n\n // Top edge (skip if top scale present)\n if (!skipTop) {\n ctx.beginPath();\n // Start: either from top-left corner end or top-left corner point\n if (!skipLeft && corners.topLeft) {\n ctx.moveTo(x + r, y);\n } else {\n ctx.moveTo(x, y);\n }\n // Draw to: either to top-right corner start or top-right corner point\n if (!skipRight && corners.topRight) {\n ctx.lineTo(x + width - r, y);\n } else {\n ctx.lineTo(x + width, y);\n }\n ctx.stroke();\n }\n\n // Right edge (skip if right scale present)\n if (!skipRight) {\n ctx.beginPath();\n // Start: either from top-right corner end or top-right point\n if (!skipTop && corners.topRight) {\n ctx.moveTo(x + width, y + r);\n } else {\n ctx.moveTo(x + width, y);\n }\n // Draw to: either to bottom-right corner start or bottom-right point\n if (!skipBottom && corners.bottomRight) {\n ctx.lineTo(x + width, y + height - r);\n } else {\n ctx.lineTo(x + width, y + height);\n }\n ctx.stroke();\n }\n\n // Bottom edge (skip if bottom scale present)\n if (!skipBottom) {\n ctx.beginPath();\n // Start: either from bottom-right corner end or bottom-right point\n if (!skipRight && corners.bottomRight) {\n ctx.moveTo(x + width - r, y + height);\n } else {\n ctx.moveTo(x + width, y + height);\n }\n // Draw to: either to bottom-left corner start or bottom-left point\n if (!skipLeft && corners.bottomLeft) {\n ctx.lineTo(x + r, y + height);\n } else {\n ctx.lineTo(x, y + height);\n }\n ctx.stroke();\n }\n\n // Left edge (skip if left scale present)\n if (!skipLeft) {\n ctx.beginPath();\n // Start: either from bottom-left corner end or bottom-left point\n if (!skipBottom && corners.bottomLeft) {\n ctx.moveTo(x, y + height - r);\n } else {\n ctx.moveTo(x, y + height);\n }\n // Draw to: either to top-left corner start or top-left point\n if (!skipTop && corners.topLeft) {\n ctx.lineTo(x, y + r);\n } else {\n ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n\n // Draw corners separately (only if adjacent edges are both drawn)\n // Top-left corner\n if (!skipTop && !skipLeft && corners.topLeft) {\n ctx.beginPath();\n ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);\n ctx.stroke();\n }\n\n // Top-right corner\n if (!skipTop && !skipRight && corners.topRight) {\n ctx.beginPath();\n ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2);\n ctx.stroke();\n }\n\n // Bottom-right corner\n if (!skipRight && !skipBottom && corners.bottomRight) {\n ctx.beginPath();\n ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5);\n ctx.stroke();\n }\n\n // Bottom-left corner\n if (!skipBottom && !skipLeft && corners.bottomLeft) {\n ctx.beginPath();\n ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI);\n ctx.stroke();\n }\n }\n\n ctx.restore();\n\n // Redraw points above the border so edge points are not clipped.\n // The dataset draw already happened (and may have been clipped), so this pass only\n // matters for points near the chart-area boundary.\n if (this.showPoints) {\n ctx.save();\n\n chart.data.datasets.forEach((_ds, datasetIndex) => {\n const meta = chart.getDatasetMeta(datasetIndex);\n if (!meta || meta.hidden) return;\n\n // For line charts, meta.data contains PointElements\n (meta.data ?? []).forEach((el) => {\n const point = el as unknown as {\n draw: (ctx: CanvasRenderingContext2D) => void;\n skip?: boolean;\n options?: {radius?: number};\n };\n\n if (point.skip) return;\n const r = point.options?.radius;\n if (typeof r === 'number' && r <= 0) return;\n\n point.draw(ctx as CanvasRenderingContext2D);\n });\n });\n\n ctx.restore();\n }\n },\n afterDatasetsDraw: (chart: Chart) => {\n // Restore context after datasets are drawn to remove clipping\n if (didApplyClip) {\n chart.ctx.restore();\n didApplyClip = false;\n }\n },\n };\n }\n\n /**\n * Check if any external scales are slotted\n */\n private hasExternalScales(): boolean {\n const top = this.topScaleSlot?.assignedElements() ?? [];\n const bottom = this.bottomScaleSlot?.assignedElements() ?? [];\n const left = this.leftScaleSlot?.assignedElements() ?? [];\n const right = this.rightScaleSlot?.assignedElements() ?? [];\n return (\n top.length > 0 || bottom.length > 0 || left.length > 0 || right.length > 0\n );\n }\n\n /**\n * Handle slot change events - when scales are added/removed\n */\n private handleSlotChange = () => {\n // Reset ready state when scales change\n this.externalScaleDimensions.clear();\n\n // Wait for slotted elements to report their dimensions\n this.waitForScaleDimensions();\n };\n\n /**\n * Handle scale-dimensions-changed events from slotted scales\n */\n private handleScaleDimensionsChanged = (e: Event) => {\n if (this.isUpdatingScales) return; // Prevent infinite loops\n\n const event = e as CustomEvent<ExternalScaleDimensions>;\n const {side, thickness} = event.detail;\n\n // console.debug(`[chart-line-base] Scale dimension changed:`, {\n // side,\n // thickness,\n // previousThickness: this.externalScaleDimensions.get(side),\n // isUpdatingScales: this.isUpdatingScales,\n // });\n\n // Update dimension tracking\n const previousThickness = this.externalScaleDimensions.get(side);\n if (previousThickness === thickness) return; // No change\n\n this.externalScaleDimensions.set(side, thickness);\n\n // Debounce updates to avoid layout thrashing\n if (this.dimensionUpdateTimer) {\n clearTimeout(this.dimensionUpdateTimer);\n }\n\n this.dimensionUpdateTimer = setTimeout(() => {\n this.syncScalesAndChart();\n }, 16); // One frame\n };\n\n /**\n * Wait for all slotted scales to report their dimensions\n */\n private async waitForScaleDimensions() {\n if (!this.hasExternalScales()) {\n this.requestUpdate();\n return;\n }\n\n // Collect all slotted scale elements\n const scaleElements: ExternalScaleElement[] = [];\n [\n this.topScaleSlot,\n this.bottomScaleSlot,\n this.leftScaleSlot,\n this.rightScaleSlot,\n ].forEach((slot) => {\n if (slot) {\n const assigned = slot.assignedElements() as ExternalScaleElement[];\n scaleElements.push(...assigned);\n }\n });\n\n // Ensure all scales have fixedAspectRatio matching our fixedAspectRatioScaling setting\n // and use the same scaleReferenceSize for consistent proportional scaling.\n // Each scale handles orientation-specific scaling internally based on its main axis.\n const setScaleProps = (slot: HTMLSlotElement | undefined) => {\n if (!slot) return;\n const scales = slot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n scale.fixedAspectRatio = this.fixedAspectRatioScaling;\n scale.scaleReferenceSize = this.scaleReferenceSize;\n });\n };\n\n // All scales use the same scaleReferenceSize - this avoids churn from\n // conflicting values between here and updateScaleProperties()\n setScaleProps(this.leftScaleSlot);\n setScaleProps(this.rightScaleSlot);\n setScaleProps(this.topScaleSlot);\n setScaleProps(this.bottomScaleSlot);\n\n // Wait for all scales to finish rendering\n await Promise.all(\n scaleElements.map((el) =>\n 'updateComplete' in el && typeof el.updateComplete === 'object'\n ? (el.updateComplete as Promise<unknown>)\n : Promise.resolve()\n )\n );\n\n // Scales should have dispatched their dimensions by now\n // If we don't have dimensions yet, wait a bit more\n if (this.externalScaleDimensions.size === 0 && scaleElements.length > 0) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n this.syncScalesAndChart();\n }\n\n /**\n * Synchronize scale and chart dimensions/data\n * This is the main coordination function\n */\n private syncScalesAndChart() {\n if (this.isUpdatingScales) return;\n this.isUpdatingScales = true;\n\n // console.debug(`[chart-line-base] Syncing scales and chart`, {\n // width: this.width,\n // height: this.height,\n // scaleDimensions: Array.from(this.externalScaleDimensions.entries()),\n // });\n\n try {\n // Step 1: Calculate padding from scale dimensions\n const padding = this.calculatePaddingFromScales();\n\n // console.debug(`[chart-line-base] Calculated padding:`, padding);\n\n // Step 2: Calculate effective chart area\n const effectiveWidth = this.width - padding.left - padding.right;\n const effectiveHeight = this.height - padding.top - padding.bottom;\n\n // console.debug(`[chart-line-base] Effective dimensions:`, {\n // effectiveWidth,\n // effectiveHeight,\n // });\n\n // Guard against invalid dimensions\n if (effectiveWidth <= 0 || effectiveHeight <= 0) {\n console.warn('[chart-line-base] Invalid effective dimensions', {\n width: this.width,\n height: this.height,\n padding,\n effectiveWidth,\n effectiveHeight,\n });\n return;\n }\n\n // Step 3: Update slotted scales with coordinated properties\n // this.updateScaleProperties(padding, effectiveWidth, effectiveHeight);\n this.updateScaleProperties(padding);\n\n // Step 4: Force recreation of chart with new padding\n if (this.chart) {\n this.chart.destroy();\n }\n this.createChart();\n } finally {\n this.isUpdatingScales = false;\n }\n }\n\n /**\n * Calculate chart padding from external scale dimensions.\n *\n * For sides without an external scale, falls back to `CHART_DIMENSIONS.CANVAS_PADDING`\n * (the chart's own padding to reserve room for axis tick labels). When\n * `hasLabelPadding=false` that fallback is 0 so the chart renders edge-to-edge,\n * and this same value is cascaded to slotted scales via `updateScaleProperties()`\n * — so the bar's main-axis padding (`paddingTop`/`paddingBottom` for vertical bars)\n * collapses with the chart's perpendicular padding and they stay visually aligned.\n */\n private calculatePaddingFromScales() {\n const defaultPadding = this.hasLabelPadding\n ? CHART_DIMENSIONS.CANVAS_PADDING\n : 0;\n\n const padding = {\n top: this.externalScaleDimensions.get('top') ?? defaultPadding,\n right: this.externalScaleDimensions.get('right') ?? defaultPadding,\n bottom: this.externalScaleDimensions.get('bottom') ?? defaultPadding,\n left: this.externalScaleDimensions.get('left') ?? defaultPadding,\n };\n\n // console.debug(`[chart-line-base] calculatePaddingFromScales:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // scaleReferenceSize: this.scaleReferenceSize,\n // externalScaleDimensions: Object.fromEntries(this.externalScaleDimensions),\n // defaultPadding,\n // calculatedPadding: padding,\n // });\n\n return padding;\n }\n\n /**\n * Update properties on slotted scale elements\n */\n private updateScaleProperties(\n padding: {top: number; right: number; bottom: number; left: number}\n // effectiveWidth: number,\n // effectiveHeight: number\n ) {\n // Get chart scales for min/max values\n const yMin = this.chart?.scales['y']?.min ?? 0;\n const yMax = this.chart?.scales['y']?.max ?? 100;\n const xMin = this.chart?.scales['x']?.min ?? 0;\n const xMax = this.chart?.scales['x']?.max ?? 100;\n\n // Use effective dimensions for threshold checks\n const effectiveWidth = this.getEffectiveWidth();\n const effectiveHeight = this.getEffectiveHeight();\n\n // Determine if we should show labels (above threshold).\n // When `hasLabelPadding=false` the chart reserves no room for axis labels,\n // so slotted scales must also hide their labels — otherwise their\n // `labelThickness` band stays in the reported thickness and the chart\n // gets re-padded inward (leaving whitespace on the scale's side), and any\n // visible labels would be clipped against the canvas edge.\n const showLabels =\n this.hasLabelPadding &&\n effectiveWidth >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS &&\n effectiveHeight >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Calculate viewBox padding for external scales.\n // When fixedAspectRatioScaling is true, the chart's Canvas padding is scaled by\n // scaleFactor = computedWidth / this.width. For external scales to match, their\n // viewBox padding needs to be: basePadding * scaleReferenceSize / referenceSize\n // This ensures the visual padding matches when the SVG scales to fill the container.\n const verticalViewBoxPadding = this.fixedAspectRatioScaling\n ? {\n top: Math.round(\n (padding.top * this.scaleReferenceSize) / this.height\n ),\n bottom: Math.round(\n (padding.bottom * this.scaleReferenceSize) / this.height\n ),\n }\n : {top: padding.top, bottom: padding.bottom};\n\n const horizontalViewBoxPadding = this.fixedAspectRatioScaling\n ? {\n left: Math.round(\n (padding.left * this.scaleReferenceSize) / this.width\n ),\n right: Math.round(\n (padding.right * this.scaleReferenceSize) / this.width\n ),\n }\n : {left: padding.left, right: padding.right};\n\n // console.debug(`[chart-line-base] updateScaleProperties:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // scaleReferenceSize: this.scaleReferenceSize,\n // effectiveWidth,\n // effectiveHeight,\n // scaleFactor: this.getScaleFactor(),\n // basePadding: padding,\n // verticalViewBoxPadding,\n // horizontalViewBoxPadding,\n // showLabels,\n // });\n\n // Update each slotted scale\n const updates: Array<\n [\n HTMLSlotElement | undefined,\n ExternalScaleElement,\n Partial<ExternalScaleElement>,\n ]\n > = [];\n\n // Left scale\n if (this.leftScaleSlot) {\n const scales =\n this.leftScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: yMin,\n maxValue: yMax,\n height: effectiveHeight, // Use effective height for proper sizing\n paddingTop: verticalViewBoxPadding.top,\n paddingBottom: verticalViewBoxPadding.bottom,\n paddingStart: verticalViewBoxPadding.top,\n paddingEnd: verticalViewBoxPadding.bottom,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.yStepSize !== undefined) {\n props.primaryTickmarkInterval = this.yStepSize;\n }\n updates.push([this.leftScaleSlot, scale, props]);\n });\n }\n\n // Right scale\n if (this.rightScaleSlot) {\n const scales =\n this.rightScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: yMin,\n maxValue: yMax,\n height: effectiveHeight, // Use effective height for proper sizing\n paddingTop: verticalViewBoxPadding.top,\n paddingBottom: verticalViewBoxPadding.bottom,\n paddingStart: verticalViewBoxPadding.top,\n paddingEnd: verticalViewBoxPadding.bottom,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.yStepSize !== undefined) {\n props.primaryTickmarkInterval = this.yStepSize;\n }\n updates.push([this.rightScaleSlot, scale, props]);\n });\n }\n\n // Top scale\n if (this.topScaleSlot) {\n const scales =\n this.topScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: xMin,\n maxValue: xMax,\n width: effectiveWidth, // Use effective width for proper sizing\n paddingLeft: horizontalViewBoxPadding.left,\n paddingRight: horizontalViewBoxPadding.right,\n paddingStart: horizontalViewBoxPadding.left,\n paddingEnd: horizontalViewBoxPadding.right,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.xStepSize !== undefined) {\n props.primaryTickmarkInterval = this.xStepSize;\n }\n updates.push([this.topScaleSlot, scale, props]);\n });\n }\n\n // Bottom scale\n if (this.bottomScaleSlot) {\n const scales =\n this.bottomScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: xMin,\n maxValue: xMax,\n width: effectiveWidth, // Use effective width for proper sizing\n paddingLeft: horizontalViewBoxPadding.left,\n paddingRight: horizontalViewBoxPadding.right,\n paddingStart: horizontalViewBoxPadding.left,\n paddingEnd: horizontalViewBoxPadding.right,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.xStepSize !== undefined) {\n props.primaryTickmarkInterval = this.xStepSize;\n }\n updates.push([this.bottomScaleSlot, scale, props]);\n });\n }\n\n // Apply all updates\n // console.debug(`[chart-line-base] Applying ${updates.length} scale updates`);\n updates.forEach(([_slot, scale, props]) => {\n // console.debug(` - Updating scale:`, props);\n Object.assign(scale, props);\n });\n }\n\n private hasAnyChanged(\n changed: PropertyValues,\n props: readonly (keyof ObcChartLineBase)[]\n ): boolean {\n return props.some((prop) => changed.has(prop));\n }\n\n /**\n * Apply fillMode rules to datasets. Must be called after the chart is created\n * so scales and pixel coordinates are available for gradient construction.\n *\n * NOTE: For non-threshold modes (solid, semitransparent), backgroundColor is already\n * set correctly in buildDataset(). This method now only handles threshold gradients\n * which require Chart.js scales to be available.\n */\n protected applyFillModes() {\n // Guard: Verify chart and canvas exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const chart = this.chart; // Store reference for TypeScript\n const ctx = chart.ctx as CanvasRenderingContext2D;\n\n // Guard: Verify canvas context is available\n if (!ctx) return;\n\n const fill = this.shouldApplyFill();\n const fillMode = this.getFillMode();\n\n // Only process threshold mode - other modes already have correct backgroundColor from buildDataset()\n if (fillMode !== 'threshold' || !fill) {\n return;\n }\n\n chart.data.datasets.forEach((ds, _idx) => {\n const dataset = ds as ChartDataset<'line'> & {\n fill?:\n | boolean\n | number\n | {target: number; above: string; below: string};\n yAxisID?: string;\n };\n\n // Skip if not filling\n if (dataset.fill === false || !fill) {\n return;\n }\n\n // Threshold fill: only applies to single-series, creates gradients for border\n const yScaleId = dataset.yAxisID ?? 'y';\n const yScale = chart.scales[yScaleId];\n\n if (!yScale) {\n return;\n }\n\n // Calculate threshold and gradient stop position\n const dataValues = (dataset.data as (number | {x: number; y: number})[])\n .map((d) => (typeof d === 'number' ? d : d.y))\n .filter((v) => Number.isFinite(v));\n\n // Guard: Need at least some data to calculate threshold\n if (dataValues.length === 0) {\n return;\n }\n\n const minVal = Math.min(...dataValues);\n const maxVal = Math.max(...dataValues);\n const thresholdVal = (minVal + maxVal) / 2;\n const thresholdPixel = yScale.getPixelForValue(thresholdVal);\n const range = yScale.bottom - yScale.top;\n\n // Guard: Ensure stop is a finite number between 0 and 1\n let stop = (thresholdPixel - yScale.top) / range;\n if (!Number.isFinite(stop) || range === 0) {\n stop = 0.5; // Fallback to middle if calculation fails\n } else {\n stop = Math.max(0, Math.min(1, stop));\n }\n\n // Extract threshold color variables (used for both fill and border)\n const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;\n const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;\n\n // Helper to create threshold gradient\n const createGradient = (lowAlpha: number, highAlpha: number) => {\n const low = applyAlphaToColor(this, lowRaw, lowAlpha);\n const high = applyAlphaToColor(this, highRaw, highAlpha);\n const grad = ctx.createLinearGradient(0, yScale.top, 0, yScale.bottom);\n grad.addColorStop(0, high);\n grad.addColorStop(stop, high);\n grad.addColorStop(stop, low);\n grad.addColorStop(1, low);\n return grad;\n };\n\n // Create fill gradient (35% alpha) and border gradient (80% alpha)\n const fillGradient = createGradient(0.35, 0.35);\n const borderGradient = createGradient(0.8, 0.8);\n dataset.backgroundColor = fillGradient as unknown as string;\n dataset.borderColor = borderGradient as unknown as string;\n });\n }\n\n // Update external library AFTER render\n override updated(changed: PropertyValues) {\n super.updated(changed);\n\n // Only update if watched properties changed\n if (!this.hasAnyChanged(changed, LINE_GRAPH_WATCHED_PROP_NAMES)) {\n return;\n }\n\n // `hasLabelPadding` cascades into slotted scales via `updateScaleProperties()`\n // (toggles `showLabels`, which collapses/expands the bar's label band and\n // changes its reported thickness). That path only runs through\n // `syncScalesAndChart()`, so when only `hasLabelPadding` changes we must\n // route through there — otherwise slotted scales stay stale until the\n // next slot/resize event and the chart re-pads on stale thickness.\n if (changed.has('hasLabelPadding') && this.hasExternalScales()) {\n this.syncScalesAndChart();\n return;\n }\n\n const needsRecreation = this.hasAnyChanged(\n changed,\n LINE_GRAPH_RECREATE_PROP_NAMES\n );\n\n if (needsRecreation) {\n this.chart?.destroy();\n this.createChart();\n } else {\n this.updateChart();\n }\n }\n\n override async firstUpdated() {\n // Wait for external scales to report dimensions before creating chart\n await this.waitForScaleDimensions();\n\n if (!this.hasExternalScales()) {\n // No external scales, create chart normally\n this.createChart();\n }\n // If we have external scales, chart is created in syncScalesAndChart()\n\n this.themeObserver = observeThemeChanges(() => {\n this.updateChartColors();\n this.updateBorderRadius(); // Border color may change with theme\n });\n this.setupResizeObserver();\n this.setupAspectRatioResizeObserver();\n\n // Setup border radius observer and apply initial styling\n // In instrument mode, skip observer - we use fixed border radius\n if (this.canvasEl) {\n if (!this.instrumentMode) {\n this.borderRadiusObserver = startExternalScaleBorderRadiusObserver(\n this.canvasEl,\n this.updateBorderRadius\n );\n }\n this.updateBorderRadius();\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.chart?.destroy();\n this.themeObserver?.disconnect();\n this.resizeObserver?.disconnect();\n this.aspectRatioResizeObserver?.disconnect();\n this.borderRadiusObserver?.disconnect();\n\n if (this.dimensionUpdateTimer) {\n clearTimeout(this.dimensionUpdateTimer);\n }\n }\n\n /**\n * Setup resize observer to detect height threshold crossings\n * Recreates chart when crossing MIN_HEIGHT_WITH_LABELS (192px) to show/hide labels\n * Detect when height property changes programmatically (e.g., via Storybook controls or user code)\n */\n private setupResizeObserver() {\n if (!this.canvasEl) return;\n\n this.resizeObserver = new ResizeObserver(() => {\n // Guard: Check if chart and canvas still exist (component may be disconnecting)\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const height = this.canvasEl.clientHeight;\n const isAboveThreshold =\n height >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Only recreate chart if we crossed the threshold\n if (isAboveThreshold !== this.wasAboveThreshold) {\n this.wasAboveThreshold = isAboveThreshold;\n this.chart.destroy();\n this.createChart();\n } else {\n // Height changed but didn't cross threshold - just update\n this.updateChart();\n }\n });\n\n this.resizeObserver.observe(this.canvasEl);\n\n // Initialize threshold state\n const height = this.canvasEl.clientHeight;\n this.wasAboveThreshold =\n height >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n }\n\n /**\n * Setup resize observer for fixed aspect ratio scaling.\n * Observes the wrapper element and recalculates dimensions when parent size changes.\n */\n private setupAspectRatioResizeObserver() {\n const wrapper = this.renderRoot.querySelector('.wrapper');\n if (!wrapper) return;\n\n // Initialize computed dimensions\n this.updateComputedDimensions();\n\n this.aspectRatioResizeObserver = new ResizeObserver(() => {\n if (!this.fixedAspectRatioScaling) return;\n this.updateComputedDimensions();\n });\n\n this.aspectRatioResizeObserver.observe(wrapper);\n }\n\n /**\n * Calculate actual dimensions based on parent width and aspect ratio.\n * Only used when fixedAspectRatioScaling is true.\n */\n private updateComputedDimensions() {\n if (!this.fixedAspectRatioScaling) {\n // In pixel mode, use width/height directly\n this.computedWidth = this.width;\n this.computedHeight = this.height;\n return;\n }\n\n // Get the wrapper element\n const wrapper = this.renderRoot.querySelector('.wrapper') as HTMLElement;\n if (!wrapper) return;\n\n // Get parent's available width\n const parentWidth = wrapper.clientWidth;\n if (parentWidth <= 0) return;\n\n // Calculate aspect ratio from width/height properties\n const aspectRatio = this.width / this.height;\n\n // Use parent width as actual width, calculate height from aspect ratio\n const newWidth = parentWidth;\n const newHeight = Math.round(parentWidth / aspectRatio);\n\n // console.debug(`[chart-line-base] updateComputedDimensions:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // scaleReferenceSize: this.scaleReferenceSize,\n // parentWidth,\n // aspectRatio,\n // newWidth,\n // newHeight,\n // scaleFactor: newWidth / this.width,\n // });\n\n // Only update if dimensions changed\n if (this.computedWidth !== newWidth || this.computedHeight !== newHeight) {\n this.computedWidth = newWidth;\n this.computedHeight = newHeight;\n\n // Update external scales and recreate chart with new dimensions\n // Note: syncScalesAndChart() handles chart destruction and creation internally,\n // so we only call createChart() directly when there are no external scales.\n if (this.hasExternalScales()) {\n this.syncScalesAndChart();\n } else if (this.chart) {\n // No external scales - just recreate chart\n this.chart.destroy();\n this.createChart();\n }\n }\n }\n\n /**\n * Get the effective width for chart rendering.\n * Returns computed width when fixedAspectRatioScaling is true, otherwise the width property.\n */\n protected getEffectiveWidth(): number {\n return this.fixedAspectRatioScaling ? this.computedWidth : this.width;\n }\n\n /**\n * Get the effective height for chart rendering.\n * Returns computed height when fixedAspectRatioScaling is true, otherwise the height property.\n */\n protected getEffectiveHeight(): number {\n return this.fixedAspectRatioScaling ? this.computedHeight : this.height;\n }\n\n /**\n * Get the scale factor for proportional scaling when fixedAspectRatioScaling is true.\n * Returns 1.0 when not in fixed aspect ratio mode.\n * The scale factor is based on computed width vs reference width (the width property).\n */\n protected getScaleFactor(): number {\n if (!this.fixedAspectRatioScaling) {\n return 1.0;\n }\n // Scale factor is based on computed width vs the reference width (width property)\n // The width property defines the \"design\" or \"reference\" size\n return this.computedWidth / this.width;\n }\n\n /**\n * Build a complete dataset configuration with all styling properties.\n * Handles both new datasets (from values array) and existing datasets (normalization).\n *\n * @param data - Either numeric values array or existing dataset to normalize\n * @param index - Dataset index for color cycling\n * @param chartColors - Color palette array\n * @param totalCount - Total number of datasets (used for stacked divider logic)\n * @returns Fully configured Chart.js dataset\n */\n protected buildDataset(\n data:\n | number[]\n | ChartDataset<\n 'line',\n (number | {x: string | number | Date; y: number})[]\n >,\n index: number,\n chartColors: string[],\n totalCount = 1\n ): ChartDataset<\n 'line',\n number[] | (number | {x: string | number | Date; y: number})[]\n > {\n const currentColor = chartColors[index % chartColors.length];\n\n // Check if input is existing dataset (has 'data' property) or raw values array\n const existingDataset =\n 'data' in (data as object)\n ? (data as ChartDataset<\n 'line',\n (number | {x: string | number | Date; y: number})[]\n >)\n : null;\n const values = existingDataset ? null : (data as number[]);\n\n const borderColor = existingDataset?.borderColor ?? currentColor;\n const fillFlag = existingDataset?.fill ?? this.shouldApplyFill();\n const tension = this.lineMode === 'smooth' ? this.DEFAULT_TENSION : 0;\n\n // For stacked mode, add divider lines between datasets (except the topmost one)\n const isStacked = this.shouldStack() && this.getFillMode() !== 'threshold';\n const needsDivider = isStacked && index < totalCount - 1;\n\n // Calculate backgroundColor immediately instead of deferring to applyFillModes()\n // This prevents flicker when chart is recreated multiple times during resize\n let backgroundColor: string = 'transparent';\n const fillMode = this.getFillMode();\n\n if (fillFlag && fillMode) {\n const nextColor = chartColors[(index + 1) % chartColors.length];\n\n if (fillMode === 'solid') {\n backgroundColor = String(borderColor);\n } else if (fillMode === 'semitransparent') {\n backgroundColor = applyAlphaToColor(this, nextColor, 0.5);\n } else if (fillMode === 'threshold') {\n // For threshold, we'll still need gradients from applyFillModes\n // but set a reasonable default to avoid transparent flash\n backgroundColor = applyAlphaToColor(this, nextColor, 0.5);\n }\n }\n\n const result = {\n ...(existingDataset || {}),\n data: existingDataset?.data ?? values!,\n borderColor,\n backgroundColor,\n borderWidth: existingDataset?.borderWidth ?? 2,\n showLine: existingDataset?.showLine ?? true,\n tension: existingDataset?.tension ?? tension,\n pointRadius:\n existingDataset?.pointRadius ??\n (this.showPoints ? this.POINT_RADIUS : 0),\n pointBackgroundColor: existingDataset?.pointBackgroundColor ?? '#fff',\n pointBorderColor: existingDataset?.pointBorderColor ?? borderColor,\n pointBorderWidth: existingDataset?.pointBorderWidth ?? 2,\n stepped: existingDataset?.stepped ?? this.lineMode === 'stepped',\n // Use 'start' to fill from chart bottom, not 'origin' (y=0)\n fill: fillFlag ? 'start' : false,\n spanGaps: existingDataset?.spanGaps ?? true,\n // Add segment styling for stacked divider lines\n ...(needsDivider && {\n segment: {\n borderColor: getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.stackedDividerColorVar\n ),\n borderWidth: 1,\n },\n }),\n };\n\n return result as ChartDataset<\n 'line',\n number[] | (number | {x: string | number | Date; y: number})[]\n >;\n }\n\n /**\n * Create threshold mode datasets: invisible baseline + main dataset with above/below fills\n */\n protected createThresholdDatasets(\n values: number[],\n chartColors: string[]\n ): ChartDataset<'line', number[]>[] {\n const numericValues = values\n .map((v) => Number(v))\n .filter((n) => Number.isFinite(n));\n const minV = numericValues.length ? Math.min(...numericValues) : 0;\n const maxV = numericValues.length ? Math.max(...numericValues) : 100;\n const threshold = (minV + maxV) / 2;\n const baselineData = numericValues.map(() => threshold);\n\n const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;\n const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;\n const highFill = applyAlphaToColor(this, highRaw, 0.35);\n const lowFill = applyAlphaToColor(this, lowRaw, 0.35);\n\n const baselineDataset: ChartDataset<'line', number[]> = {\n label: 'threshold-baseline',\n data: baselineData,\n borderColor: 'transparent',\n backgroundColor: 'transparent',\n borderWidth: 0,\n pointRadius: 0,\n showLine: false,\n fill: false,\n spanGaps: true,\n };\n\n const main = this.buildDataset(values, 0, chartColors) as ChartDataset<\n 'line',\n number[]\n >;\n (main as unknown as Record<string, unknown>).fill = {\n target: 0,\n above: highFill,\n below: lowFill,\n };\n // Border gradient will be set by applyFillModes after chart scales are ready\n main.borderWidth = 2;\n\n return [baselineDataset, main];\n }\n\n /**\n * Prepare normalized datasets for multi-series charts\n */\n protected prepareMultiSeriesDatasets() {\n const defaultPalette =\n this.priority === Priority.enhanced\n ? CHART_SECTOR_ENHANCED_COLORS\n : CHART_SECTOR_DEFAULT_COLORS;\n const chartColors = getChartColorsOrDefault(\n this,\n this.colors,\n defaultPalette\n );\n\n const totalCount = this.datasets!.length;\n return this.datasets!.map((ds, i) =>\n this.buildDataset(ds, i, chartColors, totalCount)\n );\n }\n\n /**\n * Prepare datasets for single-series charts\n * Handles both regular and threshold fill modes\n */\n protected prepareSingleSeriesDatasets() {\n const values = this.data.map((d) => d.value);\n const labels = this.data.map((d) => d.label);\n const defaultPalette =\n this.priority === Priority.enhanced\n ? CHART_SECTOR_ENHANCED_COLORS\n : CHART_SECTOR_DEFAULT_COLORS;\n const chartColors = getChartColorsOrDefault(\n this,\n this.colors,\n defaultPalette\n );\n const fill = this.shouldApplyFill();\n const fillMode = this.getFillMode();\n\n const datasets =\n fill && fillMode === 'threshold'\n ? this.createThresholdDatasets(values, chartColors)\n : [this.buildDataset(values, 0, chartColors)];\n\n return {datasets, labels};\n }\n\n /**\n * Get Chart.js options with dynamic sizing and padding\n */\n protected getChartOptions(): ChartOptions<'line'> {\n // Use effective dimensions (computed when fixedAspectRatioScaling=true)\n const effectiveWidth = this.getEffectiveWidth();\n const effectiveHeight = this.getEffectiveHeight();\n\n // Determine if chart is too small for labels\n const isTooSmall =\n effectiveWidth < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS ||\n effectiveHeight < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Get scale factor for proportional scaling in fixed aspect ratio mode\n const scaleFactor = this.getScaleFactor();\n\n // Calculate padding for the chart.\n // External scales report their actual visual (scaled) thickness when in fixedAspectRatio mode,\n // so we use those values directly without additional scaling.\n // For sides without external scales, we apply the chart's scaleFactor to default padding.\n let padding: {top: number; right: number; bottom: number; left: number};\n\n // When hasLabelPadding=false the chart never reserves space for axis tick\n // labels on sides without an external scale (renders edge-to-edge there).\n // External-scale sides still receive their reported visual thickness so\n // slotted scales/bars remain fully visible.\n const defaultPaddingScaled = !this.hasLabelPadding\n ? 0\n : this.fixedAspectRatioScaling\n ? Math.round(CHART_DIMENSIONS.CANVAS_PADDING * scaleFactor)\n : CHART_DIMENSIONS.CANVAS_PADDING;\n\n if (isTooSmall && this.hasLabelPadding) {\n padding = {top: 0, right: 0, bottom: 0, left: 0};\n } else if (this.hasExternalScales()) {\n // External scales report their visual dimensions (already scaled when fixedAspectRatio=true)\n const scalePadding = this.calculatePaddingFromScales();\n padding = {\n top: this.externalScaleDimensions.has('top')\n ? scalePadding.top\n : defaultPaddingScaled,\n right: this.externalScaleDimensions.has('right')\n ? scalePadding.right\n : defaultPaddingScaled,\n bottom: this.externalScaleDimensions.has('bottom')\n ? scalePadding.bottom\n : defaultPaddingScaled,\n left: this.externalScaleDimensions.has('left')\n ? scalePadding.left\n : defaultPaddingScaled,\n };\n } else {\n // No external scales - apply scaleFactor to all default padding\n padding = {\n top: defaultPaddingScaled,\n right: defaultPaddingScaled,\n bottom: defaultPaddingScaled,\n left: defaultPaddingScaled,\n };\n }\n\n // console.debug(`[chart-line-base] getChartOptions:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // effectiveWidth,\n // effectiveHeight,\n // scaleFactor,\n // scaleReferenceSize: this.scaleReferenceSize,\n // padding,\n // externalScaleDimensions: Object.fromEntries(this.externalScaleDimensions),\n // hasExternalScales: this.hasExternalScales(),\n // });\n\n // Set CSS variables for wrapper and canvas sizing\n if (this.fixedAspectRatioScaling) {\n // In responsive mode, use 100% width, computed height\n this.style.setProperty('--chart-width', '100%');\n this.style.setProperty('--chart-height', `${effectiveHeight}px`);\n } else {\n // In pixel mode, use width/height directly\n this.style.setProperty('--chart-width', `${this.width}px`);\n this.style.setProperty('--chart-height', `${this.height}px`);\n }\n\n // Compute reference timestamp for time-based x-axis\n const refTs = this.computeTimeReference();\n\n // Force showTickMarks=false when external scales are present\n const effectiveShowTickMarks = this.hasExternalScales()\n ? false\n : this.showTickMarks;\n\n return {\n responsive: true,\n maintainAspectRatio: false, // Use explicit width/height instead\n layout: {\n padding,\n },\n plugins: {\n legend: {\n display: false,\n labels: {\n generateLabels: () => [], // Prevent Chart.js from generating labels internally\n },\n onClick: () => {}, // Disable legend click handler\n },\n tooltip: {\n ...getChartTooltipOptions(this),\n enabled: !isTooSmall,\n callbacks: {\n title: () => '',\n label: (context) => {\n const label = context.label ?? '';\n const value =\n typeof context.parsed === 'object' && context.parsed !== null\n ? (context.parsed as {y: number}).y\n : (context.parsed as number);\n const numericValue = formatNumericValue(value, 1, false, 0);\n const unit = this.unit ? `${this.unit}` : '';\n return `${label} ${numericValue}${unit}`;\n },\n },\n },\n },\n animation: false,\n scales: this.buildScalesConfig(refTs, isTooSmall, effectiveShowTickMarks),\n };\n }\n\n /**\n * Compute reference timestamp for time axis formatting.\n * Returns earliest timestamp for 'date' mode, latest for 'minutes' mode.\n */\n private computeTimeReference(): number | undefined {\n const timestamps: number[] = [];\n\n // Collect timestamps from datasets\n if (this.datasets?.length) {\n this.datasets.forEach((ds) => {\n if (!ds.data) return;\n (ds.data as (number | {x: unknown; y: number})[]).forEach((pt) => {\n if (pt && typeof pt === 'object' && 'x' in pt) {\n const xVal = (pt as {x: unknown}).x;\n const ts =\n typeof xVal === 'string'\n ? new Date(String(xVal)).getTime()\n : Number(xVal);\n if (Number.isFinite(ts)) timestamps.push(ts);\n }\n });\n });\n }\n\n // Collect timestamps from labels if no dataset timestamps found\n if (!timestamps.length && this.labels?.length) {\n this.labels.forEach((l) => {\n if (typeof l === 'string') {\n const ts = new Date(l).getTime();\n if (Number.isFinite(ts)) timestamps.push(ts);\n }\n });\n }\n\n return timestamps.length\n ? this.timeDisplay === 'minutes'\n ? Math.max(...timestamps)\n : Math.min(...timestamps)\n : undefined;\n }\n\n /**\n * Build Chart.js scale configuration with theme-aware styling.\n * Applies CSS variables for grid colors, tick colors, and label typography.\n *\n * @param minX - Reference timestamp for time-based x-axis (used for 'minutes' display)\n * @param isTooSmall - Whether chart is below 192px threshold (hides ticks when true)\n * @param showTickMarks - Whether to show tick marks (overridden to false when external scales present)\n * @returns Configured scales object for Chart.js options\n */\n protected buildScalesConfig(\n minX?: number,\n isTooSmall = false,\n showTickMarks = true\n ) {\n // Build scales typed for ChartOptions<'line'>\n // If we don't have a date adapter available, fall back to numeric linear scale\n // by converting date strings to timestamps before chart creation. We still\n // render formatted tick labels for readability.\n // Read CSS variables for styling\n const gridColor = getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.gridColorVar\n );\n const tickColor = getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.tickColorVar\n );\n const fontFamily = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontFamily\n );\n const fontSize = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontSizeVar\n );\n const fontWeight = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontWeightVar\n );\n const fontColor = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontColorVar\n );\n\n // Extract common values used for both x and y axes.\n // When hasLabelPadding=false the chart renders edge-to-edge, so labels are\n // force-hidden to prevent clipping.\n const showLabels = showTickMarks && !isTooSmall && this.hasLabelPadding;\n const showTicks = showTickMarks && !isTooSmall && this.hasLabelPadding;\n const fontConfig = {family: fontFamily, size: fontSize, weight: fontWeight};\n\n const x = {\n type: this.xAxisType === 'time' ? 'linear' : 'category',\n offset: false, // Always edge-to-edge (no padding on x-axis)\n grace: 0, // No extra margin\n bounds: 'data', // Use data bounds for edge-to-edge rendering\n grid: {\n display: this.showGrid && this.showGridX,\n color: gridColor,\n offset: false,\n drawTicks: showTicks,\n },\n ticks: {\n display: showLabels,\n color: fontColor,\n font: fontConfig,\n maxRotation: 0, // Keep labels horizontal (no rotation)\n minRotation: 0, // Keep labels horizontal (no rotation)\n maxTicksLimit: this.xTicksLimit,\n stepSize: this.xStepSize,\n callback: (value: unknown) => {\n if (this.xAxisType !== 'time') return String(value);\n const n = Number(value);\n if (!Number.isFinite(n)) return String(value);\n if (\n this.timeDisplay === 'minutes' &&\n minX !== undefined &&\n Number.isFinite(minX)\n ) {\n const minutes = Math.round((n - minX) / 60000);\n return `${minutes}min`;\n }\n return new Date(n).toLocaleDateString();\n },\n },\n border: {\n display: showLabels,\n color: tickColor,\n },\n } as unknown;\n\n // Build y-axis scales configuration\n const yAxesConfig = this.yAxes?.length\n ? this.yAxes.map((axis, i) => ({\n id: axis.id ?? `y${i}`,\n position: axis.position ?? ('left' as 'left' | 'right'),\n min: axis.min,\n max: axis.max,\n gridDisplay: axis.grid ?? (this.showGrid && this.showGridY),\n }))\n : [\n {\n id: 'y',\n position: this.yAxisPosition,\n min: undefined,\n max: undefined,\n gridDisplay: this.showGrid && this.showGridY,\n },\n ];\n\n const scalesRecord: Record<string, unknown> = {x};\n\n yAxesConfig.forEach(({id, position, min, max, gridDisplay}) => {\n scalesRecord[id] = {\n type: 'linear',\n display: true,\n position,\n stacked: this.shouldStack() && this.getFillMode() !== 'threshold',\n grace: isTooSmall ? 0 : undefined,\n bounds: isTooSmall ? 'data' : 'ticks',\n grid: {\n display: gridDisplay,\n color: gridColor,\n drawTicks: showTicks,\n },\n ticks: {\n display: showLabels,\n color: fontColor,\n font: fontConfig,\n maxTicksLimit: this.yTicksLimit,\n stepSize: this.yStepSize,\n },\n border: {\n display: showLabels,\n color: tickColor,\n },\n min,\n max,\n };\n });\n\n return scalesRecord as ChartOptions<'line'>['scales'];\n }\n\n /**\n * Prepare chart data and labels for both single and multi-series modes\n */\n private prepareChartDataAndLabels() {\n if (this.datasets?.length) {\n return {\n datasets: this.prepareMultiSeriesDatasets(),\n labels: (this.labels ?? []) as (string | number)[],\n };\n }\n return this.prepareSingleSeriesDatasets();\n }\n\n private createChart() {\n // Guard: Verify canvas exists and is connected to DOM\n if (!this.canvasEl || !this.canvasEl.isConnected) return;\n\n const ctx = this.canvasEl.getContext('2d');\n if (!ctx) return;\n\n // Destroy existing chart instance to prevent canvas reuse errors\n if (this.chart) {\n this.chart.destroy();\n this.chart = undefined;\n }\n\n const {datasets, labels} = this.prepareChartDataAndLabels();\n\n this.chart = new Chart(ctx, {\n type: 'line',\n data: {labels, datasets},\n options: this.getChartOptions(),\n plugins: this.borderRadiusPosition ? [this.createBorderPlugin()] : [],\n } as ChartConfiguration<'line'>);\n\n // Defer legend update to next tick to ensure Chart.js metadata is initialized\n requestAnimationFrame(() => this.updateLegend());\n this.applyFillModes();\n }\n\n private updateChart() {\n // Guard: Verify chart and canvas still exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const {datasets, labels} = this.prepareChartDataAndLabels();\n\n this.chart.data.labels = labels;\n this.chart.data.datasets = datasets as unknown as ChartDataset<'line'>[];\n\n // Update options (chart.options is always defined after chart creation)\n Object.assign(this.chart.options, this.getChartOptions());\n\n this.applyFillModes();\n this.chart.update();\n\n // Update legend after chart update completes to ensure metadata is ready\n requestAnimationFrame(() => this.updateLegend());\n }\n\n /**\n * Update only chart colors without recalculating layout\n * Used by theme observer for efficient theme changes\n */\n private updateChartColors() {\n // Guard: Verify chart and canvas still exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n // Re-apply fill modes which will update gradients for threshold mode\n this.applyFillModes();\n\n // Update without animation for instant theme change\n this.chart.update('none');\n\n // Defer legend update to next frame to ensure metadata is ready\n requestAnimationFrame(() => this.updateLegend());\n }\n\n /**\n * Update the legend HTML content\n */\n private updateLegend() {\n // Guard: Check if legend should be shown and chart is ready\n if (!this.legend || !this.legendDiv || !this.chart) return;\n\n // Guard: Check if chart has datasets\n if (!this.chart.data.datasets || this.chart.data.datasets.length === 0) {\n // console.debug('[chart-line-base] updateLegend: skipped - no datasets available');\n this.legendDiv.innerHTML = '';\n return;\n }\n\n try {\n const legendItems = this.chart.data.datasets\n .map((ds, i) => {\n const meta = this.chart!.getDatasetMeta(i);\n\n // Guard: Check if metadata and controller are available\n if (!meta || !meta.controller) {\n // console.debug(`[chart-line-base] updateLegend: dataset ${i} metadata not yet initialized`);\n return null;\n }\n\n const style = meta.controller.getStyle(0, false);\n const dataset = ds as ChartDataset<\n 'line',\n (number | {x: number; y: number})[]\n >;\n\n return {\n fillStyle: (dataset.borderColor ??\n style.borderColor ??\n '') as string,\n label: (dataset.label as string) || `Series ${i + 1}`,\n value: '',\n unit: '',\n };\n })\n .filter((item) => item !== null);\n\n // Only update legend if we have valid items\n if (legendItems.length > 0) {\n const legendHTML = generateLegendHTML(legendItems);\n this.legendDiv.innerHTML = legendHTML;\n }\n } catch (error) {\n console.debug(\n '[chart-line-base] updateLegend: error generating legend HTML',\n error\n );\n // Silent failure - don't throw, just skip legend update this time\n }\n }\n\n override render() {\n return html`\n <div class=\"wrapper\">\n <div class=\"canvas-and-slots-container\">\n <slot\n name=\"top-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"bottom-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"left-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"right-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <canvas></canvas>\n </div>\n\n ${this.legend ? html`<div class=\"legend\"></div>` : ''}\n </div>\n `;\n }\n\n static override styles = [\n unsafeCSS(componentStyle),\n unsafeCSS(chartCommonStyle),\n unsafeCSS(chartLegendStyle),\n unsafeCSS(chartDebugStyle),\n ];\n}\n"],"names":["XAxisType","YAxisPosition","LineMode","TimeDisplay","r","height"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-line-base.js","sources":["../../../src/building-blocks/chart-line/chart-line-base.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, query} from 'lit/decorators.js';\nimport componentStyle from './chart-line-base.css?inline';\nimport chartCommonStyle from '../../charthelpers/chart-common.css?inline';\nimport chartDebugStyle from '../../charthelpers/chart-debug.css?inline';\nimport chartLegendStyle from '../../charthelpers/chart-legend.css?inline';\nimport {\n Chart,\n LineController,\n LineElement,\n PointElement,\n ArcElement,\n Tooltip,\n CategoryScale,\n LinearScale,\n TimeScale,\n Filler,\n} from 'chart.js';\nimport type {ChartOptions, ChartDataset, ChartConfiguration} from 'chart.js';\nimport {\n InstrumentState,\n FrameStyle,\n BorderRadiusPosition,\n Priority,\n} from '../../navigation-instruments/types.js';\nimport {\n CHART_SECTOR_DEFAULT_COLORS,\n CHART_SECTOR_ENHANCED_COLORS,\n RECTANGULAR_CHART_DIMENSIONS,\n LINE_GRAPH_LABEL_CONFIG,\n LINE_GRAPH_GRID_CONFIG,\n CHART_DIMENSIONS,\n CHART_AREA_BACKGROUND_COLOR_VAR,\n getCssVariableValue,\n getChartColorsOrDefault,\n observeThemeChanges,\n formatNumericValue,\n getChartTooltipOptions,\n generateLegendHTML,\n applyAlphaToColor,\n normalizeXValue,\n formatXValue,\n XValueMode,\n} from '../../charthelpers/index.js';\nimport type {ChartXValue} from '../../charthelpers/x-value.js';\nimport {\n EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR,\n readExternalScaleBorderRadiusPx,\n startExternalScaleBorderRadiusObserver,\n ScaleType,\n} from '../external-scale/external-scale.js';\n\n// Register Chart.js components used by the line graph (scales, elements, plugins)\nChart.register(\n LineController,\n LineElement,\n PointElement,\n ArcElement,\n CategoryScale,\n LinearScale,\n TimeScale,\n Filler,\n Tooltip\n);\n\n/**\n * Dimension information reported by external scale components.\n * Dispatched via 'scale-dimensions-changed' event from slotted scale elements.\n */\nexport interface ExternalScaleDimensions {\n /** Which side this scale is positioned on */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Natural thickness in pixels (width for vertical, height for horizontal) */\n thickness: number;\n}\n\n/**\n * Type guard to check if an element is an external scale component\n */\ninterface ExternalScaleElement extends HTMLElement {\n minValue?: number;\n maxValue?: number;\n height?: number;\n width?: number;\n paddingTop?: number;\n paddingBottom?: number;\n paddingLeft?: number;\n paddingRight?: number;\n paddingStart?: number;\n paddingEnd?: number;\n primaryTickmarkInterval?: number;\n showLabels?: boolean;\n fixedAspectRatio?: boolean;\n scaleReferenceSize?: number;\n state?: InstrumentState;\n priority?: Priority;\n frameStyle?: FrameStyle;\n borderRadiusPosition?: BorderRadiusPosition;\n}\n\nexport type {ChartXValue, TemporalLike} from '../../charthelpers/x-value.js';\n\nexport enum XAxisType {\n category = 'category',\n time = 'time',\n number = 'number',\n}\n\nexport enum YAxisPosition {\n left = 'left',\n right = 'right',\n}\n\nexport enum LineMode {\n smooth = 'smooth',\n straight = 'straight',\n stepped = 'stepped',\n}\n\nexport enum TimeDisplay {\n minutes = 'minutes',\n date = 'date',\n}\n\nexport type ChartLinePoint = number | {x: ChartXValue; y: number};\n\nexport type ChartLineDataItem = {\n /** Category label. Used when `xAxisType='category'` (the default). */\n label?: string;\n /**\n * X-coordinate for `xAxisType='time'` (epoch ms, ISO string, Date, or\n * Temporal object) or `xAxisType='number'` (plain number). When absent,\n * `label` is parsed as a fallback.\n */\n x?: ChartXValue;\n value: number;\n};\n\nexport type ChartLineYAxisConfig = {\n id?: string;\n position?: 'left' | 'right';\n min?: number;\n max?: number;\n grid?: boolean;\n};\n\nconst LINE_GRAPH_WATCHED_PROP_NAMES = [\n 'data',\n 'datasets',\n 'labels',\n 'colors',\n 'xAxisType',\n 'yAxisPosition',\n 'yAxes',\n 'showGrid',\n 'showGridX',\n 'showGridY',\n 'showTickMarks',\n 'showPoints',\n 'lineMode',\n 'unit', // Used in tooltip display\n 'timeDisplay',\n 'xTicksLimit',\n 'xStepSize',\n 'yTicksLimit',\n 'yStepSize',\n 'priority', // Triggers color palette change\n 'borderRadiusPosition', // Triggers border styling update\n 'borderRadiusPositionExternalScales', // Triggers external scale border styling update\n // legend only affects HTML; do not use it to drive chart updates\n 'width',\n 'height',\n 'fixedAspectRatioScaling', // Triggers responsive mode change\n 'hasLabelPadding', // Toggles edge-to-edge rendering and label visibility\n] as const;\n\nconst LINE_GRAPH_RECREATE_PROP_NAMES = [\n 'showDebugOverlay',\n 'width',\n 'height',\n 'fixedAspectRatioScaling',\n] as const;\n\n/**\n * Abstract base class for line and area chart components built on Chart.js.\n *\n * ## Features\n * - **Single or multi-series**: Use `data` for simple single-series or `datasets` for multi-series charts\n * - **Category, time and number axes**: `category` (labels, evenly spaced), `time` (epoch ms,\n * ISO strings, `Date` or Temporal objects — positioned proportionally, so uneven intervals\n * render unevenly) and `number` (plain numeric x-values on a linear scale)\n * - **Line styles**: Choose `smooth` (curved), `straight`, or `stepped` line rendering\n * - **Fill modes**: Area fills with `semitransparent`, `solid`, or `threshold` (red/blue above/below midpoint)\n * - **Stacked charts**: Enable `stacked` for multi-series datasets to stack values on y-axis\n * - **Flexible axes**: Single y-axis via `yAxisPosition` or multi-axis via `yAxes` for complex charts\n * - **Theme-aware**: Automatically updates colors on theme changes using CSS variables\n * - **Responsive sizing**: Fixed height with 1.5:1 aspect ratio (e.g., 320px height → 480px width)\n * - **Grid & ticks**: Toggle grid lines (`showGrid`, `showGridX`, `showGridY`) and tick marks (`showTickMarks`)\n * - **Legend support**: Optional HTML legend showing series labels with `legend` property\n * - **External axis support**: via slots\n * - **Color priority**: Set `priority` to `Priority.enhanced` to use the blue/enhanced\n * color palette instead of the default gray/regular palette (default: `Priority.regular`)\n *\n * ## Size Behavior\n * - Above 192px: Shows labels, tick marks, and grid lines with standard padding\n * - Below 192px: Hides labels/ticks and uses edge-to-edge rendering for compact display\n *\n * ## Examples\n *\n * Basic single-series with category axis:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.data = [\n * {label: 'Jan', value: 10},\n * {label: 'Feb', value: 14},\n * {label: 'Mar', value: 12}\n * ];\n * chart.unit = 'kW';\n * chart.height = 256;\n * </script>\n * ```\n *\n * Multi-series with time axis and legend:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.xAxisType = 'time';\n * chart.timeDisplay = 'date';\n * chart.legend = true;\n * chart.datasets = [\n * {label: 'Temperature', data: [{x: '2025-01-01', y: 20}, {x: '2025-01-02', y: 22}]},\n * {label: 'Humidity', data: [{x: '2025-01-01', y: 65}, {x: '2025-01-02', y: 68}]}\n * ];\n * </script>\n * ```\n *\n * Single-series with time axis (uneven intervals position proportionally;\n * x accepts epoch ms, ISO strings, Date or Temporal objects):\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.xAxisType = 'time';\n * chart.timeDisplay = 'minutes';\n * chart.data = [\n * {x: '2026-07-06T10:00:00Z', value: 10},\n * {x: new Date('2026-07-06T10:03:00Z'), value: 14},\n * {x: Temporal.Instant.from('2026-07-06T10:15:00Z'), value: 12}\n * ];\n * </script>\n * ```\n *\n * Single-series with numeric x-axis:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.xAxisType = 'number';\n * chart.data = [\n * {x: 0, value: 2},\n * {x: 2.5, value: 3},\n * {x: 10, value: 6}\n * ];\n * </script>\n * ```\n *\n * Stacked area chart with solid fill:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.datasets = [\n * {label: 'Series A', data: [2, 3, 4, 3, 5]},\n * {label: 'Series B', data: [1, 2, 3, 2, 4]},\n * {label: 'Series C', data: [3, 2, 1, 2, 3]}\n * ];\n * chart.fill = true;\n * chart.fillMode = 'solid';\n * chart.stacked = true;\n * chart.legend = true;\n * </script>\n * ```\n *\n * Threshold fill (single-series only):\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.data = [{label: '1', value: 20}, {label: '2', value: 45}, {label: '3', value: 35}];\n * chart.fill = true;\n * chart.fillMode = 'threshold';\n * </script>\n * ```\n *\n * Multi-axis chart with right-side y-axis:\n * ```html\n * <obc-line-graph></obc-line-graph>\n * <script>\n * const chart = document.querySelector('obc-line-graph');\n * chart.yAxes = [\n * {id: 'y-temp', position: 'left', min: 0, max: 100},\n * {id: 'y-pressure', position: 'right', min: 0, max: 10}\n * ];\n * chart.datasets = [\n * {label: 'Temperature', data: [20, 25, 30], yAxisID: 'y-temp'},\n * {label: 'Pressure', data: [2, 3, 2.5], yAxisID: 'y-pressure'}\n * ];\n * </script>\n * ```\n *\n * @property {Array<{label?: string, x?: number|string|Date|TemporalLike, value: number}>} data - Single-series data array. In `category` mode each item needs `label`; in `time`/`number` mode each item needs `x` (epoch ms, ISO string, Date, or Temporal object — `label` is parsed as a fallback). Used when `datasets` is not provided. Points are drawn in array order (no sorting); Temporal Plain* values are interpreted in the system time zone.\n * @property {ChartDataset<'line', (number | {x: number|string|Date|TemporalLike; y: number})[]>[]} datasets - Multi-series Chart.js datasets. Takes precedence over `data`. Each dataset can have `label`, `data` (numeric array or `{x, y}` points), and visual properties like `borderColor`, `backgroundColor`, `fill`, etc. In `time`/`number` mode point x-values are normalized like single-series `x`.\n * @property {(string|number)[]} labels - Explicit labels for category x-axis. If omitted, labels are derived from `data` property or dataset x-values.\n * @property {string[]} colors - Custom color palette (CSS variable names or color strings). Falls back to theme default colors if not provided.\n * @property {'category'|'time'|'number'} xAxisType - X-axis mode. `'category'` for labeled, evenly spaced data points; `'time'` for time-based data positioned proportionally (numbers are always epoch ms — `xStepSize`/`xTicksLimit` operate in ms); `'number'` for plain numeric x-values. Default: `'category'`.\n * @property {'minutes'|'date'} timeDisplay - Time axis label format when `xAxisType='time'`. `'date'` shows a locale date, `'minutes'` shows minutes relative to the latest data point. Default: `'date'`.\n * @property {'left'|'right'} yAxisPosition - Single y-axis position. Use this for simple charts with one y-axis. For multiple y-axes, use `yAxes` property instead. Default: `'left'`.\n * @property {Array<{id?: string; position?: 'left'|'right'; min?: number; max?: number; grid?: boolean}>} yAxes - Multiple y-axis definitions for complex charts. Each axis can specify `id` (referenced by dataset `yAxisID`), `position`, `min`/`max` range, and `grid` visibility.\n * @property {boolean} showGrid - Show vertical grid lines (x-axis). When combined with `showGridX` and `showGridY`, controls full grid visibility. Default: `false`.\n * @property {boolean} showGridX - Show vertical grid lines (x-axis). Set to `false` to hide only vertical lines while keeping horizontal lines. Default: `false`.\n * @property {boolean} showGridY - Show horizontal grid lines (y-axis). Set to `false` to hide only horizontal lines while keeping vertical lines. Default: `false`.\n * @property {boolean} showTickMarks - Show axis tick marks and labels. Automatically hidden below 192px height threshold. Default: `false`.\n * @property {boolean} showPoints - Show point markers on data points. Default: `false`.\n * @property {boolean} fill - Enable area fill under/between lines. Use with `fillMode` to control fill style. Default: `false`.\n * @property {'semitransparent'|'solid'|'threshold'} fillMode - Fill rendering mode. `'semitransparent'` uses 50% alpha, `'solid'` uses opaque fill, `'threshold'` (single-series only) fills above/below midpoint with red/blue gradient. Default: `'semitransparent'`.\n * @property {'smooth'|'straight'|'stepped'} lineMode - Line drawing style. `'smooth'` applies bezier curve tension, `'straight'` draws straight lines, `'stepped'` creates step-like lines. Default: `'smooth'`.\n * @property {boolean} stacked - Stack multi-series datasets vertically on y-axis. Ignored for single-series and threshold fill mode. Default: `false`.\n * @property {string} unit - Unit label displayed in tooltips (e.g., 'kW', 'kg', '%'). Default: empty string.\n * @property {number} xTicksLimit - Maximum number of x-axis ticks/grid lines. Useful for matching external axes. Optional.\n * @property {number} xStepSize - Force specific interval between x-axis ticks (e.g., 1, 2, 5). Useful for matching external axes. Optional.\n * @property {number} yTicksLimit - Maximum number of y-axis ticks/grid lines. Useful for matching external axes. Optional.\n * @property {number} yStepSize - Force specific interval between y-axis ticks (e.g., 2, 5, 10). Useful for matching external axes. Optional.\n * @property {boolean} legend - Show HTML legend below chart with series labels and colors. Default: `false`.\n * @property {number} height - Chart height in pixels. Determines chart size with 1.5:1 aspect ratio (width = height × 1.5). Default: `320`.\n * @property {boolean} showDebugOverlay - Development mode: show visual debug overlay with dimension guides. Shows blue border around canvas (axis area) and red border around chart grid (data area). Default: `false`.\n *\n * @ignore This is an abstract base class. Use concrete implementations like ObcLineGraph or ObcAreaGraph instead.\n * @experimental\n */\nexport class ObcChartLineBase extends LitElement {\n /**\n * Simple single-series data. `{label, value}` items for the category axis;\n * `{x, value}` items for time/number axes (x: epoch ms, ISO string, Date,\n * or Temporal object). Points are drawn in array order (no sorting).\n */\n @property({type: Array, attribute: false})\n data: ChartLineDataItem[] = [];\n\n /** Chart.js-style datasets for multi-series use. If provided, takes precedence over `data`. */\n @property({type: Array, attribute: false})\n datasets?: ChartDataset<'line', ChartLinePoint[]>[] = undefined;\n\n /** Optional explicit labels for the x-axis (category mode). If omitted labels are derived from `data` */\n @property({type: Array, attribute: false})\n labels?: (string | number)[] = undefined;\n\n /** Custom color palette (CSS variable names or color strings). */\n @property({type: Array, attribute: false})\n colors: string[] = [];\n\n /** Show HTML legend below chart with series labels and colors. */\n @property({type: Boolean, reflect: true})\n legend = false;\n\n /** Development mode: show visual debug overlay with dimension guides. */\n @property({type: Boolean, reflect: true})\n showDebugOverlay = false;\n\n /** Width of the chart in pixels. Default: 480. */\n @property({type: Number, reflect: true})\n width = 480;\n\n /** Height of the chart in pixels. Default: 320. */\n @property({type: Number, reflect: true})\n height = 320;\n\n /**\n * Enable fixed aspect ratio scaling mode.\n * When true, width/height properties define the aspect ratio (not actual pixels).\n * The component fills 100% of parent width and calculates height from aspect ratio.\n * When false (default), width/height are used as actual pixel dimensions.\n */\n @property({type: Boolean, reflect: true})\n fixedAspectRatioScaling = false;\n\n /**\n * Reference size for external scales when using fixedAspectRatioScaling.\n * This value is passed down to external scales to determine their 1:1 Figma design size.\n * At this reference size, scales render at native size; above/below they scale proportionally.\n * Default: 384 (matches Figma design baseline).\n */\n @property({type: Number})\n scaleReferenceSize = 384;\n\n /**\n * X-axis mode: 'category' for labeled, evenly spaced data points; 'time'\n * for time-based data positioned proportionally; 'number' for plain\n * numeric x-values.\n */\n @property({type: String})\n xAxisType: XAxisType = XAxisType.category;\n\n /** Single y-axis position ('left' or 'right'). For multiple y-axes, use yAxes instead. */\n @property({type: String})\n yAxisPosition: YAxisPosition = YAxisPosition.left;\n\n /** Multiple y-axis definitions for complex multi-axis charts. */\n @property({type: Array, attribute: false})\n yAxes?: ChartLineYAxisConfig[] = undefined;\n\n /** Show grid lines. */\n @property({type: Boolean})\n showGrid = false;\n\n /**\n * Show vertical grid lines (x-axis). Default: false.\n * @availableWhen showGrid==true\n */\n @property({type: Boolean})\n showGridX = false;\n\n /**\n * Show horizontal grid lines (y-axis). Default: false.\n * @availableWhen showGrid==true\n */\n @property({type: Boolean})\n showGridY = false;\n\n /** Show axis tick marks and labels. */\n @property({type: Boolean})\n showTickMarks = false;\n\n /**\n * Reserve canvas padding for axis tick labels on sides without an external scale.\n *\n * When `true` (default), the chart leaves room for tick labels and renders them\n * (subject to `showTickMarks` and the 192px auto-compact threshold).\n *\n * When `false`, the chart renders edge-to-edge on sides without a slotted external\n * scale AND axis tick labels are force-hidden so they cannot be clipped. This also\n * suppresses the automatic edge-to-edge switch that normally happens below the\n * 192px threshold, eliminating the visible padding \"jump\" when crossing it.\n *\n * Useful when embedding the chart inside another component that owns framing\n * and never wants to show axis labels (e.g. `obc-automation-tank`).\n *\n * Defaults to `true` to preserve existing behavior. Declared with `attribute: false`\n * because a `true`-default boolean cannot work as an HTML boolean attribute.\n */\n @property({type: Boolean, attribute: false})\n hasLabelPadding = true;\n\n /** @internal - True when the x-axis positions points by numeric value. */\n protected get isNumericXAxis(): boolean {\n return (\n this.xAxisType === XAxisType.time || this.xAxisType === XAxisType.number\n );\n }\n\n /** @internal - Normalization mode for the current x-axis type. */\n protected get xValueMode(): XValueMode {\n return this.xAxisType === XAxisType.number\n ? XValueMode.number\n : XValueMode.time;\n }\n\n /** @internal - Last data/datasets reference already warned about. */\n private lastWarnedXSource?: unknown;\n\n /** @internal - Warn once per data assignment about unparseable x-values. */\n private warnOnInvalidX(xValues: number[], sourceRef: unknown) {\n const invalid = xValues.filter((x) => !Number.isFinite(x)).length;\n if (invalid === 0 || this.lastWarnedXSource === sourceRef) return;\n this.lastWarnedXSource = sourceRef;\n console.warn(\n `[obc-chart] ${invalid} x value(s) could not be parsed for xAxisType='${this.xAxisType}'; the points render as gaps.`\n );\n }\n\n // Internal default tension used when `lineMode` is 'smooth'. Not exposed as a property.\n private readonly DEFAULT_TENSION = 0.4;\n\n // Internal default point radius when points are shown.\n private readonly POINT_RADIUS = 3;\n\n /** Show point markers on data points. Default: false. */\n @property({type: Boolean})\n showPoints = false;\n\n /** Line drawing style: 'smooth' (curved), 'straight', or 'stepped'. */\n @property({type: String})\n lineMode: LineMode = LineMode.smooth;\n\n /** Unit label displayed in tooltips (e.g., 'kW', 'kg', '%'). */\n @property({type: String})\n unit = '';\n\n /**\n * Time axis label format: 'date' (full date/time) or 'minutes' (relative).\n * @availableWhen xAxisType==time\n */\n @property({type: String})\n timeDisplay: TimeDisplay = TimeDisplay.date;\n\n /** Max number of x-axis ticks/grid lines. Useful for matching external axes. */\n @property({type: Number})\n xTicksLimit?: number = undefined;\n\n /** Force x-axis tick interval. Useful for matching external axes. */\n @property({type: Number})\n xStepSize?: number = undefined;\n\n /** Max number of y-axis ticks/grid lines. Useful for matching external axes. */\n @property({type: Number})\n yTicksLimit?: number = undefined;\n\n /** Force y-axis tick interval. Useful for matching external axes. */\n @property({type: Number})\n yStepSize?: number = undefined;\n\n /** Instrument state affecting colors of external scales. */\n @property({type: String})\n state: InstrumentState = InstrumentState.active;\n\n /** Color priority: enhanced uses blue palette instead of default gray. */\n @property({type: String})\n priority: Priority = Priority.regular;\n\n /** Frame style for chart and external scales. */\n @property({type: String})\n frameStyle: FrameStyle = FrameStyle.regular;\n\n /** Border radius position for the chart's own border. */\n @property({type: String})\n borderRadiusPosition?: BorderRadiusPosition = undefined;\n\n /** Border radius position for external scales based on layout. */\n @property({type: String})\n borderRadiusPositionExternalScales?: BorderRadiusPosition = undefined;\n\n /**\n * When true, the chart is used inside an instrument (e.g., gauge-trend).\n * In this mode, only label font size responds to .obc-component-size-* CSS classes.\n * Border radius uses the explicit `borderRadius` property value (or defaults to 8px),\n * rather than reading from CSS variables.\n * @default false\n */\n @property({type: Boolean})\n instrumentMode = false;\n\n /**\n * Explicit border radius value in pixels.\n * When instrumentMode=true, this value is used directly (defaults to 8px).\n * When instrumentMode=false, this is ignored and border radius is read from CSS variable.\n * @availableWhen instrumentMode==true\n */\n @property({type: Number})\n borderRadius?: number = undefined;\n\n /** @internal */\n @query('canvas') private canvasEl?: HTMLCanvasElement;\n\n /** @internal */\n @query('.legend') private legendDiv?: HTMLDivElement;\n\n /** @internal - Slot elements for external scales */\n @query('slot[name=\"top-scale\"]') private topScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"bottom-scale\"]') private bottomScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"left-scale\"]') private leftScaleSlot?: HTMLSlotElement;\n @query('slot[name=\"right-scale\"]') private rightScaleSlot?: HTMLSlotElement;\n\n /** @internal */\n private chart?: Chart;\n\n /** @internal */\n private themeObserver?: MutationObserver;\n\n /** @internal - ResizeObserver for tracking height threshold crossings (e.g. MIN_HEIGHT_WITH_LABELS = 192px) */\n private resizeObserver?: ResizeObserver;\n\n /** @internal - Track previous state to detect threshold crossing */\n private wasAboveThreshold = false;\n\n /** @internal - Track external scale dimensions */\n private externalScaleDimensions: Map<string, number> = new Map();\n\n /** @internal - Debounce timer for dimension updates */\n private dimensionUpdateTimer?: ReturnType<typeof setTimeout>;\n\n /** @internal - Flag to prevent infinite update loops */\n private isUpdatingScales = false;\n\n /** @internal - Border radius observer for theme/size changes */\n private borderRadiusObserver?: MutationObserver;\n\n /** @internal - Current computed border radius in pixels */\n private currentBorderRadiusPx = 8;\n\n /** @internal - ResizeObserver for aspect ratio scaling */\n private aspectRatioResizeObserver?: ResizeObserver;\n\n /** @internal - Computed actual width when using fixed aspect ratio scaling */\n private computedWidth = 480;\n\n /** @internal - Computed actual height when using fixed aspect ratio scaling */\n private computedHeight = 320;\n\n /**\n * Should fill be applied to this chart?\n * Line graph returns false, area graph returns true.\n * Must be implemented in subclass.\n */\n protected shouldApplyFill(): boolean {\n throw new Error('shouldApplyFill() must be implemented in subclass');\n }\n\n /**\n * Get fill mode for area rendering.\n * Line graph returns undefined, area graph returns 'semitransparent' | 'solid' | 'threshold'.\n * Must be implemented in subclass.\n */\n protected getFillMode(): string | undefined {\n throw new Error('getFillMode() must be implemented in subclass');\n }\n\n /**\n * Should multi-series datasets be stacked?\n * Line graph returns false, area graph returns stacked property value.\n * Must be implemented in subclass.\n */\n protected shouldStack(): boolean {\n throw new Error('shouldStack() must be implemented in subclass');\n }\n\n /**\n * Compute which corners should be rounded based on borderRadiusPosition and\n * which external scales are present.\n *\n * Logic:\n * - Opposite scales (left+right OR top+bottom) → no rounding (middleChild behavior)\n * - Perpendicular scales (e.g., right+bottom):\n * - innerFirstChild → round corner adjacent to both scales\n * - outerLastChild → round free corner opposite to scales\n * - Single-side scales:\n * - When external scale is on RIGHT, chart is on LEFT\n * - innerFirstChild → round LEFT corners (top-left + bottom-left)\n * - outerLastChild → round RIGHT corners (top-right + bottom-right)\n * - When external scale is on LEFT, chart is on RIGHT (opposite)\n * - When external scale is on TOP, chart is on BOTTOM\n * - innerFirstChild → round BOTTOM corners (bottom-left + bottom-right)\n * - outerLastChild → round TOP corners (top-left + top-right)\n * - When external scale is on BOTTOM, chart is on TOP (opposite)\n * - middleChild → no rounding\n */\n\n /**\n * Check if a slotted scale element is actually visible (renders content).\n * For bar-vertical/bar-horizontal elements, checks hasBar and hasScale properties.\n */\n private hasVisibleScale(side: 'left' | 'right' | 'top' | 'bottom'): boolean {\n const slotMap = {\n left: this.leftScaleSlot,\n right: this.rightScaleSlot,\n top: this.topScaleSlot,\n bottom: this.bottomScaleSlot,\n };\n\n const slot = slotMap[side];\n const elements = slot?.assignedElements() ?? [];\n\n return elements.some((el: Element) => {\n const barEl = el as HTMLElement & {\n hasBar?: boolean;\n hasScale?: boolean;\n };\n\n // If it has hasBar and hasScale properties, check if at least one is true\n if ('hasBar' in barEl && 'hasScale' in barEl) {\n return barEl.hasBar === true || barEl.hasScale === true;\n }\n\n // Otherwise assume it's visible\n return true;\n });\n }\n\n private computeRoundedCorners(): {\n topLeft: boolean;\n topRight: boolean;\n bottomLeft: boolean;\n bottomRight: boolean;\n } {\n if (!this.borderRadiusPosition) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n if (this.borderRadiusPosition === BorderRadiusPosition.middleChild) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n // middleRoundedChild → round ALL corners (standalone instrument mode)\n if (this.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild) {\n return {\n topLeft: true,\n topRight: true,\n bottomLeft: true,\n bottomRight: true,\n };\n }\n\n // Determine which external scales are VISIBLE (not just present in slots)\n const hasLeft = this.hasVisibleScale('left');\n const hasRight = this.hasVisibleScale('right');\n const hasTop = this.hasVisibleScale('top');\n const hasBottom = this.hasVisibleScale('bottom');\n\n // If scales exist on opposite sides, behave like middleChild (no rounding)\n if ((hasLeft && hasRight) || (hasTop && hasBottom)) {\n return {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n }\n\n const result = {\n topLeft: false,\n topRight: false,\n bottomLeft: false,\n bottomRight: false,\n };\n\n const isInner =\n this.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;\n const isOuter =\n this.borderRadiusPosition === BorderRadiusPosition.outerLastChild;\n\n // Handle perpendicular scale configurations (e.g., right + bottom)\n if (hasRight && hasBottom) {\n // Chart is in top-left position\n if (isInner) {\n result.bottomRight = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.topLeft = true; // Free corner\n }\n } else if (hasRight && hasTop) {\n // Chart is in bottom-left position\n if (isInner) {\n result.topRight = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.bottomLeft = true; // Free corner\n }\n } else if (hasLeft && hasBottom) {\n // Chart is in top-right position\n if (isInner) {\n result.bottomLeft = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.topRight = true; // Free corner\n }\n } else if (hasLeft && hasTop) {\n // Chart is in bottom-right position\n if (isInner) {\n result.topLeft = true; // Corner adjacent to both scales\n } else if (isOuter) {\n result.bottomRight = true; // Free corner\n }\n }\n // Handle single-side horizontal scales (left OR right, but not both)\n else if (hasRight && !hasLeft) {\n // Chart is on the left side of composition\n if (isInner) {\n result.topLeft = true;\n result.bottomLeft = true;\n } else if (isOuter) {\n result.topRight = true;\n result.bottomRight = true;\n }\n } else if (hasLeft && !hasRight) {\n // Chart is on the right side of composition\n if (isInner) {\n result.topRight = true;\n result.bottomRight = true;\n } else if (isOuter) {\n result.topLeft = true;\n result.bottomLeft = true;\n }\n }\n // Handle single-side vertical scales (top OR bottom, but not both)\n else if (hasBottom && !hasTop) {\n // Chart is on the top of composition\n if (isInner) {\n result.topLeft = true;\n result.topRight = true;\n } else if (isOuter) {\n result.bottomLeft = true;\n result.bottomRight = true;\n }\n } else if (hasTop && !hasBottom) {\n // Chart is on the bottom of composition\n if (isInner) {\n result.bottomLeft = true;\n result.bottomRight = true;\n } else if (isOuter) {\n result.topLeft = true;\n result.topRight = true;\n }\n }\n\n return result;\n }\n\n /**\n * Read current border radius from CSS variable and update state.\n * The chart will be recreated when needed through the normal update mechanism.\n * In instrument mode, uses explicit borderRadius value instead of CSS variable.\n */\n private updateBorderRadius = () => {\n if (!this.canvasEl) return;\n\n // In instrument mode, use explicit value or default (8px)\n // Skip CSS variable reading entirely\n let next: number;\n if (this.instrumentMode) {\n next = this.borderRadius ?? 8;\n } else {\n next = readExternalScaleBorderRadiusPx(\n this.canvasEl,\n ScaleType.regular,\n EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR\n );\n }\n\n if (this.currentBorderRadiusPx !== next) {\n this.currentBorderRadiusPx = next;\n // Trigger chart recreation to update border plugin\n if (this.chart) {\n this.chart.destroy();\n this.createChart();\n }\n }\n };\n\n /**\n * Create a Chart.js plugin that draws a border around the chart area with selective corner rounding\n * and clips content to that border.\n */\n private createBorderPlugin() {\n const corners = this.computeRoundedCorners();\n const radius = this.currentBorderRadiusPx;\n\n let didApplyClip = false;\n\n const buildRoundedRectPath = (\n ctx: CanvasRenderingContext2D,\n rect: {x: number; y: number; width: number; height: number},\n cornerRadius: number\n ) => {\n const {x, y, width, height} = rect;\n\n // Guard: Avoid invalid paths\n if (width <= 0 || height <= 0) return;\n\n const r = Math.max(\n 0,\n Math.min(cornerRadius, Math.min(width, height) / 2)\n );\n\n // Start at top-left corner (accounting for radius)\n ctx.moveTo(x + (corners.topLeft ? r : 0), y);\n\n // Top edge\n ctx.lineTo(x + width - (corners.topRight ? r : 0), y);\n\n // Top-right corner\n if (corners.topRight) {\n ctx.arcTo(x + width, y, x + width, y + r, r);\n }\n\n // Right edge\n ctx.lineTo(x + width, y + height - (corners.bottomRight ? r : 0));\n\n // Bottom-right corner\n if (corners.bottomRight) {\n ctx.arcTo(x + width, y + height, x + width - r, y + height, r);\n }\n\n // Bottom edge\n ctx.lineTo(x + (corners.bottomLeft ? r : 0), y + height);\n\n // Bottom-left corner\n if (corners.bottomLeft) {\n ctx.arcTo(x, y + height, x, y + height - r, r);\n }\n\n // Left edge\n ctx.lineTo(x, y + (corners.topLeft ? r : 0));\n\n // Top-left corner\n if (corners.topLeft) {\n ctx.arcTo(x, y, x + r, y, r);\n }\n };\n\n return {\n id: 'chartAreaBorder',\n beforeDatasetsDraw: (chart: Chart) => {\n const ctx = chart.ctx;\n const chartArea = chart.chartArea;\n\n if (!chartArea) return;\n\n // Draw/clip behavior should match CSS border-box:\n // - The border stroke must be fully INSIDE the chartArea.\n // - The stroke's OUTER edge should align to the chartArea boundary.\n // Reserve space by clipping content inside the border thickness.\n const borderWidthPx = 1;\n const clipInset = borderWidthPx;\n\n const {top, right, bottom, left} = chartArea;\n const rect = {\n x: left + clipInset,\n y: top + clipInset,\n width: right - left - clipInset * 2,\n height: bottom - top - clipInset * 2,\n };\n\n const clipRadius = Math.max(0, radius - clipInset);\n\n ctx.save();\n didApplyClip = true;\n\n // Create clipping path with selective corner rounding\n ctx.beginPath();\n\n buildRoundedRectPath(ctx as CanvasRenderingContext2D, rect, clipRadius);\n ctx.closePath();\n\n // Fill chart area background when in instrument mode\n if (this.instrumentMode) {\n const backgroundColor = getCssVariableValue(\n this,\n CHART_AREA_BACKGROUND_COLOR_VAR\n );\n ctx.fillStyle = backgroundColor;\n ctx.fill();\n }\n\n // Apply clipping\n ctx.clip();\n },\n afterDraw: (chart: Chart) => {\n const ctx = chart.ctx;\n const chartArea = chart.chartArea;\n\n if (!chartArea) return;\n\n const borderWidthPx = 1;\n const strokeInset = borderWidthPx / 2;\n\n const {top, right, bottom, left} = chartArea;\n const rect = {\n x: left + strokeInset,\n y: top + strokeInset,\n width: right - left - strokeInset * 2,\n height: bottom - top - strokeInset * 2,\n };\n\n const strokeRadius = Math.max(0, radius - strokeInset);\n\n // Check which sides have visible scales (edges to skip)\n const skipTop = this.hasVisibleScale('top');\n const skipRight = this.hasVisibleScale('right');\n const skipBottom = this.hasVisibleScale('bottom');\n const skipLeft = this.hasVisibleScale('left');\n\n // Get border color from CSS variable\n const borderColor = getCssVariableValue(\n this,\n '--instrument-frame-tertiary-color'\n );\n\n ctx.save();\n ctx.strokeStyle = borderColor;\n ctx.lineWidth = borderWidthPx;\n\n const {x, y, width, height} = rect;\n const r = Math.max(\n 0,\n Math.min(strokeRadius, Math.min(width, height) / 2)\n );\n\n // Draw border segments, skipping edges that have visible external scales\n if (!skipTop && !skipRight && !skipBottom && !skipLeft) {\n // No scales - draw full border path\n ctx.beginPath();\n buildRoundedRectPath(\n ctx as CanvasRenderingContext2D,\n rect,\n strokeRadius\n );\n ctx.closePath();\n ctx.stroke();\n } else {\n // Draw border in segments, skipping edges with visible scales\n // Each segment is drawn as a continuous path for proper corner rendering\n\n // Top edge (skip if top scale present)\n if (!skipTop) {\n ctx.beginPath();\n // Start: either from top-left corner end or top-left corner point\n if (!skipLeft && corners.topLeft) {\n ctx.moveTo(x + r, y);\n } else {\n ctx.moveTo(x, y);\n }\n // Draw to: either to top-right corner start or top-right corner point\n if (!skipRight && corners.topRight) {\n ctx.lineTo(x + width - r, y);\n } else {\n ctx.lineTo(x + width, y);\n }\n ctx.stroke();\n }\n\n // Right edge (skip if right scale present)\n if (!skipRight) {\n ctx.beginPath();\n // Start: either from top-right corner end or top-right point\n if (!skipTop && corners.topRight) {\n ctx.moveTo(x + width, y + r);\n } else {\n ctx.moveTo(x + width, y);\n }\n // Draw to: either to bottom-right corner start or bottom-right point\n if (!skipBottom && corners.bottomRight) {\n ctx.lineTo(x + width, y + height - r);\n } else {\n ctx.lineTo(x + width, y + height);\n }\n ctx.stroke();\n }\n\n // Bottom edge (skip if bottom scale present)\n if (!skipBottom) {\n ctx.beginPath();\n // Start: either from bottom-right corner end or bottom-right point\n if (!skipRight && corners.bottomRight) {\n ctx.moveTo(x + width - r, y + height);\n } else {\n ctx.moveTo(x + width, y + height);\n }\n // Draw to: either to bottom-left corner start or bottom-left point\n if (!skipLeft && corners.bottomLeft) {\n ctx.lineTo(x + r, y + height);\n } else {\n ctx.lineTo(x, y + height);\n }\n ctx.stroke();\n }\n\n // Left edge (skip if left scale present)\n if (!skipLeft) {\n ctx.beginPath();\n // Start: either from bottom-left corner end or bottom-left point\n if (!skipBottom && corners.bottomLeft) {\n ctx.moveTo(x, y + height - r);\n } else {\n ctx.moveTo(x, y + height);\n }\n // Draw to: either to top-left corner start or top-left point\n if (!skipTop && corners.topLeft) {\n ctx.lineTo(x, y + r);\n } else {\n ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n\n // Draw corners separately (only if adjacent edges are both drawn)\n // Top-left corner\n if (!skipTop && !skipLeft && corners.topLeft) {\n ctx.beginPath();\n ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);\n ctx.stroke();\n }\n\n // Top-right corner\n if (!skipTop && !skipRight && corners.topRight) {\n ctx.beginPath();\n ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2);\n ctx.stroke();\n }\n\n // Bottom-right corner\n if (!skipRight && !skipBottom && corners.bottomRight) {\n ctx.beginPath();\n ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5);\n ctx.stroke();\n }\n\n // Bottom-left corner\n if (!skipBottom && !skipLeft && corners.bottomLeft) {\n ctx.beginPath();\n ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI);\n ctx.stroke();\n }\n }\n\n ctx.restore();\n\n // Redraw points above the border so edge points are not clipped.\n // The dataset draw already happened (and may have been clipped), so this pass only\n // matters for points near the chart-area boundary.\n if (this.showPoints) {\n ctx.save();\n\n chart.data.datasets.forEach((_ds, datasetIndex) => {\n const meta = chart.getDatasetMeta(datasetIndex);\n if (!meta || meta.hidden) return;\n\n // For line charts, meta.data contains PointElements\n (meta.data ?? []).forEach((el) => {\n const point = el as unknown as {\n draw: (ctx: CanvasRenderingContext2D) => void;\n skip?: boolean;\n options?: {radius?: number};\n };\n\n if (point.skip) return;\n const r = point.options?.radius;\n if (typeof r === 'number' && r <= 0) return;\n\n point.draw(ctx as CanvasRenderingContext2D);\n });\n });\n\n ctx.restore();\n }\n },\n afterDatasetsDraw: (chart: Chart) => {\n // Restore context after datasets are drawn to remove clipping\n if (didApplyClip) {\n chart.ctx.restore();\n didApplyClip = false;\n }\n },\n };\n }\n\n /**\n * Check if any external scales are slotted\n */\n private hasExternalScales(): boolean {\n const top = this.topScaleSlot?.assignedElements() ?? [];\n const bottom = this.bottomScaleSlot?.assignedElements() ?? [];\n const left = this.leftScaleSlot?.assignedElements() ?? [];\n const right = this.rightScaleSlot?.assignedElements() ?? [];\n return (\n top.length > 0 || bottom.length > 0 || left.length > 0 || right.length > 0\n );\n }\n\n /**\n * Handle slot change events - when scales are added/removed\n */\n private handleSlotChange = () => {\n // Reset ready state when scales change\n this.externalScaleDimensions.clear();\n\n // Wait for slotted elements to report their dimensions\n this.waitForScaleDimensions();\n };\n\n /**\n * Handle scale-dimensions-changed events from slotted scales\n */\n private handleScaleDimensionsChanged = (e: Event) => {\n if (this.isUpdatingScales) return; // Prevent infinite loops\n\n const event = e as CustomEvent<ExternalScaleDimensions>;\n const {side, thickness} = event.detail;\n\n // console.debug(`[chart-line-base] Scale dimension changed:`, {\n // side,\n // thickness,\n // previousThickness: this.externalScaleDimensions.get(side),\n // isUpdatingScales: this.isUpdatingScales,\n // });\n\n // Update dimension tracking\n const previousThickness = this.externalScaleDimensions.get(side);\n if (previousThickness === thickness) return; // No change\n\n this.externalScaleDimensions.set(side, thickness);\n\n // Debounce updates to avoid layout thrashing\n if (this.dimensionUpdateTimer) {\n clearTimeout(this.dimensionUpdateTimer);\n }\n\n this.dimensionUpdateTimer = setTimeout(() => {\n this.syncScalesAndChart();\n }, 16); // One frame\n };\n\n /**\n * Wait for all slotted scales to report their dimensions\n */\n private async waitForScaleDimensions() {\n if (!this.hasExternalScales()) {\n this.requestUpdate();\n return;\n }\n\n // Collect all slotted scale elements\n const scaleElements: ExternalScaleElement[] = [];\n [\n this.topScaleSlot,\n this.bottomScaleSlot,\n this.leftScaleSlot,\n this.rightScaleSlot,\n ].forEach((slot) => {\n if (slot) {\n const assigned = slot.assignedElements() as ExternalScaleElement[];\n scaleElements.push(...assigned);\n }\n });\n\n // Ensure all scales have fixedAspectRatio matching our fixedAspectRatioScaling setting\n // and use the same scaleReferenceSize for consistent proportional scaling.\n // Each scale handles orientation-specific scaling internally based on its main axis.\n const setScaleProps = (slot: HTMLSlotElement | undefined) => {\n if (!slot) return;\n const scales = slot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n scale.fixedAspectRatio = this.fixedAspectRatioScaling;\n scale.scaleReferenceSize = this.scaleReferenceSize;\n });\n };\n\n // All scales use the same scaleReferenceSize - this avoids churn from\n // conflicting values between here and updateScaleProperties()\n setScaleProps(this.leftScaleSlot);\n setScaleProps(this.rightScaleSlot);\n setScaleProps(this.topScaleSlot);\n setScaleProps(this.bottomScaleSlot);\n\n // Wait for all scales to finish rendering\n await Promise.all(\n scaleElements.map((el) =>\n 'updateComplete' in el && typeof el.updateComplete === 'object'\n ? (el.updateComplete as Promise<unknown>)\n : Promise.resolve()\n )\n );\n\n // Scales should have dispatched their dimensions by now\n // If we don't have dimensions yet, wait a bit more\n if (this.externalScaleDimensions.size === 0 && scaleElements.length > 0) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n this.syncScalesAndChart();\n }\n\n /**\n * Synchronize scale and chart dimensions/data\n * This is the main coordination function\n */\n private syncScalesAndChart() {\n if (this.isUpdatingScales) return;\n this.isUpdatingScales = true;\n\n // console.debug(`[chart-line-base] Syncing scales and chart`, {\n // width: this.width,\n // height: this.height,\n // scaleDimensions: Array.from(this.externalScaleDimensions.entries()),\n // });\n\n try {\n // Step 1: Calculate padding from scale dimensions\n const padding = this.calculatePaddingFromScales();\n\n // console.debug(`[chart-line-base] Calculated padding:`, padding);\n\n // Step 2: Calculate effective chart area\n const effectiveWidth = this.width - padding.left - padding.right;\n const effectiveHeight = this.height - padding.top - padding.bottom;\n\n // console.debug(`[chart-line-base] Effective dimensions:`, {\n // effectiveWidth,\n // effectiveHeight,\n // });\n\n // Guard against invalid dimensions\n if (effectiveWidth <= 0 || effectiveHeight <= 0) {\n console.warn('[chart-line-base] Invalid effective dimensions', {\n width: this.width,\n height: this.height,\n padding,\n effectiveWidth,\n effectiveHeight,\n });\n return;\n }\n\n // Step 3: Update slotted scales with coordinated properties\n // this.updateScaleProperties(padding, effectiveWidth, effectiveHeight);\n this.updateScaleProperties(padding);\n\n // Step 4: Force recreation of chart with new padding\n if (this.chart) {\n this.chart.destroy();\n }\n this.createChart();\n } finally {\n this.isUpdatingScales = false;\n }\n }\n\n /**\n * Calculate chart padding from external scale dimensions.\n *\n * For sides without an external scale, falls back to `CHART_DIMENSIONS.CANVAS_PADDING`\n * (the chart's own padding to reserve room for axis tick labels). When\n * `hasLabelPadding=false` that fallback is 0 so the chart renders edge-to-edge,\n * and this same value is cascaded to slotted scales via `updateScaleProperties()`\n * — so the bar's main-axis padding (`paddingTop`/`paddingBottom` for vertical bars)\n * collapses with the chart's perpendicular padding and they stay visually aligned.\n */\n private calculatePaddingFromScales() {\n const defaultPadding = this.hasLabelPadding\n ? CHART_DIMENSIONS.CANVAS_PADDING\n : 0;\n\n const padding = {\n top: this.externalScaleDimensions.get('top') ?? defaultPadding,\n right: this.externalScaleDimensions.get('right') ?? defaultPadding,\n bottom: this.externalScaleDimensions.get('bottom') ?? defaultPadding,\n left: this.externalScaleDimensions.get('left') ?? defaultPadding,\n };\n\n // console.debug(`[chart-line-base] calculatePaddingFromScales:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // scaleReferenceSize: this.scaleReferenceSize,\n // externalScaleDimensions: Object.fromEntries(this.externalScaleDimensions),\n // defaultPadding,\n // calculatedPadding: padding,\n // });\n\n return padding;\n }\n\n /**\n * Update properties on slotted scale elements\n */\n private updateScaleProperties(\n padding: {top: number; right: number; bottom: number; left: number}\n // effectiveWidth: number,\n // effectiveHeight: number\n ) {\n // Get chart scales for min/max values\n const yMin = this.chart?.scales['y']?.min ?? 0;\n const yMax = this.chart?.scales['y']?.max ?? 100;\n const xMin = this.chart?.scales['x']?.min ?? 0;\n const xMax = this.chart?.scales['x']?.max ?? 100;\n\n // Use effective dimensions for threshold checks\n const effectiveWidth = this.getEffectiveWidth();\n const effectiveHeight = this.getEffectiveHeight();\n\n // Determine if we should show labels (above threshold).\n // When `hasLabelPadding=false` the chart reserves no room for axis labels,\n // so slotted scales must also hide their labels — otherwise their\n // `labelThickness` band stays in the reported thickness and the chart\n // gets re-padded inward (leaving whitespace on the scale's side), and any\n // visible labels would be clipped against the canvas edge.\n const showLabels =\n this.hasLabelPadding &&\n effectiveWidth >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS &&\n effectiveHeight >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Calculate viewBox padding for external scales.\n // When fixedAspectRatioScaling is true, the chart's Canvas padding is scaled by\n // scaleFactor = computedWidth / this.width. For external scales to match, their\n // viewBox padding needs to be: basePadding * scaleReferenceSize / referenceSize\n // This ensures the visual padding matches when the SVG scales to fill the container.\n const verticalViewBoxPadding = this.fixedAspectRatioScaling\n ? {\n top: Math.round(\n (padding.top * this.scaleReferenceSize) / this.height\n ),\n bottom: Math.round(\n (padding.bottom * this.scaleReferenceSize) / this.height\n ),\n }\n : {top: padding.top, bottom: padding.bottom};\n\n const horizontalViewBoxPadding = this.fixedAspectRatioScaling\n ? {\n left: Math.round(\n (padding.left * this.scaleReferenceSize) / this.width\n ),\n right: Math.round(\n (padding.right * this.scaleReferenceSize) / this.width\n ),\n }\n : {left: padding.left, right: padding.right};\n\n // console.debug(`[chart-line-base] updateScaleProperties:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // scaleReferenceSize: this.scaleReferenceSize,\n // effectiveWidth,\n // effectiveHeight,\n // scaleFactor: this.getScaleFactor(),\n // basePadding: padding,\n // verticalViewBoxPadding,\n // horizontalViewBoxPadding,\n // showLabels,\n // });\n\n // Update each slotted scale\n const updates: Array<\n [\n HTMLSlotElement | undefined,\n ExternalScaleElement,\n Partial<ExternalScaleElement>,\n ]\n > = [];\n\n // Left scale\n if (this.leftScaleSlot) {\n const scales =\n this.leftScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: yMin,\n maxValue: yMax,\n height: effectiveHeight, // Use effective height for proper sizing\n paddingTop: verticalViewBoxPadding.top,\n paddingBottom: verticalViewBoxPadding.bottom,\n paddingStart: verticalViewBoxPadding.top,\n paddingEnd: verticalViewBoxPadding.bottom,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.yStepSize !== undefined) {\n props.primaryTickmarkInterval = this.yStepSize;\n }\n updates.push([this.leftScaleSlot, scale, props]);\n });\n }\n\n // Right scale\n if (this.rightScaleSlot) {\n const scales =\n this.rightScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: yMin,\n maxValue: yMax,\n height: effectiveHeight, // Use effective height for proper sizing\n paddingTop: verticalViewBoxPadding.top,\n paddingBottom: verticalViewBoxPadding.bottom,\n paddingStart: verticalViewBoxPadding.top,\n paddingEnd: verticalViewBoxPadding.bottom,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.yStepSize !== undefined) {\n props.primaryTickmarkInterval = this.yStepSize;\n }\n updates.push([this.rightScaleSlot, scale, props]);\n });\n }\n\n // Top scale\n if (this.topScaleSlot) {\n const scales =\n this.topScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: xMin,\n maxValue: xMax,\n width: effectiveWidth, // Use effective width for proper sizing\n paddingLeft: horizontalViewBoxPadding.left,\n paddingRight: horizontalViewBoxPadding.right,\n paddingStart: horizontalViewBoxPadding.left,\n paddingEnd: horizontalViewBoxPadding.right,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.xStepSize !== undefined) {\n props.primaryTickmarkInterval = this.xStepSize;\n }\n updates.push([this.topScaleSlot, scale, props]);\n });\n }\n\n // Bottom scale\n if (this.bottomScaleSlot) {\n const scales =\n this.bottomScaleSlot.assignedElements() as ExternalScaleElement[];\n scales.forEach((scale) => {\n const props: Partial<ExternalScaleElement> = {\n minValue: xMin,\n maxValue: xMax,\n width: effectiveWidth, // Use effective width for proper sizing\n paddingLeft: horizontalViewBoxPadding.left,\n paddingRight: horizontalViewBoxPadding.right,\n paddingStart: horizontalViewBoxPadding.left,\n paddingEnd: horizontalViewBoxPadding.right,\n showLabels,\n fixedAspectRatio: this.fixedAspectRatioScaling,\n // Use chart's scaleReferenceSize property for proportional scaling\n scaleReferenceSize: this.scaleReferenceSize,\n state: this.state,\n priority: this.priority,\n frameStyle: this.frameStyle,\n borderRadiusPosition: this.borderRadiusPositionExternalScales,\n };\n // Only override interval if explicitly set\n if (this.xStepSize !== undefined) {\n props.primaryTickmarkInterval = this.xStepSize;\n }\n updates.push([this.bottomScaleSlot, scale, props]);\n });\n }\n\n // Apply all updates\n // console.debug(`[chart-line-base] Applying ${updates.length} scale updates`);\n updates.forEach(([_slot, scale, props]) => {\n // console.debug(` - Updating scale:`, props);\n Object.assign(scale, props);\n });\n }\n\n private hasAnyChanged(\n changed: PropertyValues,\n props: readonly (keyof ObcChartLineBase)[]\n ): boolean {\n return props.some((prop) => changed.has(prop));\n }\n\n /**\n * Apply fillMode rules to datasets. Must be called after the chart is created\n * so scales and pixel coordinates are available for gradient construction.\n *\n * NOTE: For non-threshold modes (solid, semitransparent), backgroundColor is already\n * set correctly in buildDataset(). This method now only handles threshold gradients\n * which require Chart.js scales to be available.\n */\n protected applyFillModes() {\n // Guard: Verify chart and canvas exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const chart = this.chart; // Store reference for TypeScript\n const ctx = chart.ctx as CanvasRenderingContext2D;\n\n // Guard: Verify canvas context is available\n if (!ctx) return;\n\n const fill = this.shouldApplyFill();\n const fillMode = this.getFillMode();\n\n // Only process threshold mode - other modes already have correct backgroundColor from buildDataset()\n if (fillMode !== 'threshold' || !fill) {\n return;\n }\n\n chart.data.datasets.forEach((ds, _idx) => {\n const dataset = ds as ChartDataset<'line'> & {\n fill?:\n | boolean\n | number\n | {target: number; above: string; below: string};\n yAxisID?: string;\n };\n\n // Skip if not filling\n if (dataset.fill === false || !fill) {\n return;\n }\n\n // Threshold fill: only applies to single-series, creates gradients for border\n const yScaleId = dataset.yAxisID ?? 'y';\n const yScale = chart.scales[yScaleId];\n\n if (!yScale) {\n return;\n }\n\n // Calculate threshold and gradient stop position\n const dataValues = (dataset.data as (number | {x: number; y: number})[])\n .map((d) => (typeof d === 'number' ? d : d.y))\n .filter((v) => Number.isFinite(v));\n\n // Guard: Need at least some data to calculate threshold\n if (dataValues.length === 0) {\n return;\n }\n\n const minVal = Math.min(...dataValues);\n const maxVal = Math.max(...dataValues);\n const thresholdVal = (minVal + maxVal) / 2;\n const thresholdPixel = yScale.getPixelForValue(thresholdVal);\n const range = yScale.bottom - yScale.top;\n\n // Guard: Ensure stop is a finite number between 0 and 1\n let stop = (thresholdPixel - yScale.top) / range;\n if (!Number.isFinite(stop) || range === 0) {\n stop = 0.5; // Fallback to middle if calculation fails\n } else {\n stop = Math.max(0, Math.min(1, stop));\n }\n\n // Extract threshold color variables (used for both fill and border)\n const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;\n const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;\n\n // Helper to create threshold gradient\n const createGradient = (lowAlpha: number, highAlpha: number) => {\n const low = applyAlphaToColor(this, lowRaw, lowAlpha);\n const high = applyAlphaToColor(this, highRaw, highAlpha);\n const grad = ctx.createLinearGradient(0, yScale.top, 0, yScale.bottom);\n grad.addColorStop(0, high);\n grad.addColorStop(stop, high);\n grad.addColorStop(stop, low);\n grad.addColorStop(1, low);\n return grad;\n };\n\n // Create fill gradient (35% alpha) and border gradient (80% alpha)\n const fillGradient = createGradient(0.35, 0.35);\n const borderGradient = createGradient(0.8, 0.8);\n dataset.backgroundColor = fillGradient as unknown as string;\n dataset.borderColor = borderGradient as unknown as string;\n });\n }\n\n // Update external library AFTER render\n override updated(changed: PropertyValues) {\n super.updated(changed);\n\n // Only update if watched properties changed\n if (!this.hasAnyChanged(changed, LINE_GRAPH_WATCHED_PROP_NAMES)) {\n return;\n }\n\n // `hasLabelPadding` cascades into slotted scales via `updateScaleProperties()`\n // (toggles `showLabels`, which collapses/expands the bar's label band and\n // changes its reported thickness). That path only runs through\n // `syncScalesAndChart()`, so when only `hasLabelPadding` changes we must\n // route through there — otherwise slotted scales stay stale until the\n // next slot/resize event and the chart re-pads on stale thickness.\n if (changed.has('hasLabelPadding') && this.hasExternalScales()) {\n this.syncScalesAndChart();\n return;\n }\n\n const needsRecreation = this.hasAnyChanged(\n changed,\n LINE_GRAPH_RECREATE_PROP_NAMES\n );\n\n if (needsRecreation) {\n this.chart?.destroy();\n this.createChart();\n } else {\n this.updateChart();\n }\n }\n\n override async firstUpdated() {\n // Wait for external scales to report dimensions before creating chart\n await this.waitForScaleDimensions();\n\n if (!this.hasExternalScales()) {\n // No external scales, create chart normally\n this.createChart();\n }\n // If we have external scales, chart is created in syncScalesAndChart()\n\n this.themeObserver = observeThemeChanges(() => {\n this.updateChartColors();\n this.updateBorderRadius(); // Border color may change with theme\n });\n this.setupResizeObserver();\n this.setupAspectRatioResizeObserver();\n\n // Setup border radius observer and apply initial styling\n // In instrument mode, skip observer - we use fixed border radius\n if (this.canvasEl) {\n if (!this.instrumentMode) {\n this.borderRadiusObserver = startExternalScaleBorderRadiusObserver(\n this.canvasEl,\n this.updateBorderRadius\n );\n }\n this.updateBorderRadius();\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.chart?.destroy();\n this.themeObserver?.disconnect();\n this.resizeObserver?.disconnect();\n this.aspectRatioResizeObserver?.disconnect();\n this.borderRadiusObserver?.disconnect();\n\n if (this.dimensionUpdateTimer) {\n clearTimeout(this.dimensionUpdateTimer);\n }\n }\n\n /**\n * Setup resize observer to detect height threshold crossings\n * Recreates chart when crossing MIN_HEIGHT_WITH_LABELS (192px) to show/hide labels\n * Detect when height property changes programmatically (e.g., via Storybook controls or user code)\n */\n private setupResizeObserver() {\n if (!this.canvasEl) return;\n\n this.resizeObserver = new ResizeObserver(() => {\n // Guard: Check if chart and canvas still exist (component may be disconnecting)\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const height = this.canvasEl.clientHeight;\n const isAboveThreshold =\n height >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Only recreate chart if we crossed the threshold\n if (isAboveThreshold !== this.wasAboveThreshold) {\n this.wasAboveThreshold = isAboveThreshold;\n this.chart.destroy();\n this.createChart();\n } else {\n // Height changed but didn't cross threshold - just update\n this.updateChart();\n }\n });\n\n this.resizeObserver.observe(this.canvasEl);\n\n // Initialize threshold state\n const height = this.canvasEl.clientHeight;\n this.wasAboveThreshold =\n height >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n }\n\n /**\n * Setup resize observer for fixed aspect ratio scaling.\n * Observes the wrapper element and recalculates dimensions when parent size changes.\n */\n private setupAspectRatioResizeObserver() {\n const wrapper = this.renderRoot.querySelector('.wrapper');\n if (!wrapper) return;\n\n // Initialize computed dimensions\n this.updateComputedDimensions();\n\n this.aspectRatioResizeObserver = new ResizeObserver(() => {\n if (!this.fixedAspectRatioScaling) return;\n this.updateComputedDimensions();\n });\n\n this.aspectRatioResizeObserver.observe(wrapper);\n }\n\n /**\n * Calculate actual dimensions based on parent width and aspect ratio.\n * Only used when fixedAspectRatioScaling is true.\n */\n private updateComputedDimensions() {\n if (!this.fixedAspectRatioScaling) {\n // In pixel mode, use width/height directly\n this.computedWidth = this.width;\n this.computedHeight = this.height;\n return;\n }\n\n // Get the wrapper element\n const wrapper = this.renderRoot.querySelector('.wrapper') as HTMLElement;\n if (!wrapper) return;\n\n // Get parent's available width\n const parentWidth = wrapper.clientWidth;\n if (parentWidth <= 0) return;\n\n // Calculate aspect ratio from width/height properties\n const aspectRatio = this.width / this.height;\n\n // Use parent width as actual width, calculate height from aspect ratio\n const newWidth = parentWidth;\n const newHeight = Math.round(parentWidth / aspectRatio);\n\n // console.debug(`[chart-line-base] updateComputedDimensions:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // scaleReferenceSize: this.scaleReferenceSize,\n // parentWidth,\n // aspectRatio,\n // newWidth,\n // newHeight,\n // scaleFactor: newWidth / this.width,\n // });\n\n // Only update if dimensions changed\n if (this.computedWidth !== newWidth || this.computedHeight !== newHeight) {\n this.computedWidth = newWidth;\n this.computedHeight = newHeight;\n\n // Update external scales and recreate chart with new dimensions\n // Note: syncScalesAndChart() handles chart destruction and creation internally,\n // so we only call createChart() directly when there are no external scales.\n if (this.hasExternalScales()) {\n this.syncScalesAndChart();\n } else if (this.chart) {\n // No external scales - just recreate chart\n this.chart.destroy();\n this.createChart();\n }\n }\n }\n\n /**\n * Get the effective width for chart rendering.\n * Returns computed width when fixedAspectRatioScaling is true, otherwise the width property.\n */\n protected getEffectiveWidth(): number {\n return this.fixedAspectRatioScaling ? this.computedWidth : this.width;\n }\n\n /**\n * Get the effective height for chart rendering.\n * Returns computed height when fixedAspectRatioScaling is true, otherwise the height property.\n */\n protected getEffectiveHeight(): number {\n return this.fixedAspectRatioScaling ? this.computedHeight : this.height;\n }\n\n /**\n * Get the scale factor for proportional scaling when fixedAspectRatioScaling is true.\n * Returns 1.0 when not in fixed aspect ratio mode.\n * The scale factor is based on computed width vs reference width (the width property).\n */\n protected getScaleFactor(): number {\n if (!this.fixedAspectRatioScaling) {\n return 1.0;\n }\n // Scale factor is based on computed width vs the reference width (width property)\n // The width property defines the \"design\" or \"reference\" size\n return this.computedWidth / this.width;\n }\n\n /**\n * Build a complete dataset configuration with all styling properties.\n * Handles both new datasets (from values array) and existing datasets (normalization).\n *\n * @param data - Either numeric values array or existing dataset to normalize\n * @param index - Dataset index for color cycling\n * @param chartColors - Color palette array\n * @param totalCount - Total number of datasets (used for stacked divider logic)\n * @returns Fully configured Chart.js dataset\n */\n protected buildDataset(\n data:\n | number[]\n | {x: number; y: number}[]\n | ChartDataset<'line', ChartLinePoint[]>,\n index: number,\n chartColors: string[],\n totalCount = 1\n ): ChartDataset<'line', ChartLinePoint[]> {\n const currentColor = chartColors[index % chartColors.length];\n\n // Raw input is an array (values or points); anything else is an existing dataset\n const existingDataset = Array.isArray(data)\n ? null\n : (data as ChartDataset<'line', ChartLinePoint[]>);\n const values = Array.isArray(data)\n ? (data as number[] | {x: number; y: number}[])\n : null;\n\n const borderColor = existingDataset?.borderColor ?? currentColor;\n const fillFlag = existingDataset?.fill ?? this.shouldApplyFill();\n const tension = this.lineMode === 'smooth' ? this.DEFAULT_TENSION : 0;\n\n // For stacked mode, add divider lines between datasets (except the topmost one)\n const isStacked = this.shouldStack() && this.getFillMode() !== 'threshold';\n const needsDivider = isStacked && index < totalCount - 1;\n\n // Calculate backgroundColor immediately instead of deferring to applyFillModes()\n // This prevents flicker when chart is recreated multiple times during resize\n let backgroundColor: string = 'transparent';\n const fillMode = this.getFillMode();\n\n if (fillFlag && fillMode) {\n const nextColor = chartColors[(index + 1) % chartColors.length];\n\n if (fillMode === 'solid') {\n backgroundColor = String(borderColor);\n } else if (fillMode === 'semitransparent') {\n backgroundColor = applyAlphaToColor(this, nextColor, 0.5);\n } else if (fillMode === 'threshold') {\n // For threshold, we'll still need gradients from applyFillModes\n // but set a reasonable default to avoid transparent flash\n backgroundColor = applyAlphaToColor(this, nextColor, 0.5);\n }\n }\n\n const result = {\n ...(existingDataset || {}),\n data: existingDataset?.data ?? values!,\n borderColor,\n backgroundColor,\n borderWidth: existingDataset?.borderWidth ?? 2,\n showLine: existingDataset?.showLine ?? true,\n tension: existingDataset?.tension ?? tension,\n pointRadius:\n existingDataset?.pointRadius ??\n (this.showPoints ? this.POINT_RADIUS : 0),\n pointBackgroundColor: existingDataset?.pointBackgroundColor ?? '#fff',\n pointBorderColor: existingDataset?.pointBorderColor ?? borderColor,\n pointBorderWidth: existingDataset?.pointBorderWidth ?? 2,\n stepped: existingDataset?.stepped ?? this.lineMode === 'stepped',\n // Use 'start' to fill from chart bottom, not 'origin' (y=0)\n fill: fillFlag ? 'start' : false,\n spanGaps: existingDataset?.spanGaps ?? true,\n // Add segment styling for stacked divider lines\n ...(needsDivider && {\n segment: {\n borderColor: getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.stackedDividerColorVar\n ),\n borderWidth: 1,\n },\n }),\n };\n\n return result as ChartDataset<'line', ChartLinePoint[]>;\n }\n\n /**\n * Create threshold mode datasets: invisible baseline + main dataset with\n * above/below fills. Accepts plain values (category mode) or {x, y} points\n * (time/number mode); the baseline mirrors the input x-positions.\n */\n protected createThresholdDatasets(\n values: number[] | {x: number; y: number}[],\n chartColors: string[]\n ): ChartDataset<'line', ChartLinePoint[]>[] {\n const yValues = values\n .map((v) => (typeof v === 'number' ? v : v.y))\n .filter((n) => Number.isFinite(n));\n const minV = yValues.length ? Math.min(...yValues) : 0;\n const maxV = yValues.length ? Math.max(...yValues) : 100;\n const threshold = (minV + maxV) / 2;\n const baselineData: ChartLinePoint[] = values.map((v) =>\n typeof v === 'number' ? threshold : {x: v.x, y: threshold}\n );\n\n const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;\n const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;\n const highFill = applyAlphaToColor(this, highRaw, 0.35);\n const lowFill = applyAlphaToColor(this, lowRaw, 0.35);\n\n const baselineDataset: ChartDataset<'line', ChartLinePoint[]> = {\n label: 'threshold-baseline',\n data: baselineData,\n borderColor: 'transparent',\n backgroundColor: 'transparent',\n borderWidth: 0,\n pointRadius: 0,\n showLine: false,\n fill: false,\n spanGaps: true,\n };\n\n const main = this.buildDataset(values, 0, chartColors);\n (main as unknown as Record<string, unknown>).fill = {\n target: 0,\n above: highFill,\n below: lowFill,\n };\n // Border gradient will be set by applyFillModes after chart scales are ready\n main.borderWidth = 2;\n\n return [baselineDataset, main];\n }\n\n /**\n * Prepare normalized datasets for multi-series charts.\n * In time/number mode every point's x is normalized (epoch ms / number)\n * so strings, Dates and Temporal objects position correctly.\n */\n protected prepareMultiSeriesDatasets() {\n const defaultPalette =\n this.priority === Priority.enhanced\n ? CHART_SECTOR_ENHANCED_COLORS\n : CHART_SECTOR_DEFAULT_COLORS;\n const chartColors = getChartColorsOrDefault(\n this,\n this.colors,\n defaultPalette\n );\n\n // Normalize first, then warn once per assignment with the aggregate\n // count across ALL series — warning inside the per-dataset loop would\n // either flood the console or (with ref-based dedup) silently swallow\n // failures in every series after the first.\n const normalized = this.datasets!.map((ds) => this.normalizeDatasetX(ds));\n if (this.isNumericXAxis) {\n this.warnOnInvalidX(\n normalized.flatMap((ds) =>\n (ds.data ?? []).map((pt) =>\n pt && typeof pt === 'object' ? (pt.x as number) : 0\n )\n ),\n this.datasets\n );\n }\n\n const totalCount = this.datasets!.length;\n return normalized.map((ds, i) =>\n this.buildDataset(ds, i, chartColors, totalCount)\n );\n }\n\n /** @internal - Return a copy of the dataset with normalized point x-values. */\n private normalizeDatasetX(\n ds: ChartDataset<'line', ChartLinePoint[]>\n ): ChartDataset<'line', ChartLinePoint[]> {\n if (!this.isNumericXAxis || !ds.data) return ds;\n const data = ds.data.map((pt) =>\n pt && typeof pt === 'object' && 'x' in pt\n ? {...pt, x: normalizeXValue(pt.x, this.xValueMode)}\n : pt\n );\n return {...ds, data};\n }\n\n /**\n * Prepare datasets for single-series charts.\n * Category mode: labels + numeric values (unchanged legacy path).\n * Time/number mode: normalized {x, y} points on a linear scale.\n * Handles both regular and threshold fill modes.\n */\n protected prepareSingleSeriesDatasets() {\n const defaultPalette =\n this.priority === Priority.enhanced\n ? CHART_SECTOR_ENHANCED_COLORS\n : CHART_SECTOR_DEFAULT_COLORS;\n const chartColors = getChartColorsOrDefault(\n this,\n this.colors,\n defaultPalette\n );\n const fill = this.shouldApplyFill();\n const fillMode = this.getFillMode();\n\n if (this.isNumericXAxis) {\n const points = this.data.map((d) => ({\n x: normalizeXValue(d.x ?? d.label ?? NaN, this.xValueMode),\n y: d.value,\n }));\n this.warnOnInvalidX(\n points.map((p) => p.x),\n this.data\n );\n const datasets =\n fill && fillMode === 'threshold'\n ? this.createThresholdDatasets(points, chartColors)\n : [this.buildDataset(points, 0, chartColors)];\n return {datasets, labels: [] as (string | number)[]};\n }\n\n const values = this.data.map((d) => d.value);\n const labels = this.data.map((d) => d.label ?? String(d.x ?? ''));\n\n const datasets =\n fill && fillMode === 'threshold'\n ? this.createThresholdDatasets(values, chartColors)\n : [this.buildDataset(values, 0, chartColors)];\n\n return {datasets, labels};\n }\n\n /**\n * Get Chart.js options with dynamic sizing and padding\n */\n protected getChartOptions(): ChartOptions<'line'> {\n // Use effective dimensions (computed when fixedAspectRatioScaling=true)\n const effectiveWidth = this.getEffectiveWidth();\n const effectiveHeight = this.getEffectiveHeight();\n\n // Determine if chart is too small for labels\n const isTooSmall =\n effectiveWidth < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS ||\n effectiveHeight < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;\n\n // Get scale factor for proportional scaling in fixed aspect ratio mode\n const scaleFactor = this.getScaleFactor();\n\n // Calculate padding for the chart.\n // External scales report their actual visual (scaled) thickness when in fixedAspectRatio mode,\n // so we use those values directly without additional scaling.\n // For sides without external scales, we apply the chart's scaleFactor to default padding.\n let padding: {top: number; right: number; bottom: number; left: number};\n\n // When hasLabelPadding=false the chart never reserves space for axis tick\n // labels on sides without an external scale (renders edge-to-edge there).\n // External-scale sides still receive their reported visual thickness so\n // slotted scales/bars remain fully visible.\n const defaultPaddingScaled = !this.hasLabelPadding\n ? 0\n : this.fixedAspectRatioScaling\n ? Math.round(CHART_DIMENSIONS.CANVAS_PADDING * scaleFactor)\n : CHART_DIMENSIONS.CANVAS_PADDING;\n\n if (isTooSmall && this.hasLabelPadding) {\n padding = {top: 0, right: 0, bottom: 0, left: 0};\n } else if (this.hasExternalScales()) {\n // External scales report their visual dimensions (already scaled when fixedAspectRatio=true)\n const scalePadding = this.calculatePaddingFromScales();\n padding = {\n top: this.externalScaleDimensions.has('top')\n ? scalePadding.top\n : defaultPaddingScaled,\n right: this.externalScaleDimensions.has('right')\n ? scalePadding.right\n : defaultPaddingScaled,\n bottom: this.externalScaleDimensions.has('bottom')\n ? scalePadding.bottom\n : defaultPaddingScaled,\n left: this.externalScaleDimensions.has('left')\n ? scalePadding.left\n : defaultPaddingScaled,\n };\n } else {\n // No external scales - apply scaleFactor to all default padding\n padding = {\n top: defaultPaddingScaled,\n right: defaultPaddingScaled,\n bottom: defaultPaddingScaled,\n left: defaultPaddingScaled,\n };\n }\n\n // console.debug(`[chart-line-base] getChartOptions:`, {\n // fixedAspectRatioScaling: this.fixedAspectRatioScaling,\n // referenceWidth: this.width,\n // referenceHeight: this.height,\n // effectiveWidth,\n // effectiveHeight,\n // scaleFactor,\n // scaleReferenceSize: this.scaleReferenceSize,\n // padding,\n // externalScaleDimensions: Object.fromEntries(this.externalScaleDimensions),\n // hasExternalScales: this.hasExternalScales(),\n // });\n\n // Set CSS variables for wrapper and canvas sizing\n if (this.fixedAspectRatioScaling) {\n // In responsive mode, use 100% width, computed height\n this.style.setProperty('--chart-width', '100%');\n this.style.setProperty('--chart-height', `${effectiveHeight}px`);\n } else {\n // In pixel mode, use width/height directly\n this.style.setProperty('--chart-width', `${this.width}px`);\n this.style.setProperty('--chart-height', `${this.height}px`);\n }\n\n // Compute reference timestamp for time-based x-axis\n const refTs = this.computeTimeReference();\n\n // Force showTickMarks=false when external scales are present\n const effectiveShowTickMarks = this.hasExternalScales()\n ? false\n : this.showTickMarks;\n\n return {\n responsive: true,\n maintainAspectRatio: false, // Use explicit width/height instead\n layout: {\n padding,\n },\n plugins: {\n legend: {\n display: false,\n labels: {\n generateLabels: () => [], // Prevent Chart.js from generating labels internally\n },\n onClick: () => {}, // Disable legend click handler\n },\n tooltip: {\n ...getChartTooltipOptions(this),\n enabled: !isTooSmall,\n callbacks: {\n title: () => '',\n label: (context) => {\n const value =\n typeof context.parsed === 'object' && context.parsed !== null\n ? (context.parsed as {y: number}).y\n : (context.parsed as number);\n const numericValue = formatNumericValue(value, 1, false, 0);\n const unit = this.unit ? `${this.unit}` : '';\n let label = context.label ?? '';\n if (this.isNumericXAxis) {\n const x =\n typeof context.parsed === 'object' && context.parsed !== null\n ? (context.parsed as {x: number}).x\n : NaN;\n const relativeTo =\n this.timeDisplay === TimeDisplay.minutes ? refTs : undefined;\n label = formatXValue(x, this.xValueMode, relativeTo);\n }\n return `${label} ${numericValue}${unit}`;\n },\n },\n },\n },\n animation: false,\n scales: this.buildScalesConfig(refTs, isTooSmall, effectiveShowTickMarks),\n };\n }\n\n /**\n * Compute reference timestamp for time axis formatting.\n * Returns earliest timestamp for 'date' mode, latest for 'minutes' mode.\n */\n private computeTimeReference(): number | undefined {\n if (this.xAxisType !== XAxisType.time) return undefined;\n\n const timestamps: number[] = [];\n\n // Collect timestamps from datasets\n if (this.datasets?.length) {\n this.datasets.forEach((ds) => {\n if (!ds.data) return;\n ds.data.forEach((pt) => {\n if (pt && typeof pt === 'object' && 'x' in pt) {\n const ts = normalizeXValue(pt.x, XValueMode.time);\n if (Number.isFinite(ts)) timestamps.push(ts);\n }\n });\n });\n } else if (this.data?.length) {\n // Collect timestamps from single-series data items\n this.data.forEach((d) => {\n const ts = normalizeXValue(d.x ?? d.label ?? NaN, XValueMode.time);\n if (Number.isFinite(ts)) timestamps.push(ts);\n });\n }\n\n // Collect timestamps from labels if no dataset timestamps found\n if (!timestamps.length && this.labels?.length) {\n this.labels.forEach((l) => {\n if (typeof l === 'string') {\n const ts = new Date(l).getTime();\n if (Number.isFinite(ts)) timestamps.push(ts);\n }\n });\n }\n\n return timestamps.length\n ? this.timeDisplay === 'minutes'\n ? Math.max(...timestamps)\n : Math.min(...timestamps)\n : undefined;\n }\n\n /**\n * Build Chart.js scale configuration with theme-aware styling.\n * Applies CSS variables for grid colors, tick colors, and label typography.\n *\n * @param minX - Reference timestamp for time-based x-axis (used for 'minutes' display)\n * @param isTooSmall - Whether chart is below 192px threshold (hides ticks when true)\n * @param showTickMarks - Whether to show tick marks (overridden to false when external scales present)\n * @returns Configured scales object for Chart.js options\n */\n protected buildScalesConfig(\n minX?: number,\n isTooSmall = false,\n showTickMarks = true\n ) {\n // Build scales typed for ChartOptions<'line'>\n // If we don't have a date adapter available, fall back to numeric linear scale\n // by converting date strings to timestamps before chart creation. We still\n // render formatted tick labels for readability.\n // Read CSS variables for styling\n const gridColor = getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.gridColorVar\n );\n const tickColor = getCssVariableValue(\n this,\n LINE_GRAPH_GRID_CONFIG.tickColorVar\n );\n const fontFamily = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontFamily\n );\n const fontSize = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontSizeVar\n );\n const fontWeight = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontWeightVar\n );\n const fontColor = getCssVariableValue(\n this,\n LINE_GRAPH_LABEL_CONFIG.fontColorVar\n );\n\n // Extract common values used for both x and y axes.\n // When hasLabelPadding=false the chart renders edge-to-edge, so labels are\n // force-hidden to prevent clipping.\n const showLabels = showTickMarks && !isTooSmall && this.hasLabelPadding;\n const showTicks = showTickMarks && !isTooSmall && this.hasLabelPadding;\n const fontConfig = {family: fontFamily, size: fontSize, weight: fontWeight};\n\n const x = {\n type: this.xAxisType === XAxisType.category ? 'category' : 'linear',\n offset: false, // Always edge-to-edge (no padding on x-axis)\n grace: 0, // No extra margin\n bounds: 'data', // Use data bounds for edge-to-edge rendering\n grid: {\n display: this.showGrid && this.showGridX,\n color: gridColor,\n offset: false,\n drawTicks: showTicks,\n },\n ticks: {\n display: showLabels,\n color: fontColor,\n font: fontConfig,\n maxRotation: 0, // Keep labels horizontal (no rotation)\n minRotation: 0, // Keep labels horizontal (no rotation)\n maxTicksLimit: this.xTicksLimit,\n stepSize: this.xStepSize,\n callback: (value: unknown) => {\n if (!this.isNumericXAxis) return String(value);\n const n = Number(value);\n if (!Number.isFinite(n)) return String(value);\n const relativeTo =\n this.timeDisplay === TimeDisplay.minutes ? minX : undefined;\n return formatXValue(n, this.xValueMode, relativeTo);\n },\n },\n border: {\n display: showLabels,\n color: tickColor,\n },\n } as unknown;\n\n // Build y-axis scales configuration\n const yAxesConfig = this.yAxes?.length\n ? this.yAxes.map((axis, i) => ({\n id: axis.id ?? `y${i}`,\n position: axis.position ?? ('left' as 'left' | 'right'),\n min: axis.min,\n max: axis.max,\n gridDisplay: axis.grid ?? (this.showGrid && this.showGridY),\n }))\n : [\n {\n id: 'y',\n position: this.yAxisPosition,\n min: undefined,\n max: undefined,\n gridDisplay: this.showGrid && this.showGridY,\n },\n ];\n\n const scalesRecord: Record<string, unknown> = {x};\n\n yAxesConfig.forEach(({id, position, min, max, gridDisplay}) => {\n scalesRecord[id] = {\n type: 'linear',\n display: true,\n position,\n stacked: this.shouldStack() && this.getFillMode() !== 'threshold',\n grace: isTooSmall ? 0 : undefined,\n bounds: isTooSmall ? 'data' : 'ticks',\n grid: {\n display: gridDisplay,\n color: gridColor,\n drawTicks: showTicks,\n },\n ticks: {\n display: showLabels,\n color: fontColor,\n font: fontConfig,\n maxTicksLimit: this.yTicksLimit,\n stepSize: this.yStepSize,\n },\n border: {\n display: showLabels,\n color: tickColor,\n },\n min,\n max,\n };\n });\n\n return scalesRecord as ChartOptions<'line'>['scales'];\n }\n\n /**\n * Prepare chart data and labels for both single and multi-series modes\n */\n private prepareChartDataAndLabels() {\n if (this.datasets?.length) {\n return {\n datasets: this.prepareMultiSeriesDatasets(),\n labels: (this.labels ?? []) as (string | number)[],\n };\n }\n return this.prepareSingleSeriesDatasets();\n }\n\n private createChart() {\n // Guard: Verify canvas exists and is connected to DOM\n if (!this.canvasEl || !this.canvasEl.isConnected) return;\n\n const ctx = this.canvasEl.getContext('2d');\n if (!ctx) return;\n\n // Destroy existing chart instance to prevent canvas reuse errors\n if (this.chart) {\n this.chart.destroy();\n this.chart = undefined;\n }\n\n const {datasets, labels} = this.prepareChartDataAndLabels();\n\n this.chart = new Chart(ctx, {\n type: 'line',\n data: {labels, datasets},\n options: this.getChartOptions(),\n plugins: this.borderRadiusPosition ? [this.createBorderPlugin()] : [],\n } as ChartConfiguration<'line'>);\n\n // Defer legend update to next tick to ensure Chart.js metadata is initialized\n requestAnimationFrame(() => this.updateLegend());\n this.applyFillModes();\n }\n\n private updateChart() {\n // Guard: Verify chart and canvas still exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n const {datasets, labels} = this.prepareChartDataAndLabels();\n\n this.chart.data.labels = labels;\n this.chart.data.datasets = datasets as unknown as ChartDataset<'line'>[];\n\n // Update options (chart.options is always defined after chart creation)\n Object.assign(this.chart.options, this.getChartOptions());\n\n this.applyFillModes();\n this.chart.update();\n\n // Update legend after chart update completes to ensure metadata is ready\n requestAnimationFrame(() => this.updateLegend());\n }\n\n /**\n * Update only chart colors without recalculating layout\n * Used by theme observer for efficient theme changes\n */\n private updateChartColors() {\n // Guard: Verify chart and canvas still exist and are connected\n if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;\n\n // Re-apply fill modes which will update gradients for threshold mode\n this.applyFillModes();\n\n // Update without animation for instant theme change\n this.chart.update('none');\n\n // Defer legend update to next frame to ensure metadata is ready\n requestAnimationFrame(() => this.updateLegend());\n }\n\n /**\n * Update the legend HTML content\n */\n private updateLegend() {\n // Guard: Check if legend should be shown and chart is ready\n if (!this.legend || !this.legendDiv || !this.chart) return;\n\n // Guard: Check if chart has datasets\n if (!this.chart.data.datasets || this.chart.data.datasets.length === 0) {\n // console.debug('[chart-line-base] updateLegend: skipped - no datasets available');\n this.legendDiv.innerHTML = '';\n return;\n }\n\n try {\n const legendItems = this.chart.data.datasets\n .map((ds, i) => {\n const meta = this.chart!.getDatasetMeta(i);\n\n // Guard: Check if metadata and controller are available\n if (!meta || !meta.controller) {\n // console.debug(`[chart-line-base] updateLegend: dataset ${i} metadata not yet initialized`);\n return null;\n }\n\n const style = meta.controller.getStyle(0, false);\n const dataset = ds as ChartDataset<\n 'line',\n (number | {x: number; y: number})[]\n >;\n\n return {\n fillStyle: (dataset.borderColor ??\n style.borderColor ??\n '') as string,\n label: (dataset.label as string) || `Series ${i + 1}`,\n value: '',\n unit: '',\n };\n })\n .filter((item) => item !== null);\n\n // Only update legend if we have valid items\n if (legendItems.length > 0) {\n const legendHTML = generateLegendHTML(legendItems);\n this.legendDiv.innerHTML = legendHTML;\n }\n } catch (error) {\n console.debug(\n '[chart-line-base] updateLegend: error generating legend HTML',\n error\n );\n // Silent failure - don't throw, just skip legend update this time\n }\n }\n\n override render() {\n return html`\n <div class=\"wrapper\">\n <div class=\"canvas-and-slots-container\">\n <slot\n name=\"top-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"bottom-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"left-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <slot\n name=\"right-scale\"\n @slotchange=${this.handleSlotChange}\n @scale-dimensions-changed=${this.handleScaleDimensionsChanged}\n ></slot>\n <canvas></canvas>\n </div>\n\n ${this.legend ? html`<div class=\"legend\"></div>` : ''}\n </div>\n `;\n }\n\n static override styles = [\n unsafeCSS(componentStyle),\n unsafeCSS(chartCommonStyle),\n unsafeCSS(chartLegendStyle),\n unsafeCSS(chartDebugStyle),\n ];\n}\n"],"names":["XAxisType","YAxisPosition","LineMode","TimeDisplay","r","height","datasets"],"mappings":"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"}
|