@visionaris-bruno/vs-echarts 8.4.2 → 8.5.1

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.
@@ -4,12 +4,13 @@ import { BarChart, PieChart, LineChart, ScatterChart, FunnelChart, SunburstChart
4
4
  import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GraphicComponent, ToolboxComponent, PolarComponent, DatasetComponent, DataZoomComponent } from 'echarts/components';
5
5
  import { CanvasRenderer, SVGRenderer } from 'echarts/renderers';
6
6
  import * as i0 from '@angular/core';
7
- import { EventEmitter, Output, Input, ViewChild, Directive, Component } from '@angular/core';
7
+ import { EventEmitter, Output, Input, ViewChild, Directive, inject, Component } from '@angular/core';
8
8
  import { ReplaySubject } from 'rxjs';
9
9
  import { debounceTime } from 'rxjs/operators';
10
10
  import merge from 'lodash/merge';
11
11
  import { CommonModule } from '@angular/common';
12
12
  import { merge as merge$1 } from 'lodash';
13
+ import { TranslateService } from '@ngx-translate/core';
13
14
 
14
15
  /**
15
16
  * Global Design Tokens for ECharts
@@ -188,11 +189,11 @@ class BaseEchartsComponent {
188
189
  data = { dimensions: [], source: [] };
189
190
  optionsOverrides = defaultOptionsOverrides();
190
191
  /** Paleta de colores básica */
191
- palette = getDefaultPalette();
192
+ palette;
192
193
  /** Resolver de colores dinámico (Callback) */
193
194
  colorResolver;
194
195
  /** Formateador de valores para etiquetas y tooltips */
195
- valueFormatter = (value) => value.toLocaleString();
196
+ valueFormatter;
196
197
  chartClick = new EventEmitter();
197
198
  /** Subject para debouncing de actualizaciones. ReplaySubject asegura no perder el primer renderizado. */
198
199
  updateSubject = new ReplaySubject(1);
