Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 9x 90x 90x 90x 90x 90x 90x 1833x 1833x 1833x 1833x 1833x 12955x 12954x 119x 90x 90x 29x 17x 17x 17x 17x 17x 17x 12x 3x 3x 3x 3x 3x 3x 3x 2x 1x 9x 9128x | import { canonicalAttr, formatLegendName } from '@ska-octopus-widget-sdk/widget-sdk';
// Shared utilities are now in the SDK. Re-export them so all existing
// internal imports (canonicalAttr, parseMargins, formatLegendName, etc.)
// continue to resolve without touching every call-site.
export {
canonicalAttr,
parseMargins,
formatLegendName,
extractStationAndNumber
} from '@ska-octopus-widget-sdk/widget-sdk';
// ── Timeline-specific utilities ───────────────────────────────────────────
export type MinMaxLike =
| number
| string
| { min?: number; max?: number }
| [number, number]
| null
| undefined;
const HAS_TEMPLATE_PLACEHOLDER = /\{[^}]+\}/i;
function labelAttributePath(attr: string, attrLabel: string): string {
const key = canonicalAttr(attr);
const label = String(attrLabel ?? '').trim();
Iif (!key || !label) return key;
const parts = key.split('/');
parts[parts.length - 1] = label;
return parts.join('/');
}
export function formatLegendLabel(
attr: string,
format: string,
attrLabel = '',
hasExplicitFormat = false
): string {
const label = String(attrLabel ?? '').trim();
const fmt = String(format ?? 'lastname').trim() || 'lastname';
const effectiveFmt =
!hasExplicitFormat && label && !HAS_TEMPLATE_PLACEHOLDER.test(fmt) ? 'label' : fmt;
const sourceAttr = label ? labelAttributePath(attr, label) : attr;
return formatLegendName(sourceAttr, effectiveFmt, label).trim();
}
/* Coerce to number; non-numeric → NaN */
export function toNum(v: any): number {
const n = typeof v === 'number' ? v : Number(v);
return Number.isFinite(n) ? n : NaN;
}
/**
* Try to coerce a value coming from HDB++ into:
* - y: a scalar (mid = (min+max)/2 when both exist)
* - min/max: when available
*/
export function coerceMinMax(value: MinMaxLike): {
y: number | null;
min?: number;
max?: number;
} {
if (value === null || value === undefined) return { y: null };
if (typeof value === 'number') return { y: Number.isFinite(value) ? value : null };
if (typeof value === 'string') {
const num = Number(value);
return { y: Number.isFinite(num) ? num : null };
}
// tuple [min, max]
if (Array.isArray(value) && value.length >= 2) {
const a = Number(value[0]);
const b = Number(value[1]);
Eif (Number.isFinite(a) && Number.isFinite(b)) {
const min = Math.min(a, b);
const max = Math.max(a, b);
return { y: (min + max) / 2, min, max };
}
return { y: null };
}
// object {min, max}
if (typeof value === 'object') {
const minRaw = (value as any).min;
const maxRaw = (value as any).max;
const min = Number(minRaw);
const max = Number(maxRaw);
const hasMin = Number.isFinite(min);
const hasMax = Number.isFinite(max);
if (hasMin && hasMax) return { y: (min + max) / 2, min, max };
if (hasMin && !hasMax) return { y: min, min };
Eif (!hasMin && hasMax) return { y: max, max };
return { y: null };
}
return { y: null };
}
/** Convenience: scalar numeric from arbitrary HDB++ value (or null) */
export function numericValue(value: MinMaxLike): number | null {
return coerceMinMax(value).y;
}
|