orbital-ds 0.9.0 → 0.10.0
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/AGENTS.md +18 -1
- package/components.manifest.json +388 -1
- package/contract.json +5 -0
- package/dist/hooks/use-ds-messages.d.ts +59 -1
- package/dist/hooks/use-ds-messages.js +6 -0
- package/dist/lib/echarts-presets.d.ts +153 -0
- package/dist/lib/echarts-presets.js +311 -0
- package/dist/lib/echarts-server.d.ts +15 -0
- package/dist/lib/echarts-server.js +15 -0
- package/dist/lib/echarts-setup.d.ts +4 -0
- package/dist/lib/echarts-setup.js +60 -0
- package/dist/lib/echarts-theme.d.ts +36 -0
- package/dist/lib/echarts-theme.js +142 -0
- package/dist/lib/i18n.d.ts +57 -1
- package/dist/lib/i18n.js +169 -3
- package/dist/styles.css +43 -5
- package/dist/themes/friendly.css +3 -1
- package/dist/themes/friendly.scoped.css +3 -1
- package/dist/themes/friendly.tokens.json +45 -0
- package/dist/themes/qratia.tokens.json +49 -0
- package/dist/themes/tactile.css +3 -1
- package/dist/themes/tactile.scoped.css +3 -1
- package/dist/themes/tactile.tokens.json +42 -0
- package/dist/themes/twitter.css +3 -1
- package/dist/themes/twitter.scoped.css +3 -1
- package/dist/themes/twitter.tokens.json +45 -0
- package/dist/themes/zyro.css +3 -1
- package/dist/themes/zyro.scoped.css +3 -1
- package/dist/themes/zyro.tokens.json +46 -0
- package/dist/ui/calendar.js +4 -0
- package/dist/ui/code-block.d.ts +14 -0
- package/dist/ui/code-block.js +106 -0
- package/dist/ui/data-table.d.ts +185 -0
- package/dist/ui/data-table.js +714 -0
- package/dist/ui/date-picker.d.ts +65 -0
- package/dist/ui/date-picker.js +362 -0
- package/dist/ui/dropzone.d.ts +42 -0
- package/dist/ui/dropzone.js +220 -0
- package/dist/ui/echart.d.ts +31 -0
- package/dist/ui/echart.js +88 -0
- package/dist/ui/eyebrow.d.ts +7 -0
- package/dist/ui/eyebrow.js +16 -0
- package/dist/ui/filter-bar.d.ts +36 -0
- package/dist/ui/filter-bar.js +193 -0
- package/dist/ui/heatmap-grid.d.ts +39 -0
- package/dist/ui/heatmap-grid.js +195 -0
- package/dist/ui/i18n-provider.js +3 -3
- package/dist/ui/legend.d.ts +30 -0
- package/dist/ui/legend.js +124 -0
- package/dist/ui/notifications.d.ts +69 -0
- package/dist/ui/notifications.js +335 -0
- package/dist/ui/page-header.d.ts +19 -0
- package/dist/ui/page-header.js +132 -0
- package/dist/ui/panel.d.ts +12 -0
- package/dist/ui/panel.js +41 -0
- package/dist/ui/proportion-bar.d.ts +27 -0
- package/dist/ui/proportion-bar.js +92 -0
- package/dist/ui/sparkline.d.ts +26 -0
- package/dist/ui/sparkline.js +97 -0
- package/dist/ui/stat.d.ts +61 -0
- package/dist/ui/stat.js +238 -0
- package/dist/ui/status-badge.d.ts +38 -0
- package/dist/ui/status-badge.js +153 -0
- package/dist/ui/stepper.d.ts +20 -0
- package/dist/ui/stepper.js +152 -0
- package/dist/ui/timeline.d.ts +29 -0
- package/dist/ui/timeline.js +157 -0
- package/docs/GRAFICOS.md +125 -0
- package/docs/adr/0001-rtl-clases-logicas.md +78 -0
- package/package.json +171 -160
- package/scripts/doctor.mjs +0 -0
- package/scripts/i18n.mjs +0 -0
- package/scripts/init.mjs +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { EChartsCoreOption } from 'echarts/core';
|
|
2
|
+
|
|
3
|
+
/** Valor de una serie: `null` = sin dato (hueco), nunca 0. */
|
|
4
|
+
type DsChartValue = number | null;
|
|
5
|
+
interface DsSeries {
|
|
6
|
+
name: string;
|
|
7
|
+
data: DsChartValue[];
|
|
8
|
+
/** Grupo de apilado propio (si no, el de `stack` del constructor). */
|
|
9
|
+
stack?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Formatea un valor en el tooltip y las etiquetas (p. ej. con Intl.NumberFormat). */
|
|
12
|
+
type DsValueFormatter = (value: number) => string;
|
|
13
|
+
/** Línea o área de referencia (las crean `referenceLine` y `referenceArea`). */
|
|
14
|
+
type DsReference = {
|
|
15
|
+
kind: "line";
|
|
16
|
+
markLine: Record<string, unknown>;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "area";
|
|
19
|
+
markArea: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
type Obj = Record<string, unknown>;
|
|
22
|
+
interface CommonOptions {
|
|
23
|
+
/** Muestra la leyenda (por defecto, si hay más de una serie). */
|
|
24
|
+
legend?: boolean;
|
|
25
|
+
/** Formato de los valores (tooltip y ejes de valor). */
|
|
26
|
+
valueFormatter?: DsValueFormatter;
|
|
27
|
+
/** Opciones propias fusionadas por encima del resultado. */
|
|
28
|
+
extend?: Obj;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Línea de referencia (objetivo, umbral de SLA…). `axis` es el eje del VALOR: "y" en
|
|
32
|
+
* gráficos verticales (por defecto) y "x" en barras horizontales.
|
|
33
|
+
*/
|
|
34
|
+
declare function referenceLine(value: number, label?: string, { axis }?: {
|
|
35
|
+
axis?: "x" | "y";
|
|
36
|
+
}): DsReference;
|
|
37
|
+
/**
|
|
38
|
+
* Banda de referencia entre dos valores (franja horaria, zona de alerta…). Con `axis: "x"`
|
|
39
|
+
* acepta categorías del eje X (p. ej. "08:00" → "15:00"); con "y", valores.
|
|
40
|
+
*/
|
|
41
|
+
declare function referenceArea(from: number | string, to: number | string, label?: string, { axis }?: {
|
|
42
|
+
axis?: "x" | "y";
|
|
43
|
+
}): DsReference;
|
|
44
|
+
/**
|
|
45
|
+
* Escapa texto para HTML. Un `formatter` de tooltip que devuelve una cadena se pinta COMO
|
|
46
|
+
* HTML: todo lo interpolado (categorías, nombres de serie, etiquetas, valores formateados)
|
|
47
|
+
* puede venir de datos de usuario y debe pasar por aquí. El tooltip por defecto de ECharts
|
|
48
|
+
* (nombres y `valueFormatter`) ya escapa; las etiquetas de serie, markLine y markArea son
|
|
49
|
+
* texto del lienzo/SVG, no HTML.
|
|
50
|
+
*/
|
|
51
|
+
declare function escapeHtml(value: unknown): string;
|
|
52
|
+
interface LineOptionInput extends CommonOptions {
|
|
53
|
+
categories: Array<string | number>;
|
|
54
|
+
series: DsSeries[];
|
|
55
|
+
/** Rellena el área bajo cada línea. */
|
|
56
|
+
area?: boolean;
|
|
57
|
+
/** Apila las series (true = un solo grupo, o el nombre del grupo). */
|
|
58
|
+
stack?: boolean | string;
|
|
59
|
+
smooth?: boolean;
|
|
60
|
+
/** Sin puntos en la línea (series largas). */
|
|
61
|
+
showSymbols?: boolean;
|
|
62
|
+
/** Une los huecos (`null`) en lugar de cortar la línea. */
|
|
63
|
+
connectNulls?: boolean;
|
|
64
|
+
references?: DsReference[];
|
|
65
|
+
yName?: string;
|
|
66
|
+
/** Activa el zoom horizontal con la rueda y el arrastre. */
|
|
67
|
+
zoom?: boolean;
|
|
68
|
+
}
|
|
69
|
+
declare function lineOption(input: LineOptionInput): EChartsCoreOption;
|
|
70
|
+
interface BarOptionInput extends CommonOptions {
|
|
71
|
+
categories: Array<string | number>;
|
|
72
|
+
series: DsSeries[];
|
|
73
|
+
/** Barras horizontales (categorías en el eje Y). */
|
|
74
|
+
horizontal?: boolean;
|
|
75
|
+
stack?: boolean | string;
|
|
76
|
+
/**
|
|
77
|
+
* Ranking: ordena la PRIMERA serie de mayor a menor (horizontal por defecto, la mayor
|
|
78
|
+
* arriba) y reordena las demás igual.
|
|
79
|
+
*/
|
|
80
|
+
ranking?: boolean;
|
|
81
|
+
/** Etiqueta con el valor al final de cada barra. */
|
|
82
|
+
showLabels?: boolean;
|
|
83
|
+
references?: DsReference[];
|
|
84
|
+
}
|
|
85
|
+
declare function barOption(input: BarOptionInput): EChartsCoreOption;
|
|
86
|
+
interface ComboOptionInput extends Omit<CommonOptions, "valueFormatter"> {
|
|
87
|
+
categories: Array<string | number>;
|
|
88
|
+
/** Series de barras (eje izquierdo/inicial). */
|
|
89
|
+
bars: DsSeries[];
|
|
90
|
+
/** Series de línea (eje derecho/final). */
|
|
91
|
+
lines: DsSeries[];
|
|
92
|
+
barAxisName?: string;
|
|
93
|
+
lineAxisName?: string;
|
|
94
|
+
barFormatter?: DsValueFormatter;
|
|
95
|
+
lineFormatter?: DsValueFormatter;
|
|
96
|
+
stackBars?: boolean;
|
|
97
|
+
smooth?: boolean;
|
|
98
|
+
/** Referencias sobre el eje de las líneas (p. ej. objetivo de SLA). */
|
|
99
|
+
references?: DsReference[];
|
|
100
|
+
}
|
|
101
|
+
declare function comboOption(input: ComboOptionInput): EChartsCoreOption;
|
|
102
|
+
interface HeatmapOptionInput extends CommonOptions {
|
|
103
|
+
/** Columnas (p. ej. horas "00"…"23"). */
|
|
104
|
+
xCategories: Array<string | number>;
|
|
105
|
+
/** Filas (p. ej. días "Lun"…"Dom"). */
|
|
106
|
+
yCategories: Array<string | number>;
|
|
107
|
+
/** Matriz [fila][columna]; `null` = sin dato (celda vacía, nunca 0). */
|
|
108
|
+
values: DsChartValue[][];
|
|
109
|
+
min?: number;
|
|
110
|
+
max?: number;
|
|
111
|
+
/** Muestra el valor en cada celda. */
|
|
112
|
+
showLabels?: boolean;
|
|
113
|
+
/** Muestra el mapa visual (escala) bajo el gráfico. */
|
|
114
|
+
showScale?: boolean;
|
|
115
|
+
}
|
|
116
|
+
declare function heatmapOption(input: HeatmapOptionInput): EChartsCoreOption;
|
|
117
|
+
interface SankeyLink {
|
|
118
|
+
source: string;
|
|
119
|
+
target: string;
|
|
120
|
+
value: number;
|
|
121
|
+
}
|
|
122
|
+
interface SankeyOptionInput extends CommonOptions {
|
|
123
|
+
/** Nodos (si se omiten, salen de los enlaces). */
|
|
124
|
+
nodes?: string[];
|
|
125
|
+
links: SankeyLink[];
|
|
126
|
+
orient?: "horizontal" | "vertical";
|
|
127
|
+
}
|
|
128
|
+
declare function sankeyOption(input: SankeyOptionInput): EChartsCoreOption;
|
|
129
|
+
interface GaugeOptionInput extends Omit<CommonOptions, "legend"> {
|
|
130
|
+
value: number | null;
|
|
131
|
+
min?: number;
|
|
132
|
+
max?: number;
|
|
133
|
+
/** Nombre bajo la cifra (p. ej. "SLA"). */
|
|
134
|
+
name?: string;
|
|
135
|
+
/** Marcas del eje (por defecto, 5 tramos). */
|
|
136
|
+
splitNumber?: number;
|
|
137
|
+
}
|
|
138
|
+
declare function gaugeOption(input: GaugeOptionInput): EChartsCoreOption;
|
|
139
|
+
interface PieOptionInput extends CommonOptions {
|
|
140
|
+
data: Array<{
|
|
141
|
+
name: string;
|
|
142
|
+
value: number;
|
|
143
|
+
}>;
|
|
144
|
+
/** Donut (por defecto) o tarta llena. */
|
|
145
|
+
donut?: boolean;
|
|
146
|
+
/** Texto en el centro del donut (p. ej. el total). */
|
|
147
|
+
centerLabel?: string;
|
|
148
|
+
centerSubLabel?: string;
|
|
149
|
+
showLabels?: boolean;
|
|
150
|
+
}
|
|
151
|
+
declare function pieOption(input: PieOptionInput): EChartsCoreOption;
|
|
152
|
+
|
|
153
|
+
export { type BarOptionInput, type ComboOptionInput, type DsChartValue, type DsReference, type DsSeries, type DsValueFormatter, type GaugeOptionInput, type HeatmapOptionInput, type LineOptionInput, type PieOptionInput, type SankeyLink, type SankeyOptionInput, barOption, comboOption, escapeHtml, gaugeOption, heatmapOption, lineOption, pieOption, referenceArea, referenceLine, sankeyOption };
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
function referenceLine(value, label, { axis = "y" } = {}) {
|
|
2
|
+
return {
|
|
3
|
+
kind: "line",
|
|
4
|
+
markLine: {
|
|
5
|
+
silent: true,
|
|
6
|
+
symbol: "none",
|
|
7
|
+
lineStyle: { type: "dashed" },
|
|
8
|
+
label: { show: Boolean(label), formatter: () => label ?? "", position: "insideEndTop" },
|
|
9
|
+
data: [{ [axis === "y" ? "yAxis" : "xAxis"]: value, name: label }]
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function referenceArea(from, to, label, { axis = typeof from === "string" ? "x" : "y" } = {}) {
|
|
14
|
+
const key = axis === "y" ? "yAxis" : "xAxis";
|
|
15
|
+
return {
|
|
16
|
+
kind: "area",
|
|
17
|
+
markArea: {
|
|
18
|
+
silent: true,
|
|
19
|
+
label: { show: Boolean(label), formatter: () => label ?? "", position: "insideTop" },
|
|
20
|
+
data: [[{ [key]: from, name: label }, { [key]: to }]]
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function withReferences(series, refs) {
|
|
25
|
+
if (!refs?.length) return series;
|
|
26
|
+
const lines = refs.filter((r) => r.kind === "line");
|
|
27
|
+
const areas = refs.filter((r) => r.kind === "area");
|
|
28
|
+
const out = { ...series };
|
|
29
|
+
if (lines.length) {
|
|
30
|
+
out.markLine = {
|
|
31
|
+
...lines[0].markLine,
|
|
32
|
+
data: lines.flatMap((l) => l.markLine.data.map((d) => ({ ...d, label: l.markLine.label })))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (areas.length) {
|
|
36
|
+
out.markArea = {
|
|
37
|
+
...areas[0].markArea,
|
|
38
|
+
data: areas.flatMap(
|
|
39
|
+
(a) => a.markArea.data.map(([start, end]) => [{ ...start, label: a.markArea.label }, end])
|
|
40
|
+
)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function escapeHtml(value) {
|
|
46
|
+
return String(value ?? "").replace(/[&<>"']/g, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ch]);
|
|
47
|
+
}
|
|
48
|
+
function tooltip(trigger, valueFormatter, extra = {}) {
|
|
49
|
+
return {
|
|
50
|
+
trigger,
|
|
51
|
+
...valueFormatter ? { valueFormatter: (v) => typeof v === "number" ? valueFormatter(v) : String(v ?? "\u2013") } : {},
|
|
52
|
+
...extra
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function legend(show, count) {
|
|
56
|
+
return { show: show ?? count > 1, top: 0, type: "scroll" };
|
|
57
|
+
}
|
|
58
|
+
function valueAxis(valueFormatter, extra = {}) {
|
|
59
|
+
return {
|
|
60
|
+
type: "value",
|
|
61
|
+
...valueFormatter ? { axisLabel: { formatter: (v) => valueFormatter(v) } } : {},
|
|
62
|
+
...extra
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function finish(option, extend) {
|
|
66
|
+
return { aria: { enabled: true }, ...option, ...extend };
|
|
67
|
+
}
|
|
68
|
+
function lineOption(input) {
|
|
69
|
+
const { categories, series, area = false, stack, smooth = false, showSymbols = true, connectNulls = false } = input;
|
|
70
|
+
const group = stack === true ? "total" : stack || void 0;
|
|
71
|
+
return finish(
|
|
72
|
+
{
|
|
73
|
+
tooltip: tooltip("axis", input.valueFormatter),
|
|
74
|
+
legend: legend(input.legend, series.length),
|
|
75
|
+
xAxis: { type: "category", data: categories, boundaryGap: false },
|
|
76
|
+
yAxis: valueAxis(input.valueFormatter, input.yName ? { name: input.yName } : {}),
|
|
77
|
+
...input.zoom ? { dataZoom: [{ type: "inside" }] } : {},
|
|
78
|
+
series: series.map(
|
|
79
|
+
(s, i) => withReferences(
|
|
80
|
+
{
|
|
81
|
+
type: "line",
|
|
82
|
+
name: s.name,
|
|
83
|
+
data: s.data,
|
|
84
|
+
smooth,
|
|
85
|
+
showSymbol: showSymbols,
|
|
86
|
+
connectNulls,
|
|
87
|
+
...s.stack || group ? { stack: s.stack ?? group } : {},
|
|
88
|
+
...area ? { areaStyle: { opacity: group ? 0.6 : 0.15 } } : {},
|
|
89
|
+
emphasis: { focus: "series" }
|
|
90
|
+
},
|
|
91
|
+
i === 0 ? input.references : void 0
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
},
|
|
95
|
+
input.extend
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
function barOption(input) {
|
|
99
|
+
const horizontal = input.horizontal ?? Boolean(input.ranking);
|
|
100
|
+
const group = input.stack === true ? "total" : input.stack || void 0;
|
|
101
|
+
let categories = input.categories;
|
|
102
|
+
let series = input.series;
|
|
103
|
+
if (input.ranking && series.length) {
|
|
104
|
+
const order = categories.map((_, i) => i).sort((a, b) => (series[0].data[b] ?? -Infinity) - (series[0].data[a] ?? -Infinity));
|
|
105
|
+
categories = order.map((i) => input.categories[i]);
|
|
106
|
+
series = series.map((s) => ({ ...s, data: order.map((i) => s.data[i] ?? null) }));
|
|
107
|
+
}
|
|
108
|
+
const category = { type: "category", data: categories, ...horizontal ? { inverse: true } : {} };
|
|
109
|
+
const value = valueAxis(input.valueFormatter);
|
|
110
|
+
const fmt = input.valueFormatter;
|
|
111
|
+
return finish(
|
|
112
|
+
{
|
|
113
|
+
tooltip: tooltip("axis", fmt, { axisPointer: { type: "shadow" } }),
|
|
114
|
+
legend: legend(input.legend, series.length),
|
|
115
|
+
xAxis: horizontal ? value : category,
|
|
116
|
+
yAxis: horizontal ? category : value,
|
|
117
|
+
series: series.map(
|
|
118
|
+
(s, i) => withReferences(
|
|
119
|
+
{
|
|
120
|
+
type: "bar",
|
|
121
|
+
name: s.name,
|
|
122
|
+
data: s.data,
|
|
123
|
+
...s.stack || group ? { stack: s.stack ?? group } : {},
|
|
124
|
+
...input.showLabels ? {
|
|
125
|
+
label: {
|
|
126
|
+
show: true,
|
|
127
|
+
position: group ? "inside" : horizontal ? "right" : "top",
|
|
128
|
+
...fmt ? { formatter: (p) => typeof p.value === "number" ? fmt(p.value) : "" } : {}
|
|
129
|
+
}
|
|
130
|
+
} : {},
|
|
131
|
+
emphasis: { focus: "series" }
|
|
132
|
+
},
|
|
133
|
+
i === 0 ? input.references : void 0
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
},
|
|
137
|
+
input.extend
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
function comboOption(input) {
|
|
141
|
+
const { barFormatter, lineFormatter } = input;
|
|
142
|
+
const fmtFor = (axis) => axis === 0 ? barFormatter : lineFormatter;
|
|
143
|
+
return finish(
|
|
144
|
+
{
|
|
145
|
+
tooltip: tooltip("axis", void 0, { axisPointer: { type: "cross" } }),
|
|
146
|
+
legend: legend(input.legend, input.bars.length + input.lines.length),
|
|
147
|
+
xAxis: { type: "category", data: input.categories },
|
|
148
|
+
yAxis: [
|
|
149
|
+
valueAxis(barFormatter, input.barAxisName ? { name: input.barAxisName } : {}),
|
|
150
|
+
valueAxis(lineFormatter, { ...input.lineAxisName ? { name: input.lineAxisName } : {}, splitLine: { show: false } })
|
|
151
|
+
],
|
|
152
|
+
series: [
|
|
153
|
+
...input.bars.map((s) => ({
|
|
154
|
+
type: "bar",
|
|
155
|
+
name: s.name,
|
|
156
|
+
data: s.data,
|
|
157
|
+
yAxisIndex: 0,
|
|
158
|
+
...input.stackBars || s.stack ? { stack: s.stack ?? "bars" } : {},
|
|
159
|
+
...fmtFor(0) ? { tooltip: { valueFormatter: (v) => typeof v === "number" ? fmtFor(0)(v) : "\u2013" } } : {}
|
|
160
|
+
})),
|
|
161
|
+
...input.lines.map(
|
|
162
|
+
(s, i) => withReferences(
|
|
163
|
+
{
|
|
164
|
+
type: "line",
|
|
165
|
+
name: s.name,
|
|
166
|
+
data: s.data,
|
|
167
|
+
yAxisIndex: 1,
|
|
168
|
+
smooth: input.smooth ?? false,
|
|
169
|
+
...fmtFor(1) ? { tooltip: { valueFormatter: (v) => typeof v === "number" ? fmtFor(1)(v) : "\u2013" } } : {}
|
|
170
|
+
},
|
|
171
|
+
i === 0 ? input.references : void 0
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
input.extend
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
function heatmapOption(input) {
|
|
180
|
+
const data = [];
|
|
181
|
+
const nums = [];
|
|
182
|
+
input.values.forEach(
|
|
183
|
+
(row, y) => row.forEach((v, x) => {
|
|
184
|
+
data.push([x, y, v ?? "-"]);
|
|
185
|
+
if (v != null) nums.push(v);
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
const min = input.min ?? (nums.length ? Math.min(...nums) : 0);
|
|
189
|
+
const max = input.max ?? (nums.length ? Math.max(...nums) : 1);
|
|
190
|
+
const showScale = input.showScale ?? true;
|
|
191
|
+
const fmt = input.valueFormatter;
|
|
192
|
+
return finish(
|
|
193
|
+
{
|
|
194
|
+
tooltip: tooltip("item", void 0, {
|
|
195
|
+
formatter: (p) => {
|
|
196
|
+
const [x, y, v] = p.value;
|
|
197
|
+
const shown = typeof v === "number" ? fmt ? fmt(v) : v : "\u2013";
|
|
198
|
+
return `${escapeHtml(input.yCategories[y])} \xB7 ${escapeHtml(input.xCategories[x])}: ${escapeHtml(shown)}`;
|
|
199
|
+
}
|
|
200
|
+
}),
|
|
201
|
+
grid: { top: 8, bottom: showScale ? 56 : 8 },
|
|
202
|
+
xAxis: { type: "category", data: input.xCategories, splitArea: { show: true } },
|
|
203
|
+
yAxis: { type: "category", data: input.yCategories, inverse: true, splitArea: { show: true } },
|
|
204
|
+
visualMap: {
|
|
205
|
+
show: showScale,
|
|
206
|
+
min,
|
|
207
|
+
max,
|
|
208
|
+
calculable: true,
|
|
209
|
+
orient: "horizontal",
|
|
210
|
+
left: "center",
|
|
211
|
+
bottom: 0,
|
|
212
|
+
...fmt ? { formatter: (v) => fmt(v) } : {}
|
|
213
|
+
},
|
|
214
|
+
series: [
|
|
215
|
+
{
|
|
216
|
+
type: "heatmap",
|
|
217
|
+
data,
|
|
218
|
+
label: { show: Boolean(input.showLabels) },
|
|
219
|
+
emphasis: { itemStyle: { borderWidth: 1 } }
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
input.extend
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function sankeyOption(input) {
|
|
227
|
+
const names = input.nodes ?? [...new Set(input.links.flatMap((l) => [l.source, l.target]))];
|
|
228
|
+
return finish(
|
|
229
|
+
{
|
|
230
|
+
tooltip: tooltip("item", input.valueFormatter),
|
|
231
|
+
series: [
|
|
232
|
+
{
|
|
233
|
+
type: "sankey",
|
|
234
|
+
orient: input.orient ?? "horizontal",
|
|
235
|
+
data: names.map((name) => ({ name })),
|
|
236
|
+
links: input.links,
|
|
237
|
+
emphasis: { focus: "adjacency" },
|
|
238
|
+
nodeAlign: "justify",
|
|
239
|
+
draggable: false
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
input.extend
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
function gaugeOption(input) {
|
|
247
|
+
const fmt = input.valueFormatter;
|
|
248
|
+
return finish(
|
|
249
|
+
{
|
|
250
|
+
series: [
|
|
251
|
+
{
|
|
252
|
+
type: "gauge",
|
|
253
|
+
min: input.min ?? 0,
|
|
254
|
+
max: input.max ?? 100,
|
|
255
|
+
splitNumber: input.splitNumber ?? 5,
|
|
256
|
+
startAngle: 210,
|
|
257
|
+
endAngle: -30,
|
|
258
|
+
progress: { show: true, roundCap: true },
|
|
259
|
+
pointer: { show: false },
|
|
260
|
+
axisTick: { show: false },
|
|
261
|
+
splitLine: { show: false },
|
|
262
|
+
axisLabel: { show: false },
|
|
263
|
+
anchor: { show: false },
|
|
264
|
+
title: { show: Boolean(input.name), offsetCenter: [0, "30%"] },
|
|
265
|
+
detail: {
|
|
266
|
+
valueAnimation: true,
|
|
267
|
+
offsetCenter: [0, "-5%"],
|
|
268
|
+
formatter: (v) => input.value == null ? "\u2013" : fmt ? fmt(v) : String(v)
|
|
269
|
+
},
|
|
270
|
+
data: [{ value: input.value ?? 0, name: input.name ?? "" }]
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
input.extend
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
function pieOption(input) {
|
|
278
|
+
const donut = input.donut ?? true;
|
|
279
|
+
return finish(
|
|
280
|
+
{
|
|
281
|
+
tooltip: tooltip("item", input.valueFormatter),
|
|
282
|
+
legend: { ...legend(input.legend ?? true, input.data.length), top: void 0, bottom: 0 },
|
|
283
|
+
...donut && input.centerLabel ? { title: { text: input.centerLabel, subtext: input.centerSubLabel, left: "center", top: "middle", itemGap: 4 } } : {},
|
|
284
|
+
series: [
|
|
285
|
+
{
|
|
286
|
+
type: "pie",
|
|
287
|
+
radius: donut ? ["55%", "75%"] : "75%",
|
|
288
|
+
center: ["50%", "48%"],
|
|
289
|
+
avoidLabelOverlap: true,
|
|
290
|
+
label: { show: Boolean(input.showLabels) },
|
|
291
|
+
labelLine: { show: Boolean(input.showLabels) },
|
|
292
|
+
emphasis: { scale: true },
|
|
293
|
+
data: input.data
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
input.extend
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
export {
|
|
301
|
+
barOption,
|
|
302
|
+
comboOption,
|
|
303
|
+
escapeHtml,
|
|
304
|
+
gaugeOption,
|
|
305
|
+
heatmapOption,
|
|
306
|
+
lineOption,
|
|
307
|
+
pieOption,
|
|
308
|
+
referenceArea,
|
|
309
|
+
referenceLine,
|
|
310
|
+
sankeyOption
|
|
311
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EChartsCoreOption } from 'echarts/core';
|
|
2
|
+
import { DsChartTokens, DsEchartsTheme } from './echarts-theme.js';
|
|
3
|
+
|
|
4
|
+
interface RenderEChartOptions {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
/** Valores del tema (piel `light` o `dark` de `<tema>.tokens.json`), o un tema ya montado. */
|
|
8
|
+
tokens?: DsChartTokens;
|
|
9
|
+
theme?: DsEchartsTheme;
|
|
10
|
+
/** Sin animación por defecto: en un documento no se ve. */
|
|
11
|
+
animation?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare function renderEChartToSvg(option: EChartsCoreOption, { width, height, tokens, theme, animation }: RenderEChartOptions): string;
|
|
14
|
+
|
|
15
|
+
export { type RenderEChartOptions, renderEChartToSvg };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { echarts } from "./echarts-setup";
|
|
2
|
+
import { dsEchartsThemeFromTokens } from "./echarts-theme";
|
|
3
|
+
function renderEChartToSvg(option, { width, height, tokens, theme, animation = false }) {
|
|
4
|
+
const tema = theme ?? (tokens ? dsEchartsThemeFromTokens(tokens, { reducedMotion: !animation }) : void 0);
|
|
5
|
+
const chart = echarts.init(null, tema, { renderer: "svg", ssr: true, width, height });
|
|
6
|
+
try {
|
|
7
|
+
chart.setOption({ animation, ...option });
|
|
8
|
+
return chart.renderToSVGString();
|
|
9
|
+
} finally {
|
|
10
|
+
chart.dispose();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
renderEChartToSvg
|
|
15
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BarChart,
|
|
3
|
+
FunnelChart,
|
|
4
|
+
GaugeChart,
|
|
5
|
+
HeatmapChart,
|
|
6
|
+
LineChart,
|
|
7
|
+
PieChart,
|
|
8
|
+
RadarChart,
|
|
9
|
+
SankeyChart,
|
|
10
|
+
ScatterChart
|
|
11
|
+
} from "echarts/charts";
|
|
12
|
+
import {
|
|
13
|
+
AriaComponent,
|
|
14
|
+
DatasetComponent,
|
|
15
|
+
DataZoomComponent,
|
|
16
|
+
GraphicComponent,
|
|
17
|
+
GridComponent,
|
|
18
|
+
LegendComponent,
|
|
19
|
+
MarkAreaComponent,
|
|
20
|
+
MarkLineComponent,
|
|
21
|
+
MarkPointComponent,
|
|
22
|
+
TitleComponent,
|
|
23
|
+
TooltipComponent,
|
|
24
|
+
TransformComponent,
|
|
25
|
+
VisualMapComponent
|
|
26
|
+
} from "echarts/components";
|
|
27
|
+
import * as echarts from "echarts/core";
|
|
28
|
+
import { LabelLayout, UniversalTransition } from "echarts/features";
|
|
29
|
+
import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
|
|
30
|
+
echarts.use([
|
|
31
|
+
BarChart,
|
|
32
|
+
FunnelChart,
|
|
33
|
+
GaugeChart,
|
|
34
|
+
HeatmapChart,
|
|
35
|
+
LineChart,
|
|
36
|
+
PieChart,
|
|
37
|
+
RadarChart,
|
|
38
|
+
SankeyChart,
|
|
39
|
+
ScatterChart,
|
|
40
|
+
AriaComponent,
|
|
41
|
+
DatasetComponent,
|
|
42
|
+
DataZoomComponent,
|
|
43
|
+
GraphicComponent,
|
|
44
|
+
GridComponent,
|
|
45
|
+
LegendComponent,
|
|
46
|
+
MarkAreaComponent,
|
|
47
|
+
MarkLineComponent,
|
|
48
|
+
MarkPointComponent,
|
|
49
|
+
TitleComponent,
|
|
50
|
+
TooltipComponent,
|
|
51
|
+
TransformComponent,
|
|
52
|
+
VisualMapComponent,
|
|
53
|
+
LabelLayout,
|
|
54
|
+
UniversalTransition,
|
|
55
|
+
CanvasRenderer,
|
|
56
|
+
SVGRenderer
|
|
57
|
+
]);
|
|
58
|
+
export {
|
|
59
|
+
echarts
|
|
60
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Valores de un tema que necesita un gráfico (lo que trae `<tema>.tokens.json`). */
|
|
2
|
+
interface DsChartTokens {
|
|
3
|
+
palette: string[];
|
|
4
|
+
foreground: string;
|
|
5
|
+
muted: string;
|
|
6
|
+
border: string;
|
|
7
|
+
surface: string;
|
|
8
|
+
surfaceForeground: string;
|
|
9
|
+
fontSans: string;
|
|
10
|
+
fontDisplay: string;
|
|
11
|
+
motionBaseMs: number;
|
|
12
|
+
motionSlowMs: number;
|
|
13
|
+
}
|
|
14
|
+
interface DsEchartsTheme {
|
|
15
|
+
color: string[];
|
|
16
|
+
backgroundColor: string;
|
|
17
|
+
textStyle: {
|
|
18
|
+
fontFamily: string;
|
|
19
|
+
color: string;
|
|
20
|
+
};
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** Color CSS cualquiera (oklch, color-mix…) → `rgba(r, g, b, a)`. Fuera del navegador lo devuelve tal cual. */
|
|
24
|
+
declare function dsResolveColor(value: string): string;
|
|
25
|
+
/** Lee del navegador los valores del tema ACTIVO (con la marca de la app). */
|
|
26
|
+
declare function dsChartTokens(el?: Element): DsChartTokens;
|
|
27
|
+
/** Paleta de series del tema activo, en RGB. */
|
|
28
|
+
declare function dsChartPalette(el?: Element): string[];
|
|
29
|
+
/** Tema de ECharts a partir de los valores de un tema (navegador o servidor). */
|
|
30
|
+
declare function dsEchartsThemeFromTokens(t: DsChartTokens, { reducedMotion }?: {
|
|
31
|
+
reducedMotion?: boolean | undefined;
|
|
32
|
+
}): DsEchartsTheme;
|
|
33
|
+
/** Tema de ECharts para el tema ACTIVO en el navegador. */
|
|
34
|
+
declare function dsEchartsTheme(el?: Element): DsEchartsTheme;
|
|
35
|
+
|
|
36
|
+
export { type DsChartTokens, type DsEchartsTheme, dsChartPalette, dsChartTokens, dsEchartsTheme, dsEchartsThemeFromTokens, dsResolveColor };
|