@@ -933,6 +934,7 @@ class RingBuilder {
933
934
 
934
935
  class BoxPlotBuilder {
935
936
  baseProduct;
937
+ translateService;
936
938
  valueFormatter = (value, key) => value.toLocaleString();
937
939
  palette = [];
938
940
  // TODO: Hay que implementar un valor por defecto.
@@ -940,25 +942,24 @@ class BoxPlotBuilder {
940
942
  result = {};
941
943
  constructor(baseProduct) {
942
944
  this.baseProduct = baseProduct;
945
+ try {
946
+ this.translateService = inject(TranslateService);
947
+ }
948
+ catch {
949
+ // Ignored if called outside an injection context (e.g. unit tests)
950
+ }
943
951
  }
944
952
  reset() {
945
953
  this.result = {};
946
954
  }
947
955
  addDataset(data, opts) {
948
- const statisticKeys = {
949
- min: 'Min',
950
- q1: 'Q1',
951
- median: 'Median',
952
- q3: 'Q3',
953
- max: 'Max',
954
- };
955
956
  /**
956
957
  *
957
958
  * @param arr
958
959
  * @param statisticsKeys etiquetas personalizadas para los valores de estadistica.
959
960
  * @returns
960
961
  */
961
- function calcularResumen5Numeros(arr, statisticsKeys) {
962
+ function calcularResumen5Numeros(arr) {
962
963
  if (arr.length === 0)
963
964
  return null;
964
965
  // 1. Ordenar los números de menor a mayor
@@ -976,11 +977,11 @@ class BoxPlotBuilder {
976
977
  }
977
978
  };
978
979
  return {
979
- [statisticsKeys.min]: ordenados[0],
980
- [statisticsKeys.q1]: obtenerPercentil(0.25),
981
- [statisticsKeys.median]: obtenerPercentil(0.50),
982
- [statisticsKeys.q3]: obtenerPercentil(0.75),
983
- [statisticsKeys.max]: ordenados[ordenados.length - 1],
980
+ min: ordenados[0],
981
+ q1: obtenerPercentil(0.25),
982
+ median: obtenerPercentil(0.50),
983
+ q3: obtenerPercentil(0.75),
984
+ max: ordenados[ordenados.length - 1],
984
985
  };
985
986
  }
986
987
  ;
@@ -990,7 +991,7 @@ class BoxPlotBuilder {
990
991
  .filter(([key, val]) => key !== 'category' && !isNaN(val))
991
992
  .map(([_, val]) => Number(val));
992
993
  // resumen5NumerosXCat
993
- const resObj = Object.assign({ category: s.category }, calcularResumen5Numeros(values, statisticKeys));
994
+ const resObj = Object.assign({ category: s.category }, calcularResumen5Numeros(values));
994
995
  return resObj;
995
996
  });
996
997
  const dataset = [{
@@ -1032,17 +1033,31 @@ class BoxPlotBuilder {
1032
1033
  addTooltip(data, overrides) {
1033
1034
  const mainMeassureKey = data.dimensions.filter(d => d.name != 'category')[0].name;
1034
1035
  const valueFormatter = this.valueFormatter;
1036
+ const translate = (key, fallback) => {
1037
+ if (!this.translateService)
1038
+ return fallback;
1039
+ const res = this.translateService.instant(key);
1040
+ return res === key ? fallback : res;
1041
+ };
1042
+ const labelMap = {
1043
+ min: translate('VS_ECHARTS.BOXPLOT.MIN', 'Min'),
1044
+ q1: translate('VS_ECHARTS.BOXPLOT.Q1', 'Q1'),
1045
+ median: translate('VS_ECHARTS.BOXPLOT.MEDIAN', 'Median'),
1046
+ q3: translate('VS_ECHARTS.BOXPLOT.Q3', 'Q3'),
1047
+ max: translate('VS_ECHARTS.BOXPLOT.MAX', 'Max'),
1048
+ };
1035
1049
  function tooltipFormatter(params) {
1036
1050
  const tooltipEventData = Array.isArray(params) ? params[0] : params;
1037
1051
  const title = `<b>${tooltipEventData.name}</b></br>`;
1038
1052
  let htmlbody = ``;
1039
1053
  for (const datakey in tooltipEventData.data) {
1040
- const label = datakey;
1054
+ const rawLabel = datakey;
1041
1055
  const value = tooltipEventData.data[datakey];
1042
- if (label == 'category') {
1056
+ if (rawLabel == 'category') {
1043
1057
  continue;
1044
1058
  }
1045
1059
  ;
1060
+ const label = labelMap[rawLabel] || rawLabel;
1046
1061
  const formattedValue = valueFormatter(value, mainMeassureKey);
1047
1062
  const bodyText = `${tooltipEventData.marker}${label}: ${formattedValue}</br>`;
1048
1063
  htmlbody += bodyText;
@@ -1128,236 +1143,344 @@ class BoxPlotBuilder {
1128
1143
  }
1129
1144
 
1130
1145
  /**
1131
- * Builder principal.
1132
- *
1133
- * Es muy completo, tiene soporte para ejes y sistema cartesiano polar.
1134
- *
1135
- * Puede verse utilizado en graficos como Lineas y Bars. Siempre que se pueda priorizar utilizar este.
1146
+ * Director de Builds.
1136
1147
  */
1137
- class EChartBuilder {
1138
- baseProduct = undefined;
1139
- valueFormatter = (value) => value.toLocaleString();
1140
- palette = [];
1141
- // TODO: Hay que implementar un valor por defecto.
1142
- colorResolver;
1143
- result = {};
1144
- constructor(baseProduct) {
1145
- this.baseProduct = baseProduct;
1148
+ class VSECDirector {
1149
+ builder = undefined;
1150
+ constructor(builder) {
1151
+ this.builder = builder;
1146
1152
  }
1147
- reset() {
1148
- this.result = {};
1153
+ makeBar(data, overrides, opts = {}) {
1154
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1155
+ x: 'category',
1156
+ y: 'value',
1157
+ // TODO agregar radius y angle axis
1158
+ } } = opts;
1159
+ this.builder.reset();
1160
+ // El orden importa, primero callbaks y despues componentes.
1161
+ //chart callbacks
1162
+ this.builder.setValueFormatter(valueFormatter);
1163
+ this.builder.setPalette(palette);
1164
+ this.builder.setColorResolver(colorResolver);
1165
+ const product = this.builder.baseProduct;
1166
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1167
+ // chart components
1168
+ this.builder.addCommons();
1169
+ const layoutOpts = { axisTypes };
1170
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1171
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1172
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1173
+ this.builder.addTooltip(data, overrides.tooltip);
1174
+ this.builder.addLegend();
1149
1175
  }
1150
- addCommons() {
1151
- const opts = {
1152
- palette: this.palette,
1153
- };
1154
- merge$1(this.result, getCommons(opts));
1176
+ makeBarRadial(data, overrides, opts = {}) {
1177
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1178
+ x: 'category',
1179
+ y: 'value',
1180
+ // TODO agregar radius y angle axis
1181
+ } } = opts;
1182
+ this.builder.reset();
1183
+ // El orden importa, primero callbaks y despues componentes.
1184
+ //chart callbacks
1185
+ this.builder.setValueFormatter(valueFormatter);
1186
+ this.builder.setPalette(palette);
1187
+ this.builder.setColorResolver(colorResolver);
1188
+ const product = this.builder.baseProduct;
1189
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1190
+ // chart components
1191
+ this.builder.addCommons();
1192
+ const layoutOpts = { axisTypes, coordinateSystem: 'polar' };
1193
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1194
+ this.builder.addPolar();
1195
+ this.builder.addAngleAxis(data, overrides['axis']);
1196
+ this.builder.addRadiusAxis(data, overrides['axis']);
1197
+ this.builder.addTooltip(data, overrides.tooltip);
1198
+ this.builder.addLegend();
1155
1199
  }
1156
- /**
1157
- *
1158
- * @param data
1159
- * @param overrides
1160
- * @returns
1161
- */
1162
- addSeries(data, overrides, opts) {
1163
- if (!data || !data.dimensions || !data.source || data.source.length === 0)
1164
- return;
1165
- this.result.dataset = {
1166
- dimensions: data.dimensions,
1167
- source: data.source
1168
- };
1169
- const measureDims = data.dimensions.filter(d => d.name !== 'category');
1170
- const isPolar = opts?.coordinateSystem === 'polar';
1171
- const isHorizontal = opts?.axisTypes?.x === 'value' && opts?.axisTypes?.y === 'category';
1172
- const series = measureDims.map((dim) => {
1173
- const friendlyName = dim.displayName || dim.name;
1174
- const dimKey = dim.name;
1175
- let encode = {
1176
- x: 'category',
1177
- y: dimKey
1178
- };
1179
- if (isPolar) {
1180
- encode = {
1181
- angle: 'category',
1182
- radius: dimKey
1183
- };
1184
- }
1185
- else if (isHorizontal) {
1186
- encode = {
1187
- x: dimKey,
1188
- y: 'category'
1189
- };
1190
- }
1191
- const dynamicOverrides = {
1192
- name: friendlyName,
1193
- encode,
1194
- label: {
1195
- formatter: (params) => {
1196
- const row = params.value;
1197
- const rawValue = (row && typeof row === 'object') ? row[dimKey] : params.value;
1198
- return this.formatCellValue(Number(rawValue ?? 0), dimKey);
1199
- }
1200
- }
1201
- };
1202
- const seriesOption = merge$1(dynamicOverrides, overrides);
1203
- // Inyectar el resolver de color si existe
1204
- if (this.colorResolver && seriesOption.itemStyle) {
1205
- seriesOption.itemStyle.color = this.colorResolver;
1206
- }
1207
- return seriesOption;
1208
- });
1209
- this.result.series = series;
1200
+ makeLine(data, overrides, opts = {}) {
1201
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1202
+ x: 'category',
1203
+ y: 'value',
1204
+ // TODO agregar radius y angle axis
1205
+ } } = opts;
1206
+ this.builder.reset();
1207
+ // El orden importa, primero callbaks y despues componentes.
1208
+ //chart callbacks
1209
+ this.builder.setValueFormatter(valueFormatter);
1210
+ this.builder.setPalette(palette);
1211
+ this.builder.setColorResolver(colorResolver);
1212
+ const product = this.builder.baseProduct;
1213
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1214
+ // chart components
1215
+ this.builder.addCommons();
1216
+ const layoutOpts = { axisTypes };
1217
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1218
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1219
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1220
+ this.builder.addTooltip(data, overrides.tooltip);
1221
+ this.builder.addLegend();
1210
1222
  }
1211
- /**
1212
- * TODO: Mejorar funcion, no me convence como se implemento el tooltip formatter.
1213
- * @param data
1214
- * @param overrides
1215
- */
1216
- addTooltip(data, overrides) {
1217
- // inyecto formateador a overrides de tooltip
1218
- merge$1(overrides, {
1219
- formatter: getTooltipFormatter(overrides.trigger, data, this.formatCellValue.bind(this)),
1220
- });
1221
- const tooltip = getTooltipOptions(overrides);
1222
- this.result.tooltip = tooltip;
1223
+ makeScatter(data, overrides, opts = {}) {
1224
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1225
+ x: 'category',
1226
+ y: 'value',
1227
+ } } = opts;
1228
+ this.builder.reset();
1229
+ // El orden importa, primero callbacks y despues componentes.
1230
+ this.builder.setValueFormatter(valueFormatter);
1231
+ this.builder.setPalette(palette);
1232
+ this.builder.setColorResolver(colorResolver);
1233
+ const product = this.builder.baseProduct;
1234
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1235
+ // chart components
1236
+ this.builder.addCommons();
1237
+ const layoutOpts = { axisTypes };
1238
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1239
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1240
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1241
+ this.builder.addTooltip(data, overrides.tooltip);
1242
+ this.builder.addLegend();
1223
1243
  }
1224
- addPolar() {
1225
- const polar = [];
1226
- polar.push({
1227
- radius: '65%',
1228
- center: ["50%", "44%"],
1229
- });
1230
- this.result.polar = polar;
1244
+ makeRing(data, overrides, opts = {}) {
1245
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1246
+ this.builder.reset();
1247
+ // El orden importa, primero callbacks y despues componentes.
1248
+ this.builder.setValueFormatter(valueFormatter);
1249
+ this.builder.setPalette(palette);
1250
+ this.builder.setColorResolver(colorResolver);
1251
+ const product = this.builder.baseProduct;
1252
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1253
+ // chart components
1254
+ this.builder.addCommons();
1255
+ const layoutOpts = {};
1256
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1257
+ this.builder.addGraphic();
1258
+ this.builder.addTooltip(data, overrides.tooltip);
1259
+ this.builder.addLegend();
1231
1260
  }
1232
- addXAxis(data, overrides, type = 'category') {
1233
- const xAxis = [];
1234
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1235
- const valueAxisOptions = this.getValueAxisOptions(data, overrides);
1236
- if (type == 'category') {
1237
- xAxis.push(categoryAxisOptions);
1238
- }
1239
- else if (type == 'value') {
1240
- xAxis.push(valueAxisOptions);
1241
- }
1242
- this.result.xAxis = xAxis;
1261
+ makePie(data, overrides, opts = {}) {
1262
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1263
+ this.builder.reset();
1264
+ // El orden importa, primero callbacks y despues componentes.
1265
+ this.builder.setValueFormatter(valueFormatter);
1266
+ this.builder.setPalette(palette);
1267
+ this.builder.setColorResolver(colorResolver);
1268
+ const product = this.builder.baseProduct;
1269
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1270
+ // chart components
1271
+ this.builder.addCommons();
1272
+ const layoutOpts = {};
1273
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1274
+ this.builder.addTooltip(data, overrides.tooltip);
1275
+ this.builder.addLegend();
1243
1276
  }
1244
- addYAxis(data, overrides, type = 'value') {
1245
- const yAxis = [];
1246
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1247
- const valueAxisOptions = this.getValueAxisOptions(data, overrides);
1248
- if (type == 'category') {
1249
- yAxis.push(categoryAxisOptions);
1250
- }
1251
- else if (type == 'value') {
1252
- yAxis.push(valueAxisOptions);
1277
+ makeFunnel(data, overrides, opts = {}) {
1278
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1279
+ this.builder.reset();
1280
+ // El orden importa, primero callbacks y despues componentes.
1281
+ this.builder.setValueFormatter(valueFormatter);
1282
+ this.builder.setPalette(palette);
1283
+ this.builder.setColorResolver(colorResolver);
1284
+ const product = this.builder.baseProduct;
1285
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1286
+ // chart components
1287
+ this.builder.addCommons();
1288
+ const layoutOpts = {};
1289
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1290
+ this.builder.addTooltip(data, overrides.tooltip);
1291
+ this.builder.addLegend();
1292
+ }
1293
+ makeSunburst(data, overrides, opts = {}) {
1294
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1295
+ this.builder.reset();
1296
+ // El orden importa, primero callbacks y despues componentes.
1297
+ this.builder.setValueFormatter(valueFormatter);
1298
+ this.builder.setPalette(palette);
1299
+ this.builder.setColorResolver(colorResolver);
1300
+ const product = this.builder.baseProduct;
1301
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1302
+ // chart components
1303
+ this.builder.addCommons();
1304
+ const layoutOpts = {};
1305
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1306
+ this.builder.addTooltip(data, overrides.tooltip);
1307
+ // this.builder.addLegend();
1308
+ }
1309
+ makeSankey(data, overrides, opts = {}) {
1310
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1311
+ this.builder.reset();
1312
+ // El orden importa, primero callbacks y despues componentes.
1313
+ this.builder.setValueFormatter(valueFormatter);
1314
+ this.builder.setPalette(palette);
1315
+ this.builder.setColorResolver(colorResolver);
1316
+ const product = this.builder.baseProduct;
1317
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1318
+ // chart components
1319
+ this.builder.addCommons();
1320
+ const layoutOpts = {};
1321
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1322
+ this.builder.addTooltip(data, overrides.tooltip);
1323
+ }
1324
+ makeBoxplot(data, overrides, opts = {}) {
1325
+ if (this.builder instanceof BoxPlotBuilder == false) {
1326
+ return;
1253
1327
  }
1254
- this.result.yAxis = yAxis;
1328
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1329
+ x: 'value',
1330
+ y: 'category',
1331
+ }, } = opts;
1332
+ this.builder.reset();
1333
+ // El orden importa, primero callbacks y despues componentes.
1334
+ this.builder.setValueFormatter(valueFormatter);
1335
+ this.builder.setPalette(palette);
1336
+ this.builder.setColorResolver(colorResolver);
1337
+ const product = this.builder.baseProduct;
1338
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1339
+ // chart components
1340
+ this.builder.addCommons();
1341
+ const layoutOpts = { axisTypes };
1342
+ this.builder.addDataset(data);
1343
+ this.builder.addSeries(data, seriesOverrides, layoutOpts);
1344
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1345
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1346
+ this.builder.addTooltip(data, overrides.tooltip);
1347
+ this.builder.addDataZoom();
1255
1348
  }
1256
- addRadiusAxis(data, overrides) {
1257
- const radiusAxis = [];
1258
- /** estilos exclusivos hardcodeados para el eje de valores del sistema de coordenadas polar*/
1259
- const radiusAxisOverrides = {
1260
- zlevel: 10,
1261
- axisTick: {
1262
- show: false,
1263
- },
1264
- axisLabel: {
1265
- margin: 2,
1266
- fontSize: 8,
1267
- align: 'right',
1268
- rotate: 20,
1269
- verticalAlign: 'top',
1270
- },
1271
- splitLine: {
1272
- show: true,
1273
- lineStyle: {
1274
- opacity: 0.2,
1275
- type: 'solid',
1276
- }
1349
+ }
1350
+
1351
+ /**
1352
+ * EchartsRingComponent
1353
+ *
1354
+ * Especialista en visualización de tipo Ring. Soporta multi-medidas y KPI central.
1355
+ * @see {@link vs-echarts/docs/charts/ring-patterns.md}
1356
+ */
1357
+ class EchartsRingComponent extends BaseEchartsComponent {
1358
+ baseSeriesOptions = {
1359
+ type: 'pie',
1360
+ center: ['50%', '50%'],
1361
+ avoidLabelOverlap: true,
1362
+ minAngle: 3,
1363
+ selectedMode: 'single',
1364
+ selectedOffset: 4,
1365
+ itemStyle: {
1366
+ borderColor: '#fff',
1367
+ },
1368
+ label: { show: false },
1369
+ emphasis: {
1370
+ scale: true,
1371
+ scaleSize: 2,
1372
+ },
1373
+ select: {
1374
+ itemStyle: {
1375
+ borderColor: EChartsTokens.sBorderColor,
1376
+ shadowColor: EChartsTokens.sShadowColor,
1377
+ borderWidth: 1,
1378
+ shadowBlur: 4,
1277
1379
  },
1278
- axisLine: {
1279
- lineStyle: {
1280
- type: 'dashed',
1281
- },
1282
- }
1283
- };
1284
- const radialAxisOptions = getValueAxisOptions(radiusAxisOverrides);
1285
- radiusAxis.push(radialAxisOptions);
1286
- this.result.radiusAxis = radiusAxis;
1287
- }
1288
- addAngleAxis(data, overrides) {
1289
- const angleAxis = [];
1290
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1291
- angleAxis.push(categoryAxisOptions);
1292
- this.result.angleAxis = angleAxis;
1293
- }
1294
- addLegend() {
1295
- this.result.legend = getLegendOptions();
1380
+ },
1381
+ animationType: 'scale',
1382
+ animationEasing: 'elasticOut',
1383
+ };
1384
+ baseProduct = {
1385
+ chartKey: 'ring',
1386
+ baseOptions: {
1387
+ series: this.baseSeriesOptions,
1388
+ }
1389
+ };
1390
+ builder = new RingBuilder(this.baseProduct);
1391
+ director = new VSECDirector(this.builder);
1392
+ lastSelectedSeriesIndex = null;
1393
+ lastSelectedDataIndex = null;
1394
+ selectedPercent = null;
1395
+ currentGraphicText = '';
1396
+ constructor() {
1397
+ super();
1296
1398
  }
1297
- // No-ops for ring charts
1298
- addGraphic() { }
1299
- addDataset(data) { }
1300
- addDataZoom() {
1301
- this.result.dataZoom = [
1302
- {
1303
- type: 'inside'
1304
- },
1305
- {
1306
- type: 'slider',
1307
- height: 20,
1308
- bottom: 60
1309
- }
1310
- ];
1399
+ make() {
1400
+ const makeOpts = {
1401
+ valueFormatter: this.valueFormatter,
1402
+ palette: this.palette,
1403
+ colorResolver: this.colorResolver,
1404
+ };
1405
+ this.director.makeRing(this.data, this.optionsOverrides, makeOpts);
1311
1406
  }
1312
- getResult() {
1313
- return this.result;
1407
+ onInputChanges(changes) {
1408
+ // Reset selection only if data changed
1409
+ if (changes['data']) {
1410
+ this.lastSelectedSeriesIndex = null;
1411
+ this.lastSelectedDataIndex = null;
1412
+ this.selectedPercent = null;
1413
+ this.currentGraphicText = '';
1414
+ }
1415
+ super.onInputChanges(changes);
1314
1416
  }
1315
- ;
1316
1417
  /**
1317
- * Formatea un valor utilizando el callback inyectado.
1418
+ * Maneja clics en los sectores del ring.
1419
+ * Soporta múltiples series (anillos) y actualiza el KPI central.
1318
1420
  */
1319
- formatCellValue(value, key) {
1320
- return this.valueFormatter(value, key);
1421
+ onChartClick(event) {
1422
+ if (this.chartInstance && event && event.dataIndex !== undefined) {
1423
+ const isSameSelection = event.seriesIndex === this.lastSelectedSeriesIndex &&
1424
+ event.dataIndex === this.lastSelectedDataIndex;
1425
+ if (isSameSelection) {
1426
+ // Toggle OFF
1427
+ this.lastSelectedSeriesIndex = null;
1428
+ this.lastSelectedDataIndex = null;
1429
+ this.selectedPercent = null;
1430
+ this.setGraphicText('');
1431
+ }
1432
+ else {
1433
+ // SELECT
1434
+ this.lastSelectedSeriesIndex = event.seriesIndex;
1435
+ this.lastSelectedDataIndex = event.dataIndex;
1436
+ this.selectedPercent = (event.percent !== undefined) ? event.percent + '%' : '';
1437
+ this.setGraphicText(this.selectedPercent);
1438
+ }
1439
+ this.chartClick.emit({
1440
+ type: 'cross-filter',
1441
+ data: {
1442
+ category: event.name,
1443
+ serie: event.seriesName,
1444
+ value: event.value
1445
+ }
1446
+ });
1447
+ }
1321
1448
  }
1322
- // Setters
1323
- /**
1324
- * Permite inyectar un formateador de valores externo.
1325
- */
1326
- setValueFormatter(formatter) {
1327
- if (formatter) {
1328
- this.valueFormatter = formatter;
1449
+ onChartMouseOver(event) {
1450
+ if (this.selectedPercent === null && event && event.percent !== undefined) {
1451
+ this.setGraphicText(event.percent + '%');
1329
1452
  }
1330
1453
  }
1331
- /**
1332
- * Permite inyectar una paleta de colores básica.
1333
- */
1334
- setPalette(palette) {
1335
- if (palette) {
1336
- this.palette = palette;
1454
+ onChartMouseOut(event) {
1455
+ if (this.selectedPercent === null) {
1456
+ this.setGraphicText('');
1337
1457
  }
1338
1458
  }
1339
1459
  /**
1340
- * Permite inyectar un resolver de colores dinámico.
1460
+ * Actualiza el texto del Graphic central y persiste la selección en el modelo de opciones.
1341
1461
  */
1342
- setColorResolver(resolver) {
1343
- if (resolver) {
1344
- this.colorResolver = resolver;
1345
- }
1346
- }
1347
- // Utils
1348
- getCategoryAxisOptions(data, overrides) {
1349
- // No explicit data needed on category axis when using ECharts dataset
1350
- const categoryAxisOptionsOverrides = {
1351
- ...overrides.categoryAxis[0]
1352
- };
1353
- const categoryAxisOptions = getCategoryAxisOptions(categoryAxisOptionsOverrides);
1354
- return categoryAxisOptions;
1355
- }
1356
- getValueAxisOptions(data, overrides) {
1357
- const valueAxisOptions = getValueAxisOptions();
1358
- return valueAxisOptions;
1462
+ setGraphicText(text) {
1463
+ this.currentGraphicText = text;
1464
+ // Persistencia de GRAPHIC (KPI central)
1465
+ this.chartInstance?.setOption({
1466
+ graphic: {
1467
+ style: {
1468
+ text: this.currentGraphicText,
1469
+ opacity: this.currentGraphicText ? 1 : 0,
1470
+ }
1471
+ }
1472
+ });
1359
1473
  }
1474
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1475
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsRingComponent, isStandalone: true, selector: "vs-echarts-ring", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div class=\"echarts-container\" \n echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartMouseOver)=\"onChartMouseOver($event)\" \n (chartMouseOut)=\"onChartMouseOut($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n ", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1360
1476
  }
1477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, decorators: [{
1478
+ type: Component,
1479
+ args: [{ selector: 'vs-echarts-ring', standalone: true, imports: [
1480
+ CommonModule,
1481
+ NgxEchartsDirective,
1482
+ ], providers: [provideVSEcharts()], template: "<div class=\"echarts-container\" \n echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartMouseOver)=\"onChartMouseOver($event)\" \n (chartMouseOut)=\"onChartMouseOut($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n ", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
1483
+ }], ctorParameters: () => [] });
1361
1484
 
1362
1485
  /**
1363
1486
  * PieBuilder
@@ -1522,20 +1645,80 @@ class PieBuilder {
1522
1645
  }
1523
1646
 
1524
1647
  /**
1525
- * FunnelBuilder
1648
+ * EchartsPieComponent
1526
1649
  *
1527
- * Concrete builder for Funnel charts.
1650
+ * Especialista en visualización de tipo Pie (Torta y Anillos concéntricos).
1651
+ * La primera serie se dibuja como un gráfico de torta tradicional (lleno) y
1652
+ * las subsecuentes como anillos concéntricos alrededor.
1528
1653
  */
1529
- class FunnelBuilder {
1530
- baseProduct;
1531
- valueFormatter = (value) => value.toLocaleString();
1532
- palette = [];
1533
- colorResolver;
1534
- result = {};
1535
- constructor(baseProduct) {
1536
- this.baseProduct = baseProduct;
1654
+ class EchartsPieComponent extends BaseEchartsComponent {
1655
+ baseSeriesOptions = {
1656
+ type: 'pie',
1657
+ center: ['50%', '50%'],
1658
+ avoidLabelOverlap: true,
1659
+ minAngle: 3,
1660
+ selectedMode: 'single',
1661
+ selectedOffset: 4,
1662
+ emphasis: {
1663
+ scale: true,
1664
+ scaleSize: 2,
1665
+ },
1666
+ select: {
1667
+ itemStyle: {
1668
+ borderColor: EChartsTokens.sBorderColor,
1669
+ shadowColor: EChartsTokens.sShadowColor,
1670
+ borderWidth: 1,
1671
+ shadowBlur: 4,
1672
+ },
1673
+ },
1674
+ animationType: 'scale',
1675
+ animationEasing: 'elasticOut',
1676
+ };
1677
+ baseProduct = {
1678
+ chartKey: 'pie',
1679
+ baseOptions: {
1680
+ series: this.baseSeriesOptions,
1681
+ }
1682
+ };
1683
+ builder = new PieBuilder(this.baseProduct);
1684
+ director = new VSECDirector(this.builder);
1685
+ constructor() {
1686
+ super();
1537
1687
  }
1538
- reset() {
1688
+ make() {
1689
+ const makeOpts = {
1690
+ valueFormatter: this.valueFormatter,
1691
+ palette: this.palette,
1692
+ colorResolver: this.colorResolver,
1693
+ };
1694
+ this.director.makePie(this.data, this.optionsOverrides, makeOpts);
1695
+ }
1696
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1697
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsPieComponent, isStandalone: true, selector: "vs-echarts-pie", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div\n class=\"echarts-container\"\n echarts\n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1698
+ }
1699
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, decorators: [{
1700
+ type: Component,
1701
+ args: [{ selector: 'vs-echarts-pie', standalone: true, imports: [
1702
+ CommonModule,
1703
+ NgxEchartsDirective,
1704
+ ], providers: [provideVSEcharts()], template: "<div\n class=\"echarts-container\"\n echarts\n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
1705
+ }], ctorParameters: () => [] });
1706
+
1707
+ /**
1708
+ * FunnelBuilder
1709
+ *
1710
+ * Concrete builder for Funnel charts.
1711
+ */
1712
+ class FunnelBuilder {
1713
+ baseProduct;
1714
+ valueFormatter = (value) => value.toLocaleString();
1715
+ palette = [];
1716
+ colorResolver;
1717
+ result = {};
1718
+ constructor(baseProduct) {
1719
+ this.baseProduct = baseProduct;
1720
+ }
1721
+ reset() {
1539
1722
  this.result = {};
1540
1723
  }
1541
1724
  addCommons() {
@@ -1625,10 +1808,91 @@ class FunnelBuilder {
1625
1808
  }
1626
1809
  }
1627
1810
 
1628
- class SunburstBuilder {
1629
- baseProduct;
1811
+ /**
1812
+ * EchartsFunnelComponent
1813
+ *
1814
+ * Component for Funnel visualization. Supports single and multiple measures.
1815
+ */
1816
+ class EchartsFunnelComponent extends BaseEchartsComponent {
1817
+ baseSeriesOptions = {
1818
+ type: 'funnel',
1819
+ left: '10%',
1820
+ width: '80%',
1821
+ minSize: '0.01%',
1822
+ maxSize: '100%',
1823
+ sort: 'descending',
1824
+ gap: 2,
1825
+ label: {
1826
+ show: true,
1827
+ position: 'inside'
1828
+ },
1829
+ labelLine: {
1830
+ show: false
1831
+ },
1832
+ itemStyle: {
1833
+ borderColor: '#fff',
1834
+ borderWidth: 1
1835
+ },
1836
+ emphasis: {
1837
+ label: {
1838
+ fontSize: 16
1839
+ }
1840
+ },
1841
+ selectedMode: 'single',
1842
+ select: {
1843
+ label: {
1844
+ fontSize: 16
1845
+ },
1846
+ itemStyle: {
1847
+ borderWidth: 1,
1848
+ borderColor: EChartsTokens.sBorderColor,
1849
+ shadowColor: EChartsTokens.sShadowColor,
1850
+ shadowBlur: 6,
1851
+ }
1852
+ },
1853
+ };
1854
+ baseProduct = {
1855
+ chartKey: 'funnel',
1856
+ baseOptions: {
1857
+ series: this.baseSeriesOptions,
1858
+ }
1859
+ };
1860
+ builder = new FunnelBuilder(this.baseProduct);
1861
+ director = new VSECDirector(this.builder);
1862
+ constructor() {
1863
+ super();
1864
+ }
1865
+ make() {
1866
+ const makeOpts = {
1867
+ valueFormatter: this.valueFormatter,
1868
+ palette: this.palette,
1869
+ colorResolver: this.colorResolver,
1870
+ };
1871
+ this.director.makeFunnel(this.data, this.optionsOverrides, makeOpts);
1872
+ }
1873
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1874
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsFunnelComponent, isStandalone: true, selector: "vs-echarts-funnel", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div class=\"echarts-container\" echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\" \n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1875
+ }
1876
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, decorators: [{
1877
+ type: Component,
1878
+ args: [{ selector: 'vs-echarts-funnel', standalone: true, imports: [
1879
+ CommonModule,
1880
+ NgxEchartsDirective,
1881
+ ], providers: [provideVSEcharts()], template: "<div class=\"echarts-container\" echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\" \n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
1882
+ }], ctorParameters: () => [] });
1883
+
1884
+ /**
1885
+ * Builder principal.
1886
+ *
1887
+ * Es muy completo, tiene soporte para ejes y sistema cartesiano polar.
1888
+ *
1889
+ * Puede verse utilizado en graficos como Lineas y Bars. Siempre que se pueda priorizar utilizar este.
1890
+ */
1891
+ class EChartBuilder {
1892
+ baseProduct = undefined;
1630
1893
  valueFormatter = (value) => value.toLocaleString();
1631
1894
  palette = [];
1895
+ // TODO: Hay que implementar un valor por defecto.
1632
1896
  colorResolver;
1633
1897
  result = {};
1634
1898
  constructor(baseProduct) {
@@ -1637,779 +1901,217 @@ class SunburstBuilder {
1637
1901
  reset() {
1638
1902
  this.result = {};
1639
1903
  }
1640
- addSeries(data, overrides) {
1641
- if (!data || !data.source || data.source.length === 0) {
1904
+ addCommons() {
1905
+ const opts = {
1906
+ palette: this.palette,
1907
+ };
1908
+ merge$1(this.result, getCommons(opts));
1909
+ }
1910
+ /**
1911
+ *
1912
+ * @param data
1913
+ * @param overrides
1914
+ * @returns
1915
+ */
1916
+ addSeries(data, overrides, opts) {
1917
+ if (!data || !data.dimensions || !data.source || data.source.length === 0)
1642
1918
  return;
1643
- }
1644
- const sunburstData = mapHierarchicalData(data.source, data.dimensions);
1645
- const depth = getTreeDepth(sunburstData);
1646
- const levels = [];
1647
- for (let i = 0; i <= depth; i++) {
1648
- levels.push({
1649
- label: {
1650
- show: false,
1651
- },
1652
- });
1653
- }
1654
- const dynamiSerieOptions = {
1655
- name: '',
1656
- data: sunburstData,
1657
- levels: levels
1919
+ this.result.dataset = {
1920
+ dimensions: data.dimensions,
1921
+ source: data.source
1658
1922
  };
1659
- const serie = merge$1({}, dynamiSerieOptions, overrides);
1660
- if (this.colorResolver) {
1661
- if (!serie.itemStyle) {
1662
- serie.itemStyle = {};
1923
+ const measureDims = data.dimensions.filter(d => d.name !== 'category');
1924
+ const isPolar = opts?.coordinateSystem === 'polar';
1925
+ const isHorizontal = opts?.axisTypes?.x === 'value' && opts?.axisTypes?.y === 'category';
1926
+ const series = measureDims.map((dim) => {
1927
+ const friendlyName = dim.displayName || dim.name;
1928
+ const dimKey = dim.name;
1929
+ let encode = {
1930
+ x: 'category',
1931
+ y: dimKey
1932
+ };
1933
+ if (isPolar) {
1934
+ encode = {
1935
+ angle: 'category',
1936
+ radius: dimKey
1937
+ };
1663
1938
  }
1664
- serie.itemStyle.color = this.colorResolver;
1665
- }
1666
- this.result.series = serie;
1939
+ else if (isHorizontal) {
1940
+ encode = {
1941
+ x: dimKey,
1942
+ y: 'category'
1943
+ };
1944
+ }
1945
+ const dynamicOverrides = {
1946
+ name: friendlyName,
1947
+ encode,
1948
+ label: {
1949
+ formatter: (params) => {
1950
+ const row = params.value;
1951
+ const rawValue = (row && typeof row === 'object') ? row[dimKey] : params.value;
1952
+ return this.formatCellValue(Number(rawValue ?? 0), dimKey);
1953
+ }
1954
+ }
1955
+ };
1956
+ const seriesOption = merge$1(dynamicOverrides, overrides);
1957
+ // Inyectar el resolver de color si existe
1958
+ if (this.colorResolver && seriesOption.itemStyle) {
1959
+ seriesOption.itemStyle.color = this.colorResolver;
1960
+ }
1961
+ return seriesOption;
1962
+ });
1963
+ this.result.series = series;
1667
1964
  }
1965
+ /**
1966
+ * TODO: Mejorar funcion, no me convence como se implemento el tooltip formatter.
1967
+ * @param data
1968
+ * @param overrides
1969
+ */
1668
1970
  addTooltip(data, overrides) {
1971
+ // inyecto formateador a overrides de tooltip
1669
1972
  merge$1(overrides, {
1670
- formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
1973
+ formatter: getTooltipFormatter(overrides.trigger, data, this.formatCellValue.bind(this)),
1671
1974
  });
1672
1975
  const tooltip = getTooltipOptions(overrides);
1673
1976
  this.result.tooltip = tooltip;
1674
1977
  }
1675
- addCommons() {
1676
- const opts = {
1677
- palette: this.palette,
1678
- };
1679
- merge$1(this.result, getCommons(opts));
1680
- }
1681
- getResult() {
1682
- return this.result;
1978
+ addPolar() {
1979
+ const polar = [];
1980
+ polar.push({
1981
+ radius: '65%',
1982
+ center: ["50%", "44%"],
1983
+ });
1984
+ this.result.polar = polar;
1683
1985
  }
1684
- ;
1685
- // No-ops
1686
- addPolar() { }
1687
- addXAxis(data, overrides, type) { }
1688
- addYAxis(data, overrides, type) { }
1689
- addRadiusAxis(data, overrides) { }
1690
- addAngleAxis(data, overrides) { }
1691
- addLegend() { }
1692
- addDataZoom() { }
1693
- addDataset(data, opts) { }
1694
- addGraphic() { }
1695
- // Setters
1696
- /**
1697
- * Permite inyectar un formateador de valores externo.
1698
- */
1699
- setValueFormatter(formatter) {
1700
- if (formatter) {
1701
- this.valueFormatter = formatter;
1986
+ addXAxis(data, overrides, type = 'category') {
1987
+ const xAxis = [];
1988
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1989
+ const valueAxisOptions = this.getValueAxisOptions(data, overrides);
1990
+ if (type == 'category') {
1991
+ xAxis.push(categoryAxisOptions);
1702
1992
  }
1703
- }
1704
- /**
1705
- * Permite inyectar una paleta de colores básica.
1706
- */
1707
- setPalette(palette) {
1708
- if (palette) {
1709
- this.palette = palette;
1993
+ else if (type == 'value') {
1994
+ xAxis.push(valueAxisOptions);
1710
1995
  }
1996
+ this.result.xAxis = xAxis;
1711
1997
  }
1712
- /**
1713
- * Permite inyectar un resolver de colores dinámico.
1714
- */
1715
- setColorResolver(resolver) {
1716
- if (resolver) {
1717
- this.colorResolver = resolver;
1998
+ addYAxis(data, overrides, type = 'value') {
1999
+ const yAxis = [];
2000
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
2001
+ const valueAxisOptions = this.getValueAxisOptions(data, overrides);
2002
+ if (type == 'category') {
2003
+ yAxis.push(categoryAxisOptions);
1718
2004
  }
1719
- }
1720
- }
1721
-
1722
- /**
1723
- * SankeyBuilder
1724
- *
1725
- * Builder concreto para el gráfico Sankey (diagrama de flujos de izquierda a derecha).
1726
- */
1727
- class SankeyBuilder {
1728
- baseProduct;
1729
- valueFormatter = (value) => value.toLocaleString();
1730
- palette = [];
1731
- colorResolver;
1732
- result = {};
1733
- constructor(baseProduct) {
1734
- this.baseProduct = baseProduct;
1735
- }
1736
- reset() {
1737
- this.result = {};
1738
- }
1739
- addSeries(data, overrides) {
1740
- if (!data || !data.source || data.source.length === 0) {
1741
- return;
2005
+ else if (type == 'value') {
2006
+ yAxis.push(valueAxisOptions);
1742
2007
  }
1743
- // Identificar medidas (todas las dimensiones excepto 'category')
1744
- const measureKeys = data.dimensions
1745
- .filter((d) => d.name !== "category")
1746
- .map((d) => d.name);
1747
- // Función auxiliar para sumarizar valores de medidas en caso de haber más de una
1748
- const getNodeValue = (node) => {
1749
- return measureKeys.reduce((sum, key) => sum + (Number(node[key]) || 0), 0);
1750
- };
1751
- const nodesMap = new Map();
1752
- const linksMap = new Map();
1753
- // Función recursiva para aplanar datos jerárquicos a nodos y enlaces
1754
- const traverse = (nodeList, level, parentId) => {
1755
- for (const node of nodeList) {
1756
- const category = node.category;
1757
- const currentId = `${category}___${level}`;
1758
- const value = getNodeValue(node);
1759
- nodesMap.set(currentId, (nodesMap.get(currentId) || 0) + value);
1760
- if (parentId) {
1761
- const linkKey = `${parentId}--->${currentId}`;
1762
- if (linksMap.has(linkKey)) {
1763
- linksMap.get(linkKey).value += value;
1764
- }
1765
- else {
1766
- linksMap.set(linkKey, {
1767
- source: parentId,
1768
- target: currentId,
1769
- value: value,
1770
- });
1771
- }
1772
- }
1773
- if (node.children && node.children.length > 0) {
1774
- traverse(node.children, level + 1, currentId);
1775
- }
1776
- }
1777
- };
1778
- // Comenzar el recorrido en el nivel 0
1779
- traverse(data.source, 0);
1780
- // al menos un nivel de links para dibujar.
1781
- if (linksMap.size === 0)
1782
- return;
1783
- // Mapear nodos acumulados a la estructura requerida por ECharts (name y opcionalmente color, sin value redundante)
1784
- const nodes = Array.from(nodesMap.keys()).map((currentId) => {
1785
- const category = currentId.split("___")[0];
1786
- const nodeItem = {
1787
- name: currentId,
1788
- };
1789
- if (this.colorResolver) {
1790
- const color = this.colorResolver({ name: category, data: nodeItem });
1791
- if (color) {
1792
- nodeItem.itemStyle = { color };
1793
- }
1794
- }
1795
- return nodeItem;
1796
- });
1797
- const dynamicSerieOptions = {
1798
- type: "sankey",
1799
- orient: "horizontal", // De izquierda a derecha
1800
- draggable: true,
1801
- emphasis: {
1802
- focus: "adjacency",
2008
+ this.result.yAxis = yAxis;
2009
+ }
2010
+ addRadiusAxis(data, overrides) {
2011
+ const radiusAxis = [];
2012
+ /** estilos exclusivos hardcodeados para el eje de valores del sistema de coordenadas polar*/
2013
+ const radiusAxisOverrides = {
2014
+ zlevel: 10,
2015
+ axisTick: {
2016
+ show: false,
1803
2017
  },
1804
- lineStyle: {
1805
- color: "source",
1806
- opacity: 0.25,
1807
- curveness: 0.5,
2018
+ axisLabel: {
2019
+ margin: 2,
2020
+ fontSize: 8,
2021
+ align: 'right',
2022
+ rotate: 20,
2023
+ verticalAlign: 'top',
1808
2024
  },
1809
- label: {
2025
+ splitLine: {
1810
2026
  show: true,
1811
- position: "right",
1812
- fontFamily: "'Inter', 'Roboto', 'Open Sans', sans-serif",
1813
- fontSize: 10,
1814
- formatter: (params) => {
1815
- // Remover el sufijo de nivel de la etiqueta visual
1816
- return params.name.split("___")[0];
1817
- },
2027
+ lineStyle: {
2028
+ opacity: 0.2,
2029
+ type: 'solid',
2030
+ }
1818
2031
  },
1819
- roam: true,
1820
- data: nodes,
1821
- links: Array.from(linksMap.values()),
2032
+ axisLine: {
2033
+ lineStyle: {
2034
+ type: 'dashed',
2035
+ },
2036
+ }
1822
2037
  };
1823
- const serie = merge$1({}, dynamicSerieOptions, overrides);
1824
- if (this.colorResolver && !serie.itemStyle) {
1825
- serie.itemStyle = {};
1826
- }
1827
- if (this.colorResolver && serie.itemStyle) {
1828
- serie.itemStyle.color = this.colorResolver;
1829
- }
1830
- this.result.series = serie;
2038
+ const radialAxisOptions = getValueAxisOptions(radiusAxisOverrides);
2039
+ radiusAxis.push(radialAxisOptions);
2040
+ this.result.radiusAxis = radiusAxis;
1831
2041
  }
1832
- addTooltip(data, overrides) {
1833
- merge$1(overrides, {
1834
- formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
1835
- });
1836
- const tooltip = getTooltipOptions(overrides);
1837
- this.result.tooltip = tooltip;
2042
+ addAngleAxis(data, overrides) {
2043
+ const angleAxis = [];
2044
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
2045
+ angleAxis.push(categoryAxisOptions);
2046
+ this.result.angleAxis = angleAxis;
1838
2047
  }
1839
- addPolar() { }
1840
- addXAxis(data, overrides, type) { }
1841
- addYAxis(data, overrides, type) { }
1842
- addRadiusAxis(data, overrides) { }
1843
- addAngleAxis(data, overrides) { }
1844
- addLegend() { }
1845
- addDataZoom() { }
1846
- addDataset(data, opts) { }
1847
- addCommons() {
1848
- const opts = {
1849
- palette: this.palette,
1850
- };
1851
- merge$1(this.result, getCommons(opts));
2048
+ addLegend() {
2049
+ this.result.legend = getLegendOptions();
1852
2050
  }
2051
+ // No-ops for ring charts
1853
2052
  addGraphic() { }
2053
+ addDataset(data, opts) { }
2054
+ addDataZoom() {
2055
+ this.result.dataZoom = [
2056
+ {
2057
+ type: 'inside'
2058
+ },
2059
+ {
2060
+ type: 'slider',
2061
+ height: 20,
2062
+ bottom: 60
2063
+ }
2064
+ ];
2065
+ }
1854
2066
  getResult() {
1855
2067
  return this.result;
1856
2068
  }
2069
+ ;
2070
+ /**
2071
+ * Formatea un valor utilizando el callback inyectado.
2072
+ */
2073
+ formatCellValue(value, key) {
2074
+ return this.valueFormatter(value, key);
2075
+ }
2076
+ // Setters
2077
+ /**
2078
+ * Permite inyectar un formateador de valores externo.
2079
+ */
1857
2080
  setValueFormatter(formatter) {
1858
2081
  if (formatter) {
1859
2082
  this.valueFormatter = formatter;
1860
2083
  }
1861
2084
  }
2085
+ /**
2086
+ * Permite inyectar una paleta de colores básica.
2087
+ */
1862
2088
  setPalette(palette) {
1863
2089
  if (palette) {
1864
2090
  this.palette = palette;
1865
2091
  }
1866
2092
  }
2093
+ /**
2094
+ * Permite inyectar un resolver de colores dinámico.
2095
+ */
1867
2096
  setColorResolver(resolver) {
1868
2097
  if (resolver) {
1869
2098
  this.colorResolver = resolver;
1870
2099
  }
1871
2100
  }
1872
- }
1873
-
1874
- /**
1875
- * Director de Builds.
1876
- */
1877
- class VSECDirector {
1878
- builder = undefined;
1879
- constructor(builder) {
1880
- this.builder = builder;
1881
- }
1882
- makeBar(data, overrides, opts = {}) {
1883
- if (this.builder instanceof EChartBuilder == false) {
1884
- return;
1885
- }
1886
- ;
1887
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1888
- x: 'category',
1889
- y: 'value',
1890
- // TODO agregar radius y angle axis
1891
- } } = opts;
1892
- this.builder.reset();
1893
- // El orden importa, primero callbacks y despues componentes.
1894
- // chart callbaks
1895
- if (valueFormatter)
1896
- this.builder.setValueFormatter(valueFormatter);
1897
- if (palette)
1898
- this.builder.setPalette(palette);
1899
- if (colorResolver)
1900
- this.builder.setColorResolver(colorResolver);
1901
- const product = this.builder.baseProduct;
1902
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1903
- // chart components
1904
- this.builder.addCommons();
1905
- const seriesOptions = { axisTypes };
1906
- this.builder.addSeries(data, seriesOverrides, seriesOptions);
1907
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1908
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1909
- this.builder.addTooltip(data, overrides.tooltip);
1910
- this.builder.addLegend();
2101
+ // Utils
2102
+ getCategoryAxisOptions(data, overrides) {
2103
+ // No explicit data needed on category axis when using ECharts dataset
2104
+ const categoryAxisOptionsOverrides = {
2105
+ ...overrides.categoryAxis[0]
2106
+ };
2107
+ const categoryAxisOptions = getCategoryAxisOptions(categoryAxisOptionsOverrides);
2108
+ return categoryAxisOptions;
1911
2109
  }
1912
- makeBarRadial(data, overrides, opts = {}) {
1913
- if (this.builder instanceof EChartBuilder == false) {
1914
- return;
1915
- }
1916
- ;
1917
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1918
- x: 'category',
1919
- y: 'value',
1920
- // TODO agregar radius y angle axis
1921
- } } = opts;
1922
- this.builder.reset();
1923
- // El orden importa, primero callbacks y despues componentes.
1924
- // chart callbaks
1925
- if (valueFormatter)
1926
- this.builder.setValueFormatter(valueFormatter);
1927
- if (palette)
1928
- this.builder.setPalette(palette);
1929
- if (colorResolver)
1930
- this.builder.setColorResolver(colorResolver);
1931
- const product = this.builder.baseProduct;
1932
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1933
- // chart components
1934
- this.builder.addCommons();
1935
- const seriesOptions = { axisTypes, coordinateSystem: 'polar' };
1936
- this.builder.addSeries(data, seriesOverrides, seriesOptions);
1937
- this.builder.addPolar();
1938
- this.builder.addAngleAxis(data, overrides['axis']);
1939
- this.builder.addRadiusAxis(data, overrides['axis']);
1940
- this.builder.addTooltip(data, overrides.tooltip);
1941
- this.builder.addLegend();
1942
- }
1943
- makeLine(data, overrides, opts = {}) {
1944
- if (this.builder instanceof EChartBuilder == false) {
1945
- return;
1946
- }
1947
- ;
1948
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1949
- x: 'category',
1950
- y: 'value',
1951
- // TODO agregar radius y angle axis
1952
- } } = opts;
1953
- this.builder.reset();
1954
- // El orden importa, primero callbacks y despues componentes.
1955
- // chart callbaks
1956
- if (valueFormatter)
1957
- this.builder.setValueFormatter(valueFormatter);
1958
- if (palette)
1959
- this.builder.setPalette(palette);
1960
- if (colorResolver)
1961
- this.builder.setColorResolver(colorResolver);
1962
- const product = this.builder.baseProduct;
1963
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1964
- // chart components
1965
- this.builder.addCommons();
1966
- const seriesOptions = { axisTypes };
1967
- this.builder.addSeries(data, seriesOverrides, seriesOptions);
1968
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1969
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1970
- this.builder.addTooltip(data, overrides.tooltip);
1971
- this.builder.addLegend();
1972
- }
1973
- makeScatter(data, overrides, opts = {}) {
1974
- if (this.builder instanceof EChartBuilder == false) {
1975
- return;
1976
- }
1977
- ;
1978
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1979
- x: 'category',
1980
- y: 'value',
1981
- } } = opts;
1982
- this.builder.reset();
1983
- // El orden importa, primero callbacks y despues componentes.
1984
- // chart callbaks
1985
- if (valueFormatter)
1986
- this.builder.setValueFormatter(valueFormatter);
1987
- if (palette)
1988
- this.builder.setPalette(palette);
1989
- if (colorResolver)
1990
- this.builder.setColorResolver(colorResolver);
1991
- const product = this.builder.baseProduct;
1992
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1993
- // chart components
1994
- this.builder.addCommons();
1995
- const seriesOptions = { axisTypes };
1996
- this.builder.addSeries(data, seriesOverrides, seriesOptions);
1997
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1998
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1999
- this.builder.addTooltip(data, overrides.tooltip);
2000
- this.builder.addLegend();
2001
- }
2002
- makeRing(data, overrides, opts = {}) {
2003
- if (this.builder instanceof RingBuilder == false) {
2004
- return;
2005
- }
2006
- ;
2007
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2008
- this.builder.reset();
2009
- // El orden importa, primero callbacks y despues componentes.
2010
- // chart callbaks
2011
- if (valueFormatter)
2012
- this.builder.setValueFormatter(valueFormatter);
2013
- if (palette)
2014
- this.builder.setPalette(palette);
2015
- if (colorResolver)
2016
- this.builder.setColorResolver(colorResolver);
2017
- const product = this.builder.baseProduct;
2018
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2019
- // chart components
2020
- this.builder.addCommons();
2021
- this.builder.addSeries(data, seriesOverrides);
2022
- this.builder.addGraphic();
2023
- this.builder.addTooltip(data, overrides.tooltip);
2024
- this.builder.addLegend();
2025
- }
2026
- makePie(data, overrides, opts = {}) {
2027
- if (this.builder instanceof PieBuilder == false) {
2028
- return;
2029
- }
2030
- ;
2031
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2032
- this.builder.reset();
2033
- // El orden importa, primero callbacks y despues componentes.
2034
- // chart callbaks
2035
- if (valueFormatter)
2036
- this.builder.setValueFormatter(valueFormatter);
2037
- if (palette)
2038
- this.builder.setPalette(palette);
2039
- if (colorResolver)
2040
- this.builder.setColorResolver(colorResolver);
2041
- const product = this.builder.baseProduct;
2042
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2043
- // chart components
2044
- this.builder.addCommons();
2045
- this.builder.addSeries(data, seriesOverrides);
2046
- this.builder.addTooltip(data, overrides.tooltip);
2047
- this.builder.addLegend();
2048
- }
2049
- makeFunnel(data, overrides, opts = {}) {
2050
- if (this.builder instanceof FunnelBuilder == false) {
2051
- return;
2052
- }
2053
- ;
2054
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2055
- this.builder.reset();
2056
- // El orden importa, primero callbacks y despues componentes.
2057
- // chart callbaks
2058
- if (valueFormatter)
2059
- this.builder.setValueFormatter(valueFormatter);
2060
- if (palette)
2061
- this.builder.setPalette(palette);
2062
- if (colorResolver)
2063
- this.builder.setColorResolver(colorResolver);
2064
- const product = this.builder.baseProduct;
2065
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2066
- // chart components
2067
- this.builder.addCommons();
2068
- this.builder.addSeries(data, seriesOverrides);
2069
- this.builder.addTooltip(data, overrides.tooltip);
2070
- this.builder.addLegend();
2071
- }
2072
- makeSunburst(data, overrides, opts = {}) {
2073
- if (this.builder instanceof SunburstBuilder == false) {
2074
- return;
2075
- }
2076
- ;
2077
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2078
- this.builder.reset();
2079
- // El orden importa, primero callbacks y despues componentes.
2080
- // chart callbaks
2081
- if (valueFormatter)
2082
- this.builder.setValueFormatter(valueFormatter);
2083
- if (palette)
2084
- this.builder.setPalette(palette);
2085
- if (colorResolver)
2086
- this.builder.setColorResolver(colorResolver);
2087
- const product = this.builder.baseProduct;
2088
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2089
- // chart components
2090
- this.builder.addCommons();
2091
- this.builder.addSeries(data, seriesOverrides);
2092
- this.builder.addTooltip(data, overrides.tooltip);
2093
- }
2094
- makeSankey(data, overrides, opts = {}) {
2095
- if (this.builder instanceof SankeyBuilder == false) {
2096
- return;
2097
- }
2098
- ;
2099
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2100
- this.builder.reset();
2101
- // El orden importa, primero callbacks y despues componentes.
2102
- // chart callbaks
2103
- if (valueFormatter)
2104
- this.builder.setValueFormatter(valueFormatter);
2105
- if (palette)
2106
- this.builder.setPalette(palette);
2107
- if (colorResolver)
2108
- this.builder.setColorResolver(colorResolver);
2109
- const product = this.builder.baseProduct;
2110
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2111
- // chart components
2112
- this.builder.addCommons();
2113
- this.builder.addSeries(data, seriesOverrides);
2114
- this.builder.addTooltip(data, overrides.tooltip);
2115
- }
2116
- makeBoxplot(data, overrides, opts = {}) {
2117
- if (this.builder instanceof BoxPlotBuilder == false) {
2118
- return;
2119
- }
2120
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
2121
- x: 'value',
2122
- y: 'category',
2123
- }, statisticsKeys = undefined, } = opts;
2124
- this.builder.reset();
2125
- // El orden importa, primero callbacks y despues componentes.
2126
- // chart callbaks
2127
- if (valueFormatter)
2128
- this.builder.setValueFormatter(valueFormatter);
2129
- if (palette)
2130
- this.builder.setPalette(palette);
2131
- if (colorResolver)
2132
- this.builder.setColorResolver(colorResolver);
2133
- const product = this.builder.baseProduct;
2134
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2135
- // chart components
2136
- this.builder.addCommons();
2137
- const configOpts = { axisTypes };
2138
- this.builder.addDataset(data, { statisticsKeys });
2139
- this.builder.addSeries(data, seriesOverrides, configOpts);
2140
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
2141
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
2142
- this.builder.addTooltip(data, overrides.tooltip);
2143
- this.builder.addDataZoom();
2144
- }
2145
- }
2146
-
2147
- /**
2148
- * EchartsRingComponent
2149
- *
2150
- * Especialista en visualización de tipo Ring. Soporta multi-medidas y KPI central.
2151
- * @see {@link vs-echarts/docs/charts/ring-patterns.md}
2152
- */
2153
- class EchartsRingComponent extends BaseEchartsComponent {
2154
- baseSeriesOptions = {
2155
- type: 'pie',
2156
- center: ['50%', '50%'],
2157
- avoidLabelOverlap: true,
2158
- minAngle: 3,
2159
- selectedMode: 'single',
2160
- selectedOffset: 4,
2161
- itemStyle: {
2162
- borderColor: '#fff',
2163
- },
2164
- label: { show: false },
2165
- emphasis: {
2166
- scale: true,
2167
- scaleSize: 2,
2168
- },
2169
- select: {
2170
- itemStyle: {
2171
- borderColor: EChartsTokens.sBorderColor,
2172
- shadowColor: EChartsTokens.sShadowColor,
2173
- borderWidth: 1,
2174
- shadowBlur: 4,
2175
- },
2176
- },
2177
- animationType: 'scale',
2178
- animationEasing: 'elasticOut',
2179
- };
2180
- baseProduct = {
2181
- chartKey: 'ring',
2182
- baseOptions: {
2183
- series: this.baseSeriesOptions,
2184
- }
2185
- };
2186
- builder = new RingBuilder(this.baseProduct);
2187
- director = new VSECDirector(this.builder);
2188
- lastSelectedSeriesIndex = null;
2189
- lastSelectedDataIndex = null;
2190
- selectedPercent = null;
2191
- currentGraphicText = '';
2192
- constructor() {
2193
- super();
2194
- }
2195
- make() {
2196
- const makeOpts = {
2197
- valueFormatter: this.valueFormatter,
2198
- palette: this.palette,
2199
- colorResolver: this.colorResolver,
2200
- };
2201
- this.director.makeRing(this.data, this.optionsOverrides, makeOpts);
2202
- }
2203
- onInputChanges(changes) {
2204
- // Reset selection only if data changed
2205
- if (changes['data']) {
2206
- this.lastSelectedSeriesIndex = null;
2207
- this.lastSelectedDataIndex = null;
2208
- this.selectedPercent = null;
2209
- this.currentGraphicText = '';
2210
- }
2211
- super.onInputChanges(changes);
2212
- }
2213
- /**
2214
- * Maneja clics en los sectores del ring.
2215
- * Soporta múltiples series (anillos) y actualiza el KPI central.
2216
- */
2217
- onChartClick(event) {
2218
- if (this.chartInstance && event && event.dataIndex !== undefined) {
2219
- const isSameSelection = event.seriesIndex === this.lastSelectedSeriesIndex &&
2220
- event.dataIndex === this.lastSelectedDataIndex;
2221
- if (isSameSelection) {
2222
- // Toggle OFF
2223
- this.lastSelectedSeriesIndex = null;
2224
- this.lastSelectedDataIndex = null;
2225
- this.selectedPercent = null;
2226
- this.setGraphicText('');
2227
- }
2228
- else {
2229
- // SELECT
2230
- this.lastSelectedSeriesIndex = event.seriesIndex;
2231
- this.lastSelectedDataIndex = event.dataIndex;
2232
- this.selectedPercent = (event.percent !== undefined) ? event.percent + '%' : '';
2233
- this.setGraphicText(this.selectedPercent);
2234
- }
2235
- this.chartClick.emit({
2236
- type: 'cross-filter',
2237
- data: {
2238
- category: event.name,
2239
- serie: event.seriesName,
2240
- value: event.value
2241
- }
2242
- });
2243
- }
2244
- }
2245
- onChartMouseOver(event) {
2246
- if (this.selectedPercent === null && event && event.percent !== undefined) {
2247
- this.setGraphicText(event.percent + '%');
2248
- }
2249
- }
2250
- onChartMouseOut(event) {
2251
- if (this.selectedPercent === null) {
2252
- this.setGraphicText('');
2253
- }
2254
- }
2255
- /**
2256
- * Actualiza el texto del Graphic central y persiste la selección en el modelo de opciones.
2257
- */
2258
- setGraphicText(text) {
2259
- this.currentGraphicText = text;
2260
- // Persistencia de GRAPHIC (KPI central)
2261
- this.chartInstance?.setOption({
2262
- graphic: {
2263
- style: {
2264
- text: this.currentGraphicText,
2265
- opacity: this.currentGraphicText ? 1 : 0,
2266
- }
2267
- }
2268
- });
2269
- }
2270
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2271
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsRingComponent, isStandalone: true, selector: "vs-echarts-ring", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div class=\"echarts-container\" \n echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartMouseOver)=\"onChartMouseOver($event)\" \n (chartMouseOut)=\"onChartMouseOut($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n ", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
2272
- }
2273
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, decorators: [{
2274
- type: Component,
2275
- args: [{ selector: 'vs-echarts-ring', standalone: true, imports: [
2276
- CommonModule,
2277
- NgxEchartsDirective,
2278
- ], providers: [provideVSEcharts()], template: "<div class=\"echarts-container\" \n echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartMouseOver)=\"onChartMouseOver($event)\" \n (chartMouseOut)=\"onChartMouseOut($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n ", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
2279
- }], ctorParameters: () => [] });
2280
-
2281
- /**
2282
- * EchartsPieComponent
2283
- *
2284
- * Especialista en visualización de tipo Pie (Torta y Anillos concéntricos).
2285
- * La primera serie se dibuja como un gráfico de torta tradicional (lleno) y
2286
- * las subsecuentes como anillos concéntricos alrededor.
2287
- */
2288
- class EchartsPieComponent extends BaseEchartsComponent {
2289
- baseSeriesOptions = {
2290
- type: 'pie',
2291
- center: ['50%', '50%'],
2292
- avoidLabelOverlap: true,
2293
- minAngle: 3,
2294
- selectedMode: 'single',
2295
- selectedOffset: 4,
2296
- emphasis: {
2297
- scale: true,
2298
- scaleSize: 2,
2299
- },
2300
- select: {
2301
- itemStyle: {
2302
- borderColor: EChartsTokens.sBorderColor,
2303
- shadowColor: EChartsTokens.sShadowColor,
2304
- borderWidth: 1,
2305
- shadowBlur: 4,
2306
- },
2307
- },
2308
- animationType: 'scale',
2309
- animationEasing: 'elasticOut',
2310
- };
2311
- baseProduct = {
2312
- chartKey: 'pie',
2313
- baseOptions: {
2314
- series: this.baseSeriesOptions,
2315
- }
2316
- };
2317
- builder = new PieBuilder(this.baseProduct);
2318
- director = new VSECDirector(this.builder);
2319
- constructor() {
2320
- super();
2321
- }
2322
- make() {
2323
- const makeOpts = {
2324
- valueFormatter: this.valueFormatter,
2325
- palette: this.palette,
2326
- colorResolver: this.colorResolver,
2327
- };
2328
- this.director.makePie(this.data, this.optionsOverrides, makeOpts);
2329
- }
2330
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2331
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsPieComponent, isStandalone: true, selector: "vs-echarts-pie", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div\n class=\"echarts-container\"\n echarts\n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
2332
- }
2333
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, decorators: [{
2334
- type: Component,
2335
- args: [{ selector: 'vs-echarts-pie', standalone: true, imports: [
2336
- CommonModule,
2337
- NgxEchartsDirective,
2338
- ], providers: [provideVSEcharts()], template: "<div\n class=\"echarts-container\"\n echarts\n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
2339
- }], ctorParameters: () => [] });
2340
-
2341
- /**
2342
- * EchartsFunnelComponent
2343
- *
2344
- * Component for Funnel visualization. Supports single and multiple measures.
2345
- */
2346
- class EchartsFunnelComponent extends BaseEchartsComponent {
2347
- baseSeriesOptions = {
2348
- type: 'funnel',
2349
- left: '10%',
2350
- width: '80%',
2351
- minSize: '0.01%',
2352
- maxSize: '100%',
2353
- sort: 'descending',
2354
- gap: 2,
2355
- label: {
2356
- show: true,
2357
- position: 'inside'
2358
- },
2359
- labelLine: {
2360
- show: false
2361
- },
2362
- itemStyle: {
2363
- borderColor: '#fff',
2364
- borderWidth: 1
2365
- },
2366
- emphasis: {
2367
- label: {
2368
- fontSize: 16
2369
- }
2370
- },
2371
- selectedMode: 'single',
2372
- select: {
2373
- label: {
2374
- fontSize: 16
2375
- },
2376
- itemStyle: {
2377
- borderWidth: 1,
2378
- borderColor: EChartsTokens.sBorderColor,
2379
- shadowColor: EChartsTokens.sShadowColor,
2380
- shadowBlur: 6,
2381
- }
2382
- },
2383
- };
2384
- baseProduct = {
2385
- chartKey: 'funnel',
2386
- baseOptions: {
2387
- series: this.baseSeriesOptions,
2388
- }
2389
- };
2390
- builder = new FunnelBuilder(this.baseProduct);
2391
- director = new VSECDirector(this.builder);
2392
- constructor() {
2393
- super();
2394
- }
2395
- make() {
2396
- const makeOpts = {
2397
- valueFormatter: this.valueFormatter,
2398
- palette: this.palette,
2399
- colorResolver: this.colorResolver,
2400
- };
2401
- this.director.makeFunnel(this.data, this.optionsOverrides, makeOpts);
2110
+ getValueAxisOptions(data, overrides) {
2111
+ const valueAxisOptions = getValueAxisOptions();
2112
+ return valueAxisOptions;
2402
2113
  }
2403
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2404
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsFunnelComponent, isStandalone: true, selector: "vs-echarts-funnel", providers: [provideVSEcharts()], usesInheritance: true, ngImport: i0, template: "<div class=\"echarts-container\" echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\" \n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
2405
2114
  }
2406
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, decorators: [{
2407
- type: Component,
2408
- args: [{ selector: 'vs-echarts-funnel', standalone: true, imports: [
2409
- CommonModule,
2410
- NgxEchartsDirective,
2411
- ], providers: [provideVSEcharts()], template: "<div class=\"echarts-container\" echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\" \n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event, { fixPieDataIndexInside: true })\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
2412
- }], ctorParameters: () => [] });
2413
2115
 
2414
2116
  class EchartsBarComponent extends BaseEchartsComponent {
2415
2117
  /**
@@ -2815,6 +2517,100 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
2815
2517
  ], providers: [provideVSEcharts()], template: "<div class=\"echarts-container\" echarts \n [options]=\"{}\"\n [initOpts]=\"initOptions\" \n [autoResize]=\"true\" \n (chartInit)=\"onChartInit($event)\" \n (chartClick)=\"onChartClick($event)\" \n (chartSelectChanged)=\"onChartSelectChanged($event)\"\n></div>\n", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
2816
2518
  }], ctorParameters: () => [] });
2817
2519
 
2520
+ class SunburstBuilder {
2521
+ baseProduct;
2522
+ valueFormatter = (value) => value.toLocaleString();
2523
+ palette = [];
2524
+ // TODO: Hay que implementar un valor por defecto.
2525
+ colorResolver;
2526
+ result = {};
2527
+ constructor(baseProduct) {
2528
+ this.baseProduct = baseProduct;
2529
+ }
2530
+ reset() {
2531
+ this.result = {};
2532
+ }
2533
+ addSeries(data, overrides) {
2534
+ if (!data || !data.source || data.source.length === 0) {
2535
+ return;
2536
+ }
2537
+ const sunburstData = mapHierarchicalData(data.source, data.dimensions);
2538
+ const depth = getTreeDepth(sunburstData);
2539
+ const levels = [];
2540
+ for (let i = 0; i <= depth; i++) {
2541
+ levels.push({
2542
+ label: {
2543
+ show: false,
2544
+ },
2545
+ });
2546
+ }
2547
+ const dynamiSerieOptions = {
2548
+ name: '',
2549
+ data: sunburstData,
2550
+ levels: levels
2551
+ };
2552
+ const serie = merge$1({}, dynamiSerieOptions, overrides);
2553
+ if (this.colorResolver) {
2554
+ if (!serie.itemStyle) {
2555
+ serie.itemStyle = {};
2556
+ }
2557
+ serie.itemStyle.color = this.colorResolver;
2558
+ }
2559
+ this.result.series = serie;
2560
+ }
2561
+ addTooltip(data, overrides) {
2562
+ merge$1(overrides, {
2563
+ formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
2564
+ });
2565
+ const tooltip = getTooltipOptions(overrides);
2566
+ this.result.tooltip = tooltip;
2567
+ }
2568
+ addCommons() {
2569
+ const opts = {
2570
+ palette: this.palette,
2571
+ };
2572
+ merge$1(this.result, getCommons(opts));
2573
+ }
2574
+ addGraphic() { }
2575
+ getResult() {
2576
+ return this.result;
2577
+ }
2578
+ ;
2579
+ addPolar() { }
2580
+ addXAxis(data, overrides, type) { }
2581
+ addYAxis(data, overrides, type) { }
2582
+ addRadiusAxis(data, overrides) { }
2583
+ addAngleAxis(data, overrides) { }
2584
+ addLegend() { }
2585
+ addDataZoom() { }
2586
+ addDataset(data, opts) { }
2587
+ // Setters
2588
+ /**
2589
+ * Permite inyectar un formateador de valores externo.
2590
+ */
2591
+ setValueFormatter(formatter) {
2592
+ if (formatter) {
2593
+ this.valueFormatter = formatter;
2594
+ }
2595
+ }
2596
+ /**
2597
+ * Permite inyectar una paleta de colores básica.
2598
+ */
2599
+ setPalette(palette) {
2600
+ if (palette) {
2601
+ this.palette = palette;
2602
+ }
2603
+ }
2604
+ /**
2605
+ * Permite inyectar un resolver de colores dinámico.
2606
+ */
2607
+ setColorResolver(resolver) {
2608
+ if (resolver) {
2609
+ this.colorResolver = resolver;
2610
+ }
2611
+ }
2612
+ }
2613
+
2818
2614
  class EChartsSunburstComponent extends BaseEchartsComponent {
2819
2615
  baseSeriesOptions = {
2820
2616
  type: 'sunburst',
@@ -2863,6 +2659,158 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
2863
2659
  ], providers: [provideVSEcharts()], template: "<div\n class=\"echarts-container\"\n echarts\n [options]=\"{}\"\n [initOpts]=\"initOptions\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\"\n></div>", styles: [".echarts-container{width:100%;height:100%;position:relative}\n"] }]
2864
2660
  }] });
2865
2661
 
2662
+ /**
2663
+ * SankeyBuilder
2664
+ *
2665
+ * Builder concreto para el gráfico Sankey (diagrama de flujos de izquierda a derecha).
2666
+ */
2667
+ class SankeyBuilder {
2668
+ baseProduct;
2669
+ valueFormatter = (value) => value.toLocaleString();
2670
+ palette = [];
2671
+ colorResolver;
2672
+ result = {};
2673
+ constructor(baseProduct) {
2674
+ this.baseProduct = baseProduct;
2675
+ }
2676
+ reset() {
2677
+ this.result = {};
2678
+ }
2679
+ addSeries(data, overrides) {
2680
+ if (!data || !data.source || data.source.length === 0) {
2681
+ return;
2682
+ }
2683
+ // Identificar medidas (todas las dimensiones excepto 'category')
2684
+ const measureKeys = data.dimensions
2685
+ .filter((d) => d.name !== "category")
2686
+ .map((d) => d.name);
2687
+ // Función auxiliar para sumarizar valores de medidas en caso de haber más de una
2688
+ const getNodeValue = (node) => {
2689
+ return measureKeys.reduce((sum, key) => sum + (Number(node[key]) || 0), 0);
2690
+ };
2691
+ const nodesMap = new Map();
2692
+ const linksMap = new Map();
2693
+ // Función recursiva para aplanar datos jerárquicos a nodos y enlaces
2694
+ const traverse = (nodeList, level, parentId) => {
2695
+ for (const node of nodeList) {
2696
+ const category = node.category;
2697
+ const currentId = `${category}___${level}`;
2698
+ const value = getNodeValue(node);
2699
+ nodesMap.set(currentId, (nodesMap.get(currentId) || 0) + value);
2700
+ if (parentId) {
2701
+ const linkKey = `${parentId}--->${currentId}`;
2702
+ if (linksMap.has(linkKey)) {
2703
+ linksMap.get(linkKey).value += value;
2704
+ }
2705
+ else {
2706
+ linksMap.set(linkKey, {
2707
+ source: parentId,
2708
+ target: currentId,
2709
+ value: value,
2710
+ });
2711
+ }
2712
+ }
2713
+ if (node.children && node.children.length > 0) {
2714
+ traverse(node.children, level + 1, currentId);
2715
+ }
2716
+ }
2717
+ };
2718
+ // Comenzar el recorrido en el nivel 0
2719
+ traverse(data.source, 0);
2720
+ // al menos un nivel de links para dibujar.
2721
+ if (linksMap.size === 0)
2722
+ return;
2723
+ // Mapear nodos acumulados a la estructura requerida por ECharts (name y opcionalmente color, sin value redundante)
2724
+ const nodes = Array.from(nodesMap.keys()).map((currentId) => {
2725
+ const category = currentId.split("___")[0];
2726
+ const nodeItem = {
2727
+ name: currentId,
2728
+ };
2729
+ if (this.colorResolver) {
2730
+ const color = this.colorResolver({ name: category, data: nodeItem });
2731
+ if (color) {
2732
+ nodeItem.itemStyle = { color };
2733
+ }
2734
+ }
2735
+ return nodeItem;
2736
+ });
2737
+ const dynamicSerieOptions = {
2738
+ type: "sankey",
2739
+ orient: "horizontal", // De izquierda a derecha
2740
+ draggable: true,
2741
+ emphasis: {
2742
+ focus: "adjacency",
2743
+ },
2744
+ lineStyle: {
2745
+ color: "source",
2746
+ opacity: 0.25,
2747
+ curveness: 0.5,
2748
+ },
2749
+ label: {
2750
+ show: true,
2751
+ position: "right",
2752
+ fontFamily: "'Inter', 'Roboto', 'Open Sans', sans-serif",
2753
+ fontSize: 10,
2754
+ formatter: (params) => {
2755
+ // Remover el sufijo de nivel de la etiqueta visual
2756
+ return params.name.split("___")[0];
2757
+ },
2758
+ },
2759
+ roam: true,
2760
+ data: nodes,
2761
+ links: Array.from(linksMap.values()),
2762
+ };
2763
+ const serie = merge$1({}, dynamicSerieOptions, overrides);
2764
+ if (this.colorResolver && !serie.itemStyle) {
2765
+ serie.itemStyle = {};
2766
+ }
2767
+ if (this.colorResolver && serie.itemStyle) {
2768
+ serie.itemStyle.color = this.colorResolver;
2769
+ }
2770
+ this.result.series = serie;
2771
+ }
2772
+ addTooltip(data, overrides) {
2773
+ merge$1(overrides, {
2774
+ formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
2775
+ });
2776
+ const tooltip = getTooltipOptions(overrides);
2777
+ this.result.tooltip = tooltip;
2778
+ }
2779
+ addPolar() { }
2780
+ addXAxis(data, overrides, type) { }
2781
+ addYAxis(data, overrides, type) { }
2782
+ addRadiusAxis(data, overrides) { }
2783
+ addAngleAxis(data, overrides) { }
2784
+ addLegend() { }
2785
+ addDataZoom() { }
2786
+ addDataset(data, opts) { }
2787
+ addCommons() {
2788
+ const opts = {
2789
+ palette: this.palette,
2790
+ };
2791
+ merge$1(this.result, getCommons(opts));
2792
+ }
2793
+ addGraphic() { }
2794
+ getResult() {
2795
+ return this.result;
2796
+ }
2797
+ setValueFormatter(formatter) {
2798
+ if (formatter) {
2799
+ this.valueFormatter = formatter;
2800
+ }
2801
+ }
2802
+ setPalette(palette) {
2803
+ if (palette) {
2804
+ this.palette = palette;
2805
+ }
2806
+ }
2807
+ setColorResolver(resolver) {
2808
+ if (resolver) {
2809
+ this.colorResolver = resolver;
2810
+ }
2811
+ }
2812
+ }
2813
+
2866
2814
  class EchartsSankeyComponent extends BaseEchartsComponent {
2867
2815
  baseSeriesOptions = {
2868
2816
  type: 'sankey',