135 lines
3.7 KiB
JavaScript
135 lines
3.7 KiB
JavaScript
/**
|
|
* Chart display modes — how a metrics card should paint its series.
|
|
*
|
|
* Catalog agents emit chartType: line | area | stacked.
|
|
* The desktop can also render bar / multibar / pie where they make sense.
|
|
*/
|
|
|
|
/** @typedef {'line'|'area'|'stacked'|'bar'|'multibar'|'pie'} ChartMode */
|
|
|
|
/** @type {ChartMode[]} */
|
|
export const CHART_MODES = ['line', 'area', 'stacked', 'bar', 'multibar', 'pie']
|
|
|
|
/** Short labels for the type toggle button */
|
|
export const CHART_MODE_LABEL = {
|
|
line: 'line',
|
|
area: 'area',
|
|
stacked: 'stack',
|
|
bar: 'bar',
|
|
multibar: 'bars',
|
|
pie: 'pie',
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} raw
|
|
* @returns {ChartMode}
|
|
*/
|
|
export function normalizeChartMode(raw) {
|
|
const m = String(raw || 'line')
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[_-]/g, '')
|
|
if (m === 'multibar' || m === 'bargroup') return 'multibar'
|
|
if (m === 'stack') return 'stacked'
|
|
if (CHART_MODES.includes(/** @type {ChartMode} */ (m))) {
|
|
return /** @type {ChartMode} */ (m)
|
|
}
|
|
return 'line'
|
|
}
|
|
|
|
/**
|
|
* Default mode from catalog metadata.
|
|
* @param {object} [meta]
|
|
* @returns {ChartMode}
|
|
*/
|
|
export function defaultModeFromMeta(meta = {}) {
|
|
return normalizeChartMode(meta.chartType || meta.chart_type || 'line')
|
|
}
|
|
|
|
/**
|
|
* @param {object} [meta]
|
|
*/
|
|
function dimCount(meta = {}) {
|
|
const dims = meta.dimensions
|
|
if (Array.isArray(dims)) return dims.length
|
|
if (dims && typeof dims === 'object') return Object.keys(dims).length
|
|
return 0
|
|
}
|
|
|
|
/**
|
|
* Composition charts (parts of a whole) — pie / stacked are natural.
|
|
* @param {object} [meta]
|
|
*/
|
|
export function isCompositionChart(meta = {}) {
|
|
const mode = defaultModeFromMeta(meta)
|
|
if (mode === 'stacked') return true
|
|
const units = String(meta.units || '')
|
|
if (/%|percentage|percent/i.test(units)) return true
|
|
const id = String(meta.id || meta.name || '')
|
|
// Common composition contexts
|
|
if (/\.(cpu|ram|swap|slab|kernel|states|usage)$/i.test(id)) return true
|
|
if (/^(system\.cpu|system\.ram|mem\.(swap|kernel|slab))/i.test(id)) return true
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Modes that make sense for this chart (catalog default first).
|
|
* @param {object} [meta]
|
|
* @returns {ChartMode[]}
|
|
*/
|
|
export function allowedModesFor(meta = {}) {
|
|
const preferred = defaultModeFromMeta(meta)
|
|
const n = dimCount(meta)
|
|
const composition = isCompositionChart(meta)
|
|
/** @type {Set<ChartMode>} */
|
|
const set = new Set(['line', 'area'])
|
|
|
|
if (n !== 1) set.add('stacked')
|
|
set.add('bar')
|
|
if (n === 0 || (n >= 2 && n <= 16)) set.add('multibar')
|
|
if (composition || preferred === 'stacked') set.add('pie')
|
|
|
|
// Always allow the catalog default
|
|
set.add(preferred)
|
|
|
|
const order = /** @type {ChartMode[]} */ ([
|
|
preferred,
|
|
...CHART_MODES.filter((m) => m !== preferred && set.has(m)),
|
|
])
|
|
return order
|
|
}
|
|
|
|
/**
|
|
* Cycle to the next allowed mode.
|
|
* @param {ChartMode|string} current
|
|
* @param {object} [meta]
|
|
* @returns {ChartMode}
|
|
*/
|
|
export function nextChartMode(current, meta = {}) {
|
|
const allowed = allowedModesFor(meta)
|
|
const cur = normalizeChartMode(current)
|
|
const idx = allowed.indexOf(cur)
|
|
return allowed[(idx < 0 ? 0 : idx + 1) % allowed.length]
|
|
}
|
|
|
|
/**
|
|
* Human hint for tooltips / empty states.
|
|
* @param {ChartMode|string} mode
|
|
*/
|
|
export function chartModeHint(mode) {
|
|
switch (normalizeChartMode(mode)) {
|
|
case 'area':
|
|
return 'Filled time series — good for volume and rates'
|
|
case 'stacked':
|
|
return 'Stacked over time — parts of a whole'
|
|
case 'bar':
|
|
return 'Columns over time — compare magnitude per sample'
|
|
case 'multibar':
|
|
return 'Grouped bars — compare dimensions side by side'
|
|
case 'pie':
|
|
return 'Snapshot share — latest values as a whole'
|
|
default:
|
|
return 'Lines over time — independent series'
|
|
}
|
|
}
|