@visionaris-bruno/vs-echarts 9.0.3 → 9.0.4

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.
@@ -237,11 +237,11 @@ class BaseEchartsComponent {
237
237
  data = { dimensions: [], source: [] };
238
238
  optionsOverrides = defaultOptionsOverrides();
239
239
  /** Paleta de colores básica */
240
- palette;
240
+ palette = getDefaultPalette();
241
241
  /** Resolver de colores dinámico (Callback) */
242
242
  colorResolver;
243
243
  /** Formateador de valores para etiquetas y tooltips */
244
- valueFormatter;
244
+ valueFormatter = (value) => value.toLocaleString();
245
245
  chartClick = new EventEmitter();
246
246
  /** Subject para debouncing de actualizaciones. ReplaySubject asegura no perder el primer renderizado. */
247
247
  updateSubject = new ReplaySubject(1);
@@ -1200,344 +1200,236 @@ class BoxPlotBuilder {
1200
1200
  }
1201
1201
 
1202
1202
  /**
1203
- * Director de Builds.
1203
+ * Builder principal.
1204
+ *
1205
+ * Es muy completo, tiene soporte para ejes y sistema cartesiano polar.
1206
+ *
1207
+ * Puede verse utilizado en graficos como Lineas y Bars. Siempre que se pueda priorizar utilizar este.
1204
1208
  */
1205
- class VSECDirector {
1206
- builder = undefined;
1207
- constructor(builder) {
1208
- this.builder = builder;
1209
- }
1210
- makeBar(data, overrides, opts = {}) {
1211
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1212
- x: 'category',
1213
- y: 'value',
1214
- // TODO agregar radius y angle axis
1215
- } } = opts;
1216
- this.builder.reset();
1217
- // El orden importa, primero callbaks y despues componentes.
1218
- //chart callbacks
1219
- this.builder.setValueFormatter(valueFormatter);
1220
- this.builder.setPalette(palette);
1221
- this.builder.setColorResolver(colorResolver);
1222
- const product = this.builder.baseProduct;
1223
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1224
- // chart components
1225
- this.builder.addCommons();
1226
- const layoutOpts = { axisTypes };
1227
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1228
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1229
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1230
- this.builder.addTooltip(data, overrides.tooltip);
1231
- this.builder.addLegend();
1232
- }
1233
- makeBarRadial(data, overrides, opts = {}) {
1234
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1235
- x: 'category',
1236
- y: 'value',
1237
- // TODO agregar radius y angle axis
1238
- } } = opts;
1239
- this.builder.reset();
1240
- // El orden importa, primero callbaks y despues componentes.
1241
- //chart callbacks
1242
- this.builder.setValueFormatter(valueFormatter);
1243
- this.builder.setPalette(palette);
1244
- this.builder.setColorResolver(colorResolver);
1245
- const product = this.builder.baseProduct;
1246
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1247
- // chart components
1248
- this.builder.addCommons();
1249
- const layoutOpts = { axisTypes, coordinateSystem: 'polar' };
1250
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1251
- this.builder.addPolar();
1252
- this.builder.addAngleAxis(data, overrides['axis']);
1253
- this.builder.addRadiusAxis(data, overrides['axis']);
1254
- this.builder.addTooltip(data, overrides.tooltip);
1255
- this.builder.addLegend();
1256
- }
1257
- makeLine(data, overrides, opts = {}) {
1258
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1259
- x: 'category',
1260
- y: 'value',
1261
- // TODO agregar radius y angle axis
1262
- } } = opts;
1263
- this.builder.reset();
1264
- // El orden importa, primero callbaks y despues componentes.
1265
- //chart callbacks
1266
- this.builder.setValueFormatter(valueFormatter);
1267
- this.builder.setPalette(palette);
1268
- this.builder.setColorResolver(colorResolver);
1269
- const product = this.builder.baseProduct;
1270
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1271
- // chart components
1272
- this.builder.addCommons();
1273
- const layoutOpts = { axisTypes };
1274
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1275
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1276
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1277
- this.builder.addTooltip(data, overrides.tooltip);
1278
- this.builder.addLegend();
1209
+ class EChartBuilder {
1210
+ baseProduct = undefined;
1211
+ valueFormatter = (value) => value.toLocaleString();
1212
+ palette = [];
1213
+ // TODO: Hay que implementar un valor por defecto.
1214
+ colorResolver;
1215
+ result = {};
1216
+ constructor(baseProduct) {
1217
+ this.baseProduct = baseProduct;
1279
1218
  }
1280
- makeScatter(data, overrides, opts = {}) {
1281
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1282
- x: 'category',
1283
- y: 'value',
1284
- } } = opts;
1285
- this.builder.reset();
1286
- // El orden importa, primero callbacks y despues componentes.
1287
- this.builder.setValueFormatter(valueFormatter);
1288
- this.builder.setPalette(palette);
1289
- this.builder.setColorResolver(colorResolver);
1290
- const product = this.builder.baseProduct;
1291
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1292
- // chart components
1293
- this.builder.addCommons();
1294
- const layoutOpts = { axisTypes };
1295
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1296
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1297
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1298
- this.builder.addTooltip(data, overrides.tooltip);
1299
- this.builder.addLegend();
1219
+ reset() {
1220
+ this.result = {};
1300
1221
  }
1301
- makeRing(data, overrides, opts = {}) {
1302
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1303
- this.builder.reset();
1304
- // El orden importa, primero callbacks y despues componentes.
1305
- this.builder.setValueFormatter(valueFormatter);
1306
- this.builder.setPalette(palette);
1307
- this.builder.setColorResolver(colorResolver);
1308
- const product = this.builder.baseProduct;
1309
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1310
- // chart components
1311
- this.builder.addCommons();
1312
- const layoutOpts = {};
1313
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1314
- this.builder.addGraphic();
1315
- this.builder.addTooltip(data, overrides.tooltip);
1316
- this.builder.addLegend();
1222
+ addCommons() {
1223
+ const opts = {
1224
+ palette: this.palette,
1225
+ };
1226
+ merge$1(this.result, getCommons(opts));
1317
1227
  }
1318
- makePie(data, overrides, opts = {}) {
1319
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1320
- this.builder.reset();
1321
- // El orden importa, primero callbacks y despues componentes.
1322
- this.builder.setValueFormatter(valueFormatter);
1323
- this.builder.setPalette(palette);
1324
- this.builder.setColorResolver(colorResolver);
1325
- const product = this.builder.baseProduct;
1326
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1327
- // chart components
1328
- this.builder.addCommons();
1329
- const layoutOpts = {};
1330
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1331
- this.builder.addTooltip(data, overrides.tooltip);
1332
- this.builder.addLegend();
1228
+ /**
1229
+ *
1230
+ * @param data
1231
+ * @param overrides
1232
+ * @returns
1233
+ */
1234
+ addSeries(data, overrides, opts) {
1235
+ if (!data || !data.dimensions || !data.source || data.source.length === 0)
1236
+ return;
1237
+ this.result.dataset = {
1238
+ dimensions: data.dimensions,
1239
+ source: data.source
1240
+ };
1241
+ const measureDims = data.dimensions.filter(d => d.name !== 'category');
1242
+ const isPolar = opts?.coordinateSystem === 'polar';
1243
+ const isHorizontal = opts?.axisTypes?.x === 'value' && opts?.axisTypes?.y === 'category';
1244
+ const series = measureDims.map((dim) => {
1245
+ const friendlyName = dim.displayName || dim.name;
1246
+ const dimKey = dim.name;
1247
+ let encode = {
1248
+ x: 'category',
1249
+ y: dimKey
1250
+ };
1251
+ if (isPolar) {
1252
+ encode = {
1253
+ angle: 'category',
1254
+ radius: dimKey
1255
+ };
1256
+ }
1257
+ else if (isHorizontal) {
1258
+ encode = {
1259
+ x: dimKey,
1260
+ y: 'category'
1261
+ };
1262
+ }
1263
+ const dynamicOverrides = {
1264
+ name: friendlyName,
1265
+ encode,
1266
+ label: {
1267
+ formatter: (params) => {
1268
+ const row = params.value;
1269
+ const rawValue = (row && typeof row === 'object') ? row[dimKey] : params.value;
1270
+ return this.formatCellValue(Number(rawValue ?? 0), dimKey);
1271
+ }
1272
+ }
1273
+ };
1274
+ const seriesOption = merge$1(dynamicOverrides, overrides);
1275
+ // Inyectar el resolver de color si existe
1276
+ if (this.colorResolver && seriesOption.itemStyle) {
1277
+ seriesOption.itemStyle.color = this.colorResolver;
1278
+ }
1279
+ return seriesOption;
1280
+ });
1281
+ this.result.series = series;
1333
1282
  }
1334
- makeFunnel(data, overrides, opts = {}) {
1335
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1336
- this.builder.reset();
1337
- // El orden importa, primero callbacks y despues componentes.
1338
- this.builder.setValueFormatter(valueFormatter);
1339
- this.builder.setPalette(palette);
1340
- this.builder.setColorResolver(colorResolver);
1341
- const product = this.builder.baseProduct;
1342
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1343
- // chart components
1344
- this.builder.addCommons();
1345
- const layoutOpts = {};
1346
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1347
- this.builder.addTooltip(data, overrides.tooltip);
1348
- this.builder.addLegend();
1283
+ /**
1284
+ * TODO: Mejorar funcion, no me convence como se implemento el tooltip formatter.
1285
+ * @param data
1286
+ * @param overrides
1287
+ */
1288
+ addTooltip(data, overrides) {
1289
+ // inyecto formateador a overrides de tooltip
1290
+ merge$1(overrides, {
1291
+ formatter: getTooltipFormatter(overrides.trigger, data, this.formatCellValue.bind(this)),
1292
+ });
1293
+ const tooltip = getTooltipOptions(overrides);
1294
+ this.result.tooltip = tooltip;
1349
1295
  }
1350
- makeSunburst(data, overrides, opts = {}) {
1351
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1352
- this.builder.reset();
1353
- // El orden importa, primero callbacks y despues componentes.
1354
- this.builder.setValueFormatter(valueFormatter);
1355
- this.builder.setPalette(palette);
1356
- this.builder.setColorResolver(colorResolver);
1357
- const product = this.builder.baseProduct;
1358
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1359
- // chart components
1360
- this.builder.addCommons();
1361
- const layoutOpts = {};
1362
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1363
- this.builder.addTooltip(data, overrides.tooltip);
1364
- // this.builder.addLegend();
1296
+ addPolar() {
1297
+ const polar = [];
1298
+ polar.push({
1299
+ radius: '65%',
1300
+ center: ["50%", "44%"],
1301
+ });
1302
+ this.result.polar = polar;
1365
1303
  }
1366
- makeSankey(data, overrides, opts = {}) {
1367
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
1368
- this.builder.reset();
1369
- // El orden importa, primero callbacks y despues componentes.
1370
- this.builder.setValueFormatter(valueFormatter);
1371
- this.builder.setPalette(palette);
1372
- this.builder.setColorResolver(colorResolver);
1373
- const product = this.builder.baseProduct;
1374
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1375
- // chart components
1376
- this.builder.addCommons();
1377
- const layoutOpts = {};
1378
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1379
- this.builder.addTooltip(data, overrides.tooltip);
1304
+ addXAxis(data, overrides, type = 'category') {
1305
+ const xAxis = [];
1306
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1307
+ const valueAxisOptions = this.getValueAxisOptions(data, overrides);
1308
+ if (type == 'category') {
1309
+ xAxis.push(categoryAxisOptions);
1310
+ }
1311
+ else if (type == 'value') {
1312
+ xAxis.push(valueAxisOptions);
1313
+ }
1314
+ this.result.xAxis = xAxis;
1380
1315
  }
1381
- makeBoxplot(data, overrides, opts = {}) {
1382
- if (this.builder instanceof BoxPlotBuilder == false) {
1383
- return;
1316
+ addYAxis(data, overrides, type = 'value') {
1317
+ const yAxis = [];
1318
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1319
+ const valueAxisOptions = this.getValueAxisOptions(data, overrides);
1320
+ if (type == 'category') {
1321
+ yAxis.push(categoryAxisOptions);
1384
1322
  }
1385
- const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1386
- x: 'value',
1387
- y: 'category',
1388
- }, } = opts;
1389
- this.builder.reset();
1390
- // El orden importa, primero callbacks y despues componentes.
1391
- this.builder.setValueFormatter(valueFormatter);
1392
- this.builder.setPalette(palette);
1393
- this.builder.setColorResolver(colorResolver);
1394
- const product = this.builder.baseProduct;
1395
- const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1396
- // chart components
1397
- this.builder.addCommons();
1398
- const layoutOpts = { axisTypes };
1399
- this.builder.addDataset(data);
1400
- this.builder.addSeries(data, seriesOverrides, layoutOpts);
1401
- this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1402
- this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1403
- this.builder.addTooltip(data, overrides.tooltip);
1404
- this.builder.addDataZoom();
1323
+ else if (type == 'value') {
1324
+ yAxis.push(valueAxisOptions);
1325
+ }
1326
+ this.result.yAxis = yAxis;
1405
1327
  }
1406
- }
1407
-
1408
- /**
1409
- * EchartsRingComponent
1410
- *
1411
- * Especialista en visualización de tipo Ring. Soporta multi-medidas y KPI central.
1412
- * @see {@link vs-echarts/docs/charts/ring-patterns.md}
1413
- */
1414
- class EchartsRingComponent extends BaseEchartsComponent {
1415
- baseSeriesOptions = {
1416
- type: 'pie',
1417
- center: ['50%', '50%'],
1418
- avoidLabelOverlap: true,
1419
- minAngle: 3,
1420
- selectedMode: 'single',
1421
- selectedOffset: 4,
1422
- itemStyle: {
1423
- borderColor: '#fff',
1424
- },
1425
- label: { show: false },
1426
- emphasis: {
1427
- scale: true,
1428
- scaleSize: 2,
1429
- },
1430
- select: {
1431
- itemStyle: {
1432
- borderColor: EChartsTokens.sBorderColor,
1433
- shadowColor: EChartsTokens.sShadowColor,
1434
- borderWidth: 1,
1435
- shadowBlur: 4,
1328
+ addRadiusAxis(data, overrides) {
1329
+ const radiusAxis = [];
1330
+ /** estilos exclusivos hardcodeados para el eje de valores del sistema de coordenadas polar*/
1331
+ const radiusAxisOverrides = {
1332
+ zlevel: 10,
1333
+ axisTick: {
1334
+ show: false,
1436
1335
  },
1437
- },
1438
- animationType: 'scale',
1439
- animationEasing: 'elasticOut',
1440
- };
1441
- baseProduct = {
1442
- chartKey: 'ring',
1443
- baseOptions: {
1444
- series: this.baseSeriesOptions,
1445
- }
1446
- };
1447
- builder = new RingBuilder(this.baseProduct);
1448
- director = new VSECDirector(this.builder);
1449
- lastSelectedSeriesIndex = null;
1450
- lastSelectedDataIndex = null;
1451
- selectedPercent = null;
1452
- currentGraphicText = '';
1453
- constructor() {
1454
- super();
1455
- }
1456
- make() {
1457
- const makeOpts = {
1458
- valueFormatter: this.valueFormatter,
1459
- palette: this.palette,
1460
- colorResolver: this.colorResolver,
1336
+ axisLabel: {
1337
+ margin: 2,
1338
+ fontSize: 8,
1339
+ align: 'right',
1340
+ rotate: 20,
1341
+ verticalAlign: 'top',
1342
+ },
1343
+ splitLine: {
1344
+ show: true,
1345
+ lineStyle: {
1346
+ opacity: 0.2,
1347
+ type: 'solid',
1348
+ }
1349
+ },
1350
+ axisLine: {
1351
+ lineStyle: {
1352
+ type: 'dashed',
1353
+ },
1354
+ }
1461
1355
  };
1462
- this.director.makeRing(this.data, this.optionsOverrides, makeOpts);
1356
+ const radialAxisOptions = getValueAxisOptions(radiusAxisOverrides);
1357
+ radiusAxis.push(radialAxisOptions);
1358
+ this.result.radiusAxis = radiusAxis;
1463
1359
  }
1464
- onInputChanges(changes) {
1465
- // Reset selection only if data changed
1466
- if (changes['data']) {
1467
- this.lastSelectedSeriesIndex = null;
1468
- this.lastSelectedDataIndex = null;
1469
- this.selectedPercent = null;
1470
- this.currentGraphicText = '';
1471
- }
1472
- super.onInputChanges(changes);
1360
+ addAngleAxis(data, overrides) {
1361
+ const angleAxis = [];
1362
+ const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
1363
+ angleAxis.push(categoryAxisOptions);
1364
+ this.result.angleAxis = angleAxis;
1365
+ }
1366
+ addLegend() {
1367
+ this.result.legend = getLegendOptions();
1368
+ }
1369
+ // No-ops for ring charts
1370
+ addGraphic() { }
1371
+ addDataset(data) { }
1372
+ addDataZoom() {
1373
+ this.result.dataZoom = [
1374
+ {
1375
+ type: 'inside'
1376
+ },
1377
+ {
1378
+ type: 'slider',
1379
+ height: 20,
1380
+ bottom: 60
1381
+ }
1382
+ ];
1383
+ }
1384
+ getResult() {
1385
+ return this.result;
1473
1386
  }
1387
+ ;
1474
1388
  /**
1475
- * Maneja clics en los sectores del ring.
1476
- * Soporta múltiples series (anillos) y actualiza el KPI central.
1389
+ * Formatea un valor utilizando el callback inyectado.
1477
1390
  */
1478
- onChartClick(event) {
1479
- if (this.chartInstance && event && event.dataIndex !== undefined) {
1480
- const isSameSelection = event.seriesIndex === this.lastSelectedSeriesIndex &&
1481
- event.dataIndex === this.lastSelectedDataIndex;
1482
- if (isSameSelection) {
1483
- // Toggle OFF
1484
- this.lastSelectedSeriesIndex = null;
1485
- this.lastSelectedDataIndex = null;
1486
- this.selectedPercent = null;
1487
- this.setGraphicText('');
1488
- }
1489
- else {
1490
- // SELECT
1491
- this.lastSelectedSeriesIndex = event.seriesIndex;
1492
- this.lastSelectedDataIndex = event.dataIndex;
1493
- this.selectedPercent = (event.percent !== undefined) ? event.percent + '%' : '';
1494
- this.setGraphicText(this.selectedPercent);
1495
- }
1496
- this.chartClick.emit({
1497
- type: 'cross-filter',
1498
- data: {
1499
- category: event.name,
1500
- serie: event.seriesName,
1501
- value: event.value
1502
- }
1503
- });
1504
- }
1391
+ formatCellValue(value, key) {
1392
+ return this.valueFormatter(value, key);
1505
1393
  }
1506
- onChartMouseOver(event) {
1507
- if (this.selectedPercent === null && event && event.percent !== undefined) {
1508
- this.setGraphicText(event.percent + '%');
1394
+ // Setters
1395
+ /**
1396
+ * Permite inyectar un formateador de valores externo.
1397
+ */
1398
+ setValueFormatter(formatter) {
1399
+ if (formatter) {
1400
+ this.valueFormatter = formatter;
1509
1401
  }
1510
1402
  }
1511
- onChartMouseOut(event) {
1512
- if (this.selectedPercent === null) {
1513
- this.setGraphicText('');
1403
+ /**
1404
+ * Permite inyectar una paleta de colores básica.
1405
+ */
1406
+ setPalette(palette) {
1407
+ if (palette) {
1408
+ this.palette = palette;
1514
1409
  }
1515
1410
  }
1516
1411
  /**
1517
- * Actualiza el texto del Graphic central y persiste la selección en el modelo de opciones.
1412
+ * Permite inyectar un resolver de colores dinámico.
1518
1413
  */
1519
- setGraphicText(text) {
1520
- this.currentGraphicText = text;
1521
- // Persistencia de GRAPHIC (KPI central)
1522
- this.chartInstance?.setOption({
1523
- graphic: {
1524
- style: {
1525
- text: this.currentGraphicText,
1526
- opacity: this.currentGraphicText ? 1 : 0,
1527
- }
1528
- }
1529
- });
1414
+ setColorResolver(resolver) {
1415
+ if (resolver) {
1416
+ this.colorResolver = resolver;
1417
+ }
1418
+ }
1419
+ // Utils
1420
+ getCategoryAxisOptions(data, overrides) {
1421
+ // No explicit data needed on category axis when using ECharts dataset
1422
+ const categoryAxisOptionsOverrides = {
1423
+ ...overrides.categoryAxis[0]
1424
+ };
1425
+ const categoryAxisOptions = getCategoryAxisOptions(categoryAxisOptionsOverrides);
1426
+ return categoryAxisOptions;
1427
+ }
1428
+ getValueAxisOptions(data, overrides) {
1429
+ const valueAxisOptions = getValueAxisOptions();
1430
+ return valueAxisOptions;
1530
1431
  }
1531
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1532
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsRingComponent, isStandalone: true, selector: "vs-echarts-ring", 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"] }] });
1533
1432
  }
1534
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, decorators: [{
1535
- type: Component,
1536
- args: [{ selector: 'vs-echarts-ring', standalone: true, imports: [
1537
- CommonModule,
1538
- NgxEchartsDirective,
1539
- ], 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"] }]
1540
- }], ctorParameters: () => [] });
1541
1433
 
1542
1434
  /**
1543
1435
  * PieBuilder
@@ -1702,78 +1594,18 @@ class PieBuilder {
1702
1594
  }
1703
1595
 
1704
1596
  /**
1705
- * EchartsPieComponent
1597
+ * FunnelBuilder
1706
1598
  *
1707
- * Especialista en visualización de tipo Pie (Torta y Anillos concéntricos).
1708
- * La primera serie se dibuja como un gráfico de torta tradicional (lleno) y
1709
- * las subsecuentes como anillos concéntricos alrededor.
1599
+ * Concrete builder for Funnel charts.
1710
1600
  */
1711
- class EchartsPieComponent extends BaseEchartsComponent {
1712
- baseSeriesOptions = {
1713
- type: 'pie',
1714
- center: ['50%', '50%'],
1715
- avoidLabelOverlap: true,
1716
- minAngle: 3,
1717
- selectedMode: 'single',
1718
- selectedOffset: 4,
1719
- emphasis: {
1720
- scale: true,
1721
- scaleSize: 2,
1722
- },
1723
- select: {
1724
- itemStyle: {
1725
- borderColor: EChartsTokens.sBorderColor,
1726
- shadowColor: EChartsTokens.sShadowColor,
1727
- borderWidth: 1,
1728
- shadowBlur: 4,
1729
- },
1730
- },
1731
- animationType: 'scale',
1732
- animationEasing: 'elasticOut',
1733
- };
1734
- baseProduct = {
1735
- chartKey: 'pie',
1736
- baseOptions: {
1737
- series: this.baseSeriesOptions,
1738
- }
1739
- };
1740
- builder = new PieBuilder(this.baseProduct);
1741
- director = new VSECDirector(this.builder);
1742
- constructor() {
1743
- super();
1744
- }
1745
- make() {
1746
- const makeOpts = {
1747
- valueFormatter: this.valueFormatter,
1748
- palette: this.palette,
1749
- colorResolver: this.colorResolver,
1750
- };
1751
- this.director.makePie(this.data, this.optionsOverrides, makeOpts);
1752
- }
1753
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1754
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsPieComponent, isStandalone: true, selector: "vs-echarts-pie", 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"] }] });
1755
- }
1756
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, decorators: [{
1757
- type: Component,
1758
- args: [{ selector: 'vs-echarts-pie', standalone: true, imports: [
1759
- CommonModule,
1760
- NgxEchartsDirective,
1761
- ], 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"] }]
1762
- }], ctorParameters: () => [] });
1763
-
1764
- /**
1765
- * FunnelBuilder
1766
- *
1767
- * Concrete builder for Funnel charts.
1768
- */
1769
- class FunnelBuilder {
1770
- baseProduct;
1771
- valueFormatter = (value) => value.toLocaleString();
1772
- palette = [];
1773
- colorResolver;
1774
- result = {};
1775
- constructor(baseProduct) {
1776
- this.baseProduct = baseProduct;
1601
+ class FunnelBuilder {
1602
+ baseProduct;
1603
+ valueFormatter = (value) => value.toLocaleString();
1604
+ palette = [];
1605
+ colorResolver;
1606
+ result = {};
1607
+ constructor(baseProduct) {
1608
+ this.baseProduct = baseProduct;
1777
1609
  }
1778
1610
  reset() {
1779
1611
  this.result = {};
@@ -1865,91 +1697,10 @@ class FunnelBuilder {
1865
1697
  }
1866
1698
  }
1867
1699
 
1868
- /**
1869
- * EchartsFunnelComponent
1870
- *
1871
- * Component for Funnel visualization. Supports single and multiple measures.
1872
- */
1873
- class EchartsFunnelComponent extends BaseEchartsComponent {
1874
- baseSeriesOptions = {
1875
- type: 'funnel',
1876
- left: '10%',
1877
- width: '80%',
1878
- minSize: '0.01%',
1879
- maxSize: '100%',
1880
- sort: 'descending',
1881
- gap: 2,
1882
- label: {
1883
- show: true,
1884
- position: 'inside'
1885
- },
1886
- labelLine: {
1887
- show: false
1888
- },
1889
- itemStyle: {
1890
- borderColor: '#fff',
1891
- borderWidth: 1
1892
- },
1893
- emphasis: {
1894
- label: {
1895
- fontSize: 16
1896
- }
1897
- },
1898
- selectedMode: 'single',
1899
- select: {
1900
- label: {
1901
- fontSize: 16
1902
- },
1903
- itemStyle: {
1904
- borderWidth: 1,
1905
- borderColor: EChartsTokens.sBorderColor,
1906
- shadowColor: EChartsTokens.sShadowColor,
1907
- shadowBlur: 6,
1908
- }
1909
- },
1910
- };
1911
- baseProduct = {
1912
- chartKey: 'funnel',
1913
- baseOptions: {
1914
- series: this.baseSeriesOptions,
1915
- }
1916
- };
1917
- builder = new FunnelBuilder(this.baseProduct);
1918
- director = new VSECDirector(this.builder);
1919
- constructor() {
1920
- super();
1921
- }
1922
- make() {
1923
- const makeOpts = {
1924
- valueFormatter: this.valueFormatter,
1925
- palette: this.palette,
1926
- colorResolver: this.colorResolver,
1927
- };
1928
- this.director.makeFunnel(this.data, this.optionsOverrides, makeOpts);
1929
- }
1930
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1931
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsFunnelComponent, isStandalone: true, selector: "vs-echarts-funnel", 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"] }] });
1932
- }
1933
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, decorators: [{
1934
- type: Component,
1935
- args: [{ selector: 'vs-echarts-funnel', standalone: true, imports: [
1936
- CommonModule,
1937
- NgxEchartsDirective,
1938
- ], 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"] }]
1939
- }], ctorParameters: () => [] });
1940
-
1941
- /**
1942
- * Builder principal.
1943
- *
1944
- * Es muy completo, tiene soporte para ejes y sistema cartesiano polar.
1945
- *
1946
- * Puede verse utilizado en graficos como Lineas y Bars. Siempre que se pueda priorizar utilizar este.
1947
- */
1948
- class EChartBuilder {
1949
- baseProduct = undefined;
1700
+ class SunburstBuilder {
1701
+ baseProduct;
1950
1702
  valueFormatter = (value) => value.toLocaleString();
1951
1703
  palette = [];
1952
- // TODO: Hay que implementar un valor por defecto.
1953
1704
  colorResolver;
1954
1705
  result = {};
1955
1706
  constructor(baseProduct) {
@@ -1958,217 +1709,779 @@ class EChartBuilder {
1958
1709
  reset() {
1959
1710
  this.result = {};
1960
1711
  }
1961
- addCommons() {
1962
- const opts = {
1963
- palette: this.palette,
1964
- };
1965
- merge$1(this.result, getCommons(opts));
1966
- }
1967
- /**
1968
- *
1969
- * @param data
1970
- * @param overrides
1971
- * @returns
1972
- */
1973
- addSeries(data, overrides, opts) {
1974
- if (!data || !data.dimensions || !data.source || data.source.length === 0)
1712
+ addSeries(data, overrides) {
1713
+ if (!data || !data.source || data.source.length === 0) {
1975
1714
  return;
1976
- this.result.dataset = {
1977
- dimensions: data.dimensions,
1978
- source: data.source
1979
- };
1980
- const measureDims = data.dimensions.filter(d => d.name !== 'category');
1981
- const isPolar = opts?.coordinateSystem === 'polar';
1982
- const isHorizontal = opts?.axisTypes?.x === 'value' && opts?.axisTypes?.y === 'category';
1983
- const series = measureDims.map((dim) => {
1984
- const friendlyName = dim.displayName || dim.name;
1985
- const dimKey = dim.name;
1986
- let encode = {
1987
- x: 'category',
1988
- y: dimKey
1989
- };
1990
- if (isPolar) {
1991
- encode = {
1992
- angle: 'category',
1993
- radius: dimKey
1994
- };
1995
- }
1996
- else if (isHorizontal) {
1997
- encode = {
1998
- x: dimKey,
1999
- y: 'category'
2000
- };
2001
- }
2002
- const dynamicOverrides = {
2003
- name: friendlyName,
2004
- encode,
1715
+ }
1716
+ const sunburstData = mapHierarchicalData(data.source, data.dimensions);
1717
+ const depth = getTreeDepth(sunburstData);
1718
+ const levels = [];
1719
+ for (let i = 0; i <= depth; i++) {
1720
+ levels.push({
2005
1721
  label: {
2006
- formatter: (params) => {
2007
- const row = params.value;
2008
- const rawValue = (row && typeof row === 'object') ? row[dimKey] : params.value;
2009
- return this.formatCellValue(Number(rawValue ?? 0), dimKey);
2010
- }
2011
- }
2012
- };
2013
- const seriesOption = merge$1(dynamicOverrides, overrides);
2014
- // Inyectar el resolver de color si existe
2015
- if (this.colorResolver && seriesOption.itemStyle) {
2016
- seriesOption.itemStyle.color = this.colorResolver;
1722
+ show: false,
1723
+ },
1724
+ });
1725
+ }
1726
+ const dynamiSerieOptions = {
1727
+ name: '',
1728
+ data: sunburstData,
1729
+ levels: levels
1730
+ };
1731
+ const serie = merge$1({}, dynamiSerieOptions, overrides);
1732
+ if (this.colorResolver) {
1733
+ if (!serie.itemStyle) {
1734
+ serie.itemStyle = {};
2017
1735
  }
2018
- return seriesOption;
2019
- });
2020
- this.result.series = series;
1736
+ serie.itemStyle.color = this.colorResolver;
1737
+ }
1738
+ this.result.series = serie;
2021
1739
  }
2022
- /**
2023
- * TODO: Mejorar funcion, no me convence como se implemento el tooltip formatter.
2024
- * @param data
2025
- * @param overrides
2026
- */
2027
1740
  addTooltip(data, overrides) {
2028
- // inyecto formateador a overrides de tooltip
2029
1741
  merge$1(overrides, {
2030
- formatter: getTooltipFormatter(overrides.trigger, data, this.formatCellValue.bind(this)),
1742
+ formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
2031
1743
  });
2032
1744
  const tooltip = getTooltipOptions(overrides);
2033
1745
  this.result.tooltip = tooltip;
2034
1746
  }
2035
- addPolar() {
2036
- const polar = [];
2037
- polar.push({
2038
- radius: '65%',
2039
- center: ["50%", "44%"],
2040
- });
2041
- this.result.polar = polar;
1747
+ addCommons() {
1748
+ const opts = {
1749
+ palette: this.palette,
1750
+ };
1751
+ merge$1(this.result, getCommons(opts));
2042
1752
  }
2043
- addXAxis(data, overrides, type = 'category') {
2044
- const xAxis = [];
2045
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
2046
- const valueAxisOptions = this.getValueAxisOptions(data, overrides);
2047
- if (type == 'category') {
2048
- xAxis.push(categoryAxisOptions);
2049
- }
2050
- else if (type == 'value') {
2051
- xAxis.push(valueAxisOptions);
2052
- }
2053
- this.result.xAxis = xAxis;
1753
+ getResult() {
1754
+ return this.result;
2054
1755
  }
2055
- addYAxis(data, overrides, type = 'value') {
2056
- const yAxis = [];
2057
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
2058
- const valueAxisOptions = this.getValueAxisOptions(data, overrides);
2059
- if (type == 'category') {
2060
- yAxis.push(categoryAxisOptions);
2061
- }
2062
- else if (type == 'value') {
2063
- yAxis.push(valueAxisOptions);
1756
+ ;
1757
+ // No-ops
1758
+ addPolar() { }
1759
+ addXAxis(data, overrides, type) { }
1760
+ addYAxis(data, overrides, type) { }
1761
+ addRadiusAxis(data, overrides) { }
1762
+ addAngleAxis(data, overrides) { }
1763
+ addLegend() { }
1764
+ addDataZoom() { }
1765
+ addDataset(data, opts) { }
1766
+ addGraphic() { }
1767
+ // Setters
1768
+ /**
1769
+ * Permite inyectar un formateador de valores externo.
1770
+ */
1771
+ setValueFormatter(formatter) {
1772
+ if (formatter) {
1773
+ this.valueFormatter = formatter;
2064
1774
  }
2065
- this.result.yAxis = yAxis;
2066
1775
  }
2067
- addRadiusAxis(data, overrides) {
2068
- const radiusAxis = [];
2069
- /** estilos exclusivos hardcodeados para el eje de valores del sistema de coordenadas polar*/
2070
- const radiusAxisOverrides = {
2071
- zlevel: 10,
2072
- axisTick: {
2073
- show: false,
1776
+ /**
1777
+ * Permite inyectar una paleta de colores básica.
1778
+ */
1779
+ setPalette(palette) {
1780
+ if (palette) {
1781
+ this.palette = palette;
1782
+ }
1783
+ }
1784
+ /**
1785
+ * Permite inyectar un resolver de colores dinámico.
1786
+ */
1787
+ setColorResolver(resolver) {
1788
+ if (resolver) {
1789
+ this.colorResolver = resolver;
1790
+ }
1791
+ }
1792
+ }
1793
+
1794
+ /**
1795
+ * SankeyBuilder
1796
+ *
1797
+ * Builder concreto para el gráfico Sankey (diagrama de flujos de izquierda a derecha).
1798
+ */
1799
+ class SankeyBuilder {
1800
+ baseProduct;
1801
+ valueFormatter = (value) => value.toLocaleString();
1802
+ palette = [];
1803
+ colorResolver;
1804
+ result = {};
1805
+ constructor(baseProduct) {
1806
+ this.baseProduct = baseProduct;
1807
+ }
1808
+ reset() {
1809
+ this.result = {};
1810
+ }
1811
+ addSeries(data, overrides) {
1812
+ if (!data || !data.source || data.source.length === 0) {
1813
+ return;
1814
+ }
1815
+ // Identificar medidas (todas las dimensiones excepto 'category')
1816
+ const measureKeys = data.dimensions
1817
+ .filter((d) => d.name !== "category")
1818
+ .map((d) => d.name);
1819
+ // Función auxiliar para sumarizar valores de medidas en caso de haber más de una
1820
+ const getNodeValue = (node) => {
1821
+ return measureKeys.reduce((sum, key) => sum + (Number(node[key]) || 0), 0);
1822
+ };
1823
+ const nodesMap = new Map();
1824
+ const linksMap = new Map();
1825
+ // Función recursiva para aplanar datos jerárquicos a nodos y enlaces
1826
+ const traverse = (nodeList, level, parentId) => {
1827
+ for (const node of nodeList) {
1828
+ const category = node.category;
1829
+ const currentId = `${category}___${level}`;
1830
+ const value = getNodeValue(node);
1831
+ nodesMap.set(currentId, (nodesMap.get(currentId) || 0) + value);
1832
+ if (parentId) {
1833
+ const linkKey = `${parentId}--->${currentId}`;
1834
+ if (linksMap.has(linkKey)) {
1835
+ linksMap.get(linkKey).value += value;
1836
+ }
1837
+ else {
1838
+ linksMap.set(linkKey, {
1839
+ source: parentId,
1840
+ target: currentId,
1841
+ value: value,
1842
+ });
1843
+ }
1844
+ }
1845
+ if (node.children && node.children.length > 0) {
1846
+ traverse(node.children, level + 1, currentId);
1847
+ }
1848
+ }
1849
+ };
1850
+ // Comenzar el recorrido en el nivel 0
1851
+ traverse(data.source, 0);
1852
+ // al menos un nivel de links para dibujar.
1853
+ if (linksMap.size === 0)
1854
+ return;
1855
+ // Mapear nodos acumulados a la estructura requerida por ECharts (name y opcionalmente color, sin value redundante)
1856
+ const nodes = Array.from(nodesMap.keys()).map((currentId) => {
1857
+ const category = currentId.split("___")[0];
1858
+ const nodeItem = {
1859
+ name: currentId,
1860
+ };
1861
+ if (this.colorResolver) {
1862
+ const color = this.colorResolver({ name: category, data: nodeItem });
1863
+ if (color) {
1864
+ nodeItem.itemStyle = { color };
1865
+ }
1866
+ }
1867
+ return nodeItem;
1868
+ });
1869
+ const dynamicSerieOptions = {
1870
+ type: "sankey",
1871
+ orient: "horizontal", // De izquierda a derecha
1872
+ draggable: true,
1873
+ emphasis: {
1874
+ focus: "adjacency",
2074
1875
  },
2075
- axisLabel: {
2076
- margin: 2,
2077
- fontSize: 8,
2078
- align: 'right',
2079
- rotate: 20,
2080
- verticalAlign: 'top',
1876
+ lineStyle: {
1877
+ color: "source",
1878
+ opacity: 0.25,
1879
+ curveness: 0.5,
2081
1880
  },
2082
- splitLine: {
1881
+ label: {
2083
1882
  show: true,
2084
- lineStyle: {
2085
- opacity: 0.2,
2086
- type: 'solid',
2087
- }
2088
- },
2089
- axisLine: {
2090
- lineStyle: {
2091
- type: 'dashed',
1883
+ position: "right",
1884
+ fontFamily: "'Inter', 'Roboto', 'Open Sans', sans-serif",
1885
+ fontSize: 10,
1886
+ formatter: (params) => {
1887
+ // Remover el sufijo de nivel de la etiqueta visual
1888
+ return params.name.split("___")[0];
2092
1889
  },
2093
- }
1890
+ },
1891
+ roam: true,
1892
+ data: nodes,
1893
+ links: Array.from(linksMap.values()),
2094
1894
  };
2095
- const radialAxisOptions = getValueAxisOptions(radiusAxisOverrides);
2096
- radiusAxis.push(radialAxisOptions);
2097
- this.result.radiusAxis = radiusAxis;
2098
- }
2099
- addAngleAxis(data, overrides) {
2100
- const angleAxis = [];
2101
- const categoryAxisOptions = this.getCategoryAxisOptions(data, overrides);
2102
- angleAxis.push(categoryAxisOptions);
2103
- this.result.angleAxis = angleAxis;
1895
+ const serie = merge$1({}, dynamicSerieOptions, overrides);
1896
+ if (this.colorResolver && !serie.itemStyle) {
1897
+ serie.itemStyle = {};
1898
+ }
1899
+ if (this.colorResolver && serie.itemStyle) {
1900
+ serie.itemStyle.color = this.colorResolver;
1901
+ }
1902
+ this.result.series = serie;
2104
1903
  }
2105
- addLegend() {
2106
- this.result.legend = getLegendOptions();
1904
+ addTooltip(data, overrides) {
1905
+ merge$1(overrides, {
1906
+ formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
1907
+ });
1908
+ const tooltip = getTooltipOptions(overrides);
1909
+ this.result.tooltip = tooltip;
2107
1910
  }
2108
- // No-ops for ring charts
2109
- addGraphic() { }
1911
+ addPolar() { }
1912
+ addXAxis(data, overrides, type) { }
1913
+ addYAxis(data, overrides, type) { }
1914
+ addRadiusAxis(data, overrides) { }
1915
+ addAngleAxis(data, overrides) { }
1916
+ addLegend() { }
1917
+ addDataZoom() { }
2110
1918
  addDataset(data, opts) { }
2111
- addDataZoom() {
2112
- this.result.dataZoom = [
2113
- {
2114
- type: 'inside'
2115
- },
2116
- {
2117
- type: 'slider',
2118
- height: 20,
2119
- bottom: 60
2120
- }
2121
- ];
1919
+ addCommons() {
1920
+ const opts = {
1921
+ palette: this.palette,
1922
+ };
1923
+ merge$1(this.result, getCommons(opts));
2122
1924
  }
1925
+ addGraphic() { }
2123
1926
  getResult() {
2124
1927
  return this.result;
2125
1928
  }
2126
- ;
2127
- /**
2128
- * Formatea un valor utilizando el callback inyectado.
2129
- */
2130
- formatCellValue(value, key) {
2131
- return this.valueFormatter(value, key);
2132
- }
2133
- // Setters
2134
- /**
2135
- * Permite inyectar un formateador de valores externo.
2136
- */
2137
1929
  setValueFormatter(formatter) {
2138
1930
  if (formatter) {
2139
1931
  this.valueFormatter = formatter;
2140
1932
  }
2141
1933
  }
2142
- /**
2143
- * Permite inyectar una paleta de colores básica.
2144
- */
2145
1934
  setPalette(palette) {
2146
1935
  if (palette) {
2147
1936
  this.palette = palette;
2148
1937
  }
2149
1938
  }
2150
- /**
2151
- * Permite inyectar un resolver de colores dinámico.
2152
- */
2153
1939
  setColorResolver(resolver) {
2154
1940
  if (resolver) {
2155
1941
  this.colorResolver = resolver;
2156
1942
  }
2157
1943
  }
2158
- // Utils
2159
- getCategoryAxisOptions(data, overrides) {
2160
- // No explicit data needed on category axis when using ECharts dataset
2161
- const categoryAxisOptionsOverrides = {
2162
- ...overrides.categoryAxis[0]
2163
- };
2164
- const categoryAxisOptions = getCategoryAxisOptions(categoryAxisOptionsOverrides);
2165
- return categoryAxisOptions;
1944
+ }
1945
+
1946
+ /**
1947
+ * Director de Builds.
1948
+ */
1949
+ class VSECDirector {
1950
+ builder = undefined;
1951
+ constructor(builder) {
1952
+ this.builder = builder;
2166
1953
  }
2167
- getValueAxisOptions(data, overrides) {
2168
- const valueAxisOptions = getValueAxisOptions();
2169
- return valueAxisOptions;
1954
+ makeBar(data, overrides, opts = {}) {
1955
+ if (this.builder instanceof EChartBuilder == false) {
1956
+ return;
1957
+ }
1958
+ ;
1959
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1960
+ x: 'category',
1961
+ y: 'value',
1962
+ // TODO agregar radius y angle axis
1963
+ } } = opts;
1964
+ this.builder.reset();
1965
+ // El orden importa, primero callbacks y despues componentes.
1966
+ // chart callbaks
1967
+ if (valueFormatter)
1968
+ this.builder.setValueFormatter(valueFormatter);
1969
+ if (palette)
1970
+ this.builder.setPalette(palette);
1971
+ if (colorResolver)
1972
+ this.builder.setColorResolver(colorResolver);
1973
+ const product = this.builder.baseProduct;
1974
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
1975
+ // chart components
1976
+ this.builder.addCommons();
1977
+ const seriesOptions = { axisTypes };
1978
+ this.builder.addSeries(data, seriesOverrides, seriesOptions);
1979
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
1980
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
1981
+ this.builder.addTooltip(data, overrides.tooltip);
1982
+ this.builder.addLegend();
1983
+ }
1984
+ makeBarRadial(data, overrides, opts = {}) {
1985
+ if (this.builder instanceof EChartBuilder == false) {
1986
+ return;
1987
+ }
1988
+ ;
1989
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
1990
+ x: 'category',
1991
+ y: 'value',
1992
+ // TODO agregar radius y angle axis
1993
+ } } = opts;
1994
+ this.builder.reset();
1995
+ // El orden importa, primero callbacks y despues componentes.
1996
+ // chart callbaks
1997
+ if (valueFormatter)
1998
+ this.builder.setValueFormatter(valueFormatter);
1999
+ if (palette)
2000
+ this.builder.setPalette(palette);
2001
+ if (colorResolver)
2002
+ this.builder.setColorResolver(colorResolver);
2003
+ const product = this.builder.baseProduct;
2004
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2005
+ // chart components
2006
+ this.builder.addCommons();
2007
+ const seriesOptions = { axisTypes, coordinateSystem: 'polar' };
2008
+ this.builder.addSeries(data, seriesOverrides, seriesOptions);
2009
+ this.builder.addPolar();
2010
+ this.builder.addAngleAxis(data, overrides['axis']);
2011
+ this.builder.addRadiusAxis(data, overrides['axis']);
2012
+ this.builder.addTooltip(data, overrides.tooltip);
2013
+ this.builder.addLegend();
2014
+ }
2015
+ makeLine(data, overrides, opts = {}) {
2016
+ if (this.builder instanceof EChartBuilder == false) {
2017
+ return;
2018
+ }
2019
+ ;
2020
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
2021
+ x: 'category',
2022
+ y: 'value',
2023
+ // TODO agregar radius y angle axis
2024
+ } } = opts;
2025
+ this.builder.reset();
2026
+ // El orden importa, primero callbacks y despues componentes.
2027
+ // chart callbaks
2028
+ if (valueFormatter)
2029
+ this.builder.setValueFormatter(valueFormatter);
2030
+ if (palette)
2031
+ this.builder.setPalette(palette);
2032
+ if (colorResolver)
2033
+ this.builder.setColorResolver(colorResolver);
2034
+ const product = this.builder.baseProduct;
2035
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2036
+ // chart components
2037
+ this.builder.addCommons();
2038
+ const seriesOptions = { axisTypes };
2039
+ this.builder.addSeries(data, seriesOverrides, seriesOptions);
2040
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
2041
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
2042
+ this.builder.addTooltip(data, overrides.tooltip);
2043
+ this.builder.addLegend();
2044
+ }
2045
+ makeScatter(data, overrides, opts = {}) {
2046
+ if (this.builder instanceof EChartBuilder == false) {
2047
+ return;
2048
+ }
2049
+ ;
2050
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
2051
+ x: 'category',
2052
+ y: 'value',
2053
+ } } = opts;
2054
+ this.builder.reset();
2055
+ // El orden importa, primero callbacks y despues componentes.
2056
+ // chart callbaks
2057
+ if (valueFormatter)
2058
+ this.builder.setValueFormatter(valueFormatter);
2059
+ if (palette)
2060
+ this.builder.setPalette(palette);
2061
+ if (colorResolver)
2062
+ this.builder.setColorResolver(colorResolver);
2063
+ const product = this.builder.baseProduct;
2064
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2065
+ // chart components
2066
+ this.builder.addCommons();
2067
+ const seriesOptions = { axisTypes };
2068
+ this.builder.addSeries(data, seriesOverrides, seriesOptions);
2069
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
2070
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
2071
+ this.builder.addTooltip(data, overrides.tooltip);
2072
+ this.builder.addLegend();
2073
+ }
2074
+ makeRing(data, overrides, opts = {}) {
2075
+ if (this.builder instanceof RingBuilder == false) {
2076
+ return;
2077
+ }
2078
+ ;
2079
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2080
+ this.builder.reset();
2081
+ // El orden importa, primero callbacks y despues componentes.
2082
+ // chart callbaks
2083
+ if (valueFormatter)
2084
+ this.builder.setValueFormatter(valueFormatter);
2085
+ if (palette)
2086
+ this.builder.setPalette(palette);
2087
+ if (colorResolver)
2088
+ this.builder.setColorResolver(colorResolver);
2089
+ const product = this.builder.baseProduct;
2090
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2091
+ // chart components
2092
+ this.builder.addCommons();
2093
+ this.builder.addSeries(data, seriesOverrides);
2094
+ this.builder.addGraphic();
2095
+ this.builder.addTooltip(data, overrides.tooltip);
2096
+ this.builder.addLegend();
2097
+ }
2098
+ makePie(data, overrides, opts = {}) {
2099
+ if (this.builder instanceof PieBuilder == false) {
2100
+ return;
2101
+ }
2102
+ ;
2103
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2104
+ this.builder.reset();
2105
+ // El orden importa, primero callbacks y despues componentes.
2106
+ // chart callbaks
2107
+ if (valueFormatter)
2108
+ this.builder.setValueFormatter(valueFormatter);
2109
+ if (palette)
2110
+ this.builder.setPalette(palette);
2111
+ if (colorResolver)
2112
+ this.builder.setColorResolver(colorResolver);
2113
+ const product = this.builder.baseProduct;
2114
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2115
+ // chart components
2116
+ this.builder.addCommons();
2117
+ this.builder.addSeries(data, seriesOverrides);
2118
+ this.builder.addTooltip(data, overrides.tooltip);
2119
+ this.builder.addLegend();
2120
+ }
2121
+ makeFunnel(data, overrides, opts = {}) {
2122
+ if (this.builder instanceof FunnelBuilder == false) {
2123
+ return;
2124
+ }
2125
+ ;
2126
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2127
+ this.builder.reset();
2128
+ // El orden importa, primero callbacks y despues componentes.
2129
+ // chart callbaks
2130
+ if (valueFormatter)
2131
+ this.builder.setValueFormatter(valueFormatter);
2132
+ if (palette)
2133
+ this.builder.setPalette(palette);
2134
+ if (colorResolver)
2135
+ this.builder.setColorResolver(colorResolver);
2136
+ const product = this.builder.baseProduct;
2137
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2138
+ // chart components
2139
+ this.builder.addCommons();
2140
+ this.builder.addSeries(data, seriesOverrides);
2141
+ this.builder.addTooltip(data, overrides.tooltip);
2142
+ this.builder.addLegend();
2143
+ }
2144
+ makeSunburst(data, overrides, opts = {}) {
2145
+ if (this.builder instanceof SunburstBuilder == false) {
2146
+ return;
2147
+ }
2148
+ ;
2149
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2150
+ this.builder.reset();
2151
+ // El orden importa, primero callbacks y despues componentes.
2152
+ // chart callbaks
2153
+ if (valueFormatter)
2154
+ this.builder.setValueFormatter(valueFormatter);
2155
+ if (palette)
2156
+ this.builder.setPalette(palette);
2157
+ if (colorResolver)
2158
+ this.builder.setColorResolver(colorResolver);
2159
+ const product = this.builder.baseProduct;
2160
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2161
+ // chart components
2162
+ this.builder.addCommons();
2163
+ this.builder.addSeries(data, seriesOverrides);
2164
+ this.builder.addTooltip(data, overrides.tooltip);
2165
+ }
2166
+ makeSankey(data, overrides, opts = {}) {
2167
+ if (this.builder instanceof SankeyBuilder == false) {
2168
+ return;
2169
+ }
2170
+ ;
2171
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, } = opts;
2172
+ this.builder.reset();
2173
+ // El orden importa, primero callbacks y despues componentes.
2174
+ // chart callbaks
2175
+ if (valueFormatter)
2176
+ this.builder.setValueFormatter(valueFormatter);
2177
+ if (palette)
2178
+ this.builder.setPalette(palette);
2179
+ if (colorResolver)
2180
+ this.builder.setColorResolver(colorResolver);
2181
+ const product = this.builder.baseProduct;
2182
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2183
+ // chart components
2184
+ this.builder.addCommons();
2185
+ this.builder.addSeries(data, seriesOverrides);
2186
+ this.builder.addTooltip(data, overrides.tooltip);
2187
+ }
2188
+ makeBoxplot(data, overrides, opts = {}) {
2189
+ if (this.builder instanceof BoxPlotBuilder == false) {
2190
+ return;
2191
+ }
2192
+ const { valueFormatter = undefined, palette = undefined, colorResolver = undefined, axisTypes = {
2193
+ x: 'value',
2194
+ y: 'category',
2195
+ }, } = opts;
2196
+ this.builder.reset();
2197
+ // El orden importa, primero callbacks y despues componentes.
2198
+ // chart callbaks
2199
+ if (valueFormatter)
2200
+ this.builder.setValueFormatter(valueFormatter);
2201
+ if (palette)
2202
+ this.builder.setPalette(palette);
2203
+ if (colorResolver)
2204
+ this.builder.setColorResolver(colorResolver);
2205
+ const product = this.builder.baseProduct;
2206
+ const seriesOverrides = merge$1({}, product.baseOptions.series, overrides[product.chartKey].series);
2207
+ // chart components
2208
+ this.builder.addCommons();
2209
+ const configOpts = { axisTypes };
2210
+ this.builder.addDataset(data);
2211
+ this.builder.addSeries(data, seriesOverrides, configOpts);
2212
+ this.builder.addXAxis(data, overrides.axis, axisTypes.x);
2213
+ this.builder.addYAxis(data, overrides.axis, axisTypes.y);
2214
+ this.builder.addTooltip(data, overrides.tooltip);
2215
+ this.builder.addDataZoom();
2216
+ }
2217
+ }
2218
+
2219
+ /**
2220
+ * EchartsRingComponent
2221
+ *
2222
+ * Especialista en visualización de tipo Ring. Soporta multi-medidas y KPI central.
2223
+ * @see {@link vs-echarts/docs/charts/ring-patterns.md}
2224
+ */
2225
+ class EchartsRingComponent extends BaseEchartsComponent {
2226
+ baseSeriesOptions = {
2227
+ type: 'pie',
2228
+ center: ['50%', '50%'],
2229
+ avoidLabelOverlap: true,
2230
+ minAngle: 3,
2231
+ selectedMode: 'single',
2232
+ selectedOffset: 4,
2233
+ itemStyle: {
2234
+ borderColor: '#fff',
2235
+ },
2236
+ label: { show: false },
2237
+ emphasis: {
2238
+ scale: true,
2239
+ scaleSize: 2,
2240
+ },
2241
+ select: {
2242
+ itemStyle: {
2243
+ borderColor: EChartsTokens.sBorderColor,
2244
+ shadowColor: EChartsTokens.sShadowColor,
2245
+ borderWidth: 1,
2246
+ shadowBlur: 4,
2247
+ },
2248
+ },
2249
+ animationType: 'scale',
2250
+ animationEasing: 'elasticOut',
2251
+ };
2252
+ baseProduct = {
2253
+ chartKey: 'ring',
2254
+ baseOptions: {
2255
+ series: this.baseSeriesOptions,
2256
+ }
2257
+ };
2258
+ builder = new RingBuilder(this.baseProduct);
2259
+ director = new VSECDirector(this.builder);
2260
+ lastSelectedSeriesIndex = null;
2261
+ lastSelectedDataIndex = null;
2262
+ selectedPercent = null;
2263
+ currentGraphicText = '';
2264
+ constructor() {
2265
+ super();
2266
+ }
2267
+ make() {
2268
+ const makeOpts = {
2269
+ valueFormatter: this.valueFormatter,
2270
+ palette: this.palette,
2271
+ colorResolver: this.colorResolver,
2272
+ };
2273
+ this.director.makeRing(this.data, this.optionsOverrides, makeOpts);
2274
+ }
2275
+ onInputChanges(changes) {
2276
+ // Reset selection only if data changed
2277
+ if (changes['data']) {
2278
+ this.lastSelectedSeriesIndex = null;
2279
+ this.lastSelectedDataIndex = null;
2280
+ this.selectedPercent = null;
2281
+ this.currentGraphicText = '';
2282
+ }
2283
+ super.onInputChanges(changes);
2284
+ }
2285
+ /**
2286
+ * Maneja clics en los sectores del ring.
2287
+ * Soporta múltiples series (anillos) y actualiza el KPI central.
2288
+ */
2289
+ onChartClick(event) {
2290
+ if (this.chartInstance && event && event.dataIndex !== undefined) {
2291
+ const isSameSelection = event.seriesIndex === this.lastSelectedSeriesIndex &&
2292
+ event.dataIndex === this.lastSelectedDataIndex;
2293
+ if (isSameSelection) {
2294
+ // Toggle OFF
2295
+ this.lastSelectedSeriesIndex = null;
2296
+ this.lastSelectedDataIndex = null;
2297
+ this.selectedPercent = null;
2298
+ this.setGraphicText('');
2299
+ }
2300
+ else {
2301
+ // SELECT
2302
+ this.lastSelectedSeriesIndex = event.seriesIndex;
2303
+ this.lastSelectedDataIndex = event.dataIndex;
2304
+ this.selectedPercent = (event.percent !== undefined) ? event.percent + '%' : '';
2305
+ this.setGraphicText(this.selectedPercent);
2306
+ }
2307
+ this.chartClick.emit({
2308
+ type: 'cross-filter',
2309
+ data: {
2310
+ category: event.name,
2311
+ serie: event.seriesName,
2312
+ value: event.value
2313
+ }
2314
+ });
2315
+ }
2316
+ }
2317
+ onChartMouseOver(event) {
2318
+ if (this.selectedPercent === null && event && event.percent !== undefined) {
2319
+ this.setGraphicText(event.percent + '%');
2320
+ }
2321
+ }
2322
+ onChartMouseOut(event) {
2323
+ if (this.selectedPercent === null) {
2324
+ this.setGraphicText('');
2325
+ }
2326
+ }
2327
+ /**
2328
+ * Actualiza el texto del Graphic central y persiste la selección en el modelo de opciones.
2329
+ */
2330
+ setGraphicText(text) {
2331
+ this.currentGraphicText = text;
2332
+ // Persistencia de GRAPHIC (KPI central)
2333
+ this.chartInstance?.setOption({
2334
+ graphic: {
2335
+ style: {
2336
+ text: this.currentGraphicText,
2337
+ opacity: this.currentGraphicText ? 1 : 0,
2338
+ }
2339
+ }
2340
+ });
2341
+ }
2342
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsRingComponent, isStandalone: true, selector: "vs-echarts-ring", 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"] }] });
2344
+ }
2345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsRingComponent, decorators: [{
2346
+ type: Component,
2347
+ args: [{ selector: 'vs-echarts-ring', standalone: true, imports: [
2348
+ CommonModule,
2349
+ NgxEchartsDirective,
2350
+ ], 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"] }]
2351
+ }], ctorParameters: () => [] });
2352
+
2353
+ /**
2354
+ * EchartsPieComponent
2355
+ *
2356
+ * Especialista en visualización de tipo Pie (Torta y Anillos concéntricos).
2357
+ * La primera serie se dibuja como un gráfico de torta tradicional (lleno) y
2358
+ * las subsecuentes como anillos concéntricos alrededor.
2359
+ */
2360
+ class EchartsPieComponent extends BaseEchartsComponent {
2361
+ baseSeriesOptions = {
2362
+ type: 'pie',
2363
+ center: ['50%', '50%'],
2364
+ avoidLabelOverlap: true,
2365
+ minAngle: 3,
2366
+ selectedMode: 'single',
2367
+ selectedOffset: 4,
2368
+ emphasis: {
2369
+ scale: true,
2370
+ scaleSize: 2,
2371
+ },
2372
+ select: {
2373
+ itemStyle: {
2374
+ borderColor: EChartsTokens.sBorderColor,
2375
+ shadowColor: EChartsTokens.sShadowColor,
2376
+ borderWidth: 1,
2377
+ shadowBlur: 4,
2378
+ },
2379
+ },
2380
+ animationType: 'scale',
2381
+ animationEasing: 'elasticOut',
2382
+ };
2383
+ baseProduct = {
2384
+ chartKey: 'pie',
2385
+ baseOptions: {
2386
+ series: this.baseSeriesOptions,
2387
+ }
2388
+ };
2389
+ builder = new PieBuilder(this.baseProduct);
2390
+ director = new VSECDirector(this.builder);
2391
+ constructor() {
2392
+ super();
2393
+ }
2394
+ make() {
2395
+ const makeOpts = {
2396
+ valueFormatter: this.valueFormatter,
2397
+ palette: this.palette,
2398
+ colorResolver: this.colorResolver,
2399
+ };
2400
+ this.director.makePie(this.data, this.optionsOverrides, makeOpts);
2401
+ }
2402
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2403
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsPieComponent, isStandalone: true, selector: "vs-echarts-pie", 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"] }] });
2404
+ }
2405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsPieComponent, decorators: [{
2406
+ type: Component,
2407
+ args: [{ selector: 'vs-echarts-pie', standalone: true, imports: [
2408
+ CommonModule,
2409
+ NgxEchartsDirective,
2410
+ ], 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"] }]
2411
+ }], ctorParameters: () => [] });
2412
+
2413
+ /**
2414
+ * EchartsFunnelComponent
2415
+ *
2416
+ * Component for Funnel visualization. Supports single and multiple measures.
2417
+ */
2418
+ class EchartsFunnelComponent extends BaseEchartsComponent {
2419
+ baseSeriesOptions = {
2420
+ type: 'funnel',
2421
+ left: '10%',
2422
+ width: '80%',
2423
+ minSize: '0.01%',
2424
+ maxSize: '100%',
2425
+ sort: 'descending',
2426
+ gap: 2,
2427
+ label: {
2428
+ show: true,
2429
+ position: 'inside'
2430
+ },
2431
+ labelLine: {
2432
+ show: false
2433
+ },
2434
+ itemStyle: {
2435
+ borderColor: '#fff',
2436
+ borderWidth: 1
2437
+ },
2438
+ emphasis: {
2439
+ label: {
2440
+ fontSize: 16
2441
+ }
2442
+ },
2443
+ selectedMode: 'single',
2444
+ select: {
2445
+ label: {
2446
+ fontSize: 16
2447
+ },
2448
+ itemStyle: {
2449
+ borderWidth: 1,
2450
+ borderColor: EChartsTokens.sBorderColor,
2451
+ shadowColor: EChartsTokens.sShadowColor,
2452
+ shadowBlur: 6,
2453
+ }
2454
+ },
2455
+ };
2456
+ baseProduct = {
2457
+ chartKey: 'funnel',
2458
+ baseOptions: {
2459
+ series: this.baseSeriesOptions,
2460
+ }
2461
+ };
2462
+ builder = new FunnelBuilder(this.baseProduct);
2463
+ director = new VSECDirector(this.builder);
2464
+ constructor() {
2465
+ super();
2466
+ }
2467
+ make() {
2468
+ const makeOpts = {
2469
+ valueFormatter: this.valueFormatter,
2470
+ palette: this.palette,
2471
+ colorResolver: this.colorResolver,
2472
+ };
2473
+ this.director.makeFunnel(this.data, this.optionsOverrides, makeOpts);
2170
2474
  }
2475
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2476
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EchartsFunnelComponent, isStandalone: true, selector: "vs-echarts-funnel", 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"] }] });
2171
2477
  }
2478
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EchartsFunnelComponent, decorators: [{
2479
+ type: Component,
2480
+ args: [{ selector: 'vs-echarts-funnel', standalone: true, imports: [
2481
+ CommonModule,
2482
+ NgxEchartsDirective,
2483
+ ], 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"] }]
2484
+ }], ctorParameters: () => [] });
2172
2485
 
2173
2486
  class EchartsBarComponent extends BaseEchartsComponent {
2174
2487
  /**
@@ -2570,100 +2883,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
2570
2883
  ], 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"] }]
2571
2884
  }], ctorParameters: () => [] });
2572
2885
 
2573
- class SunburstBuilder {
2574
- baseProduct;
2575
- valueFormatter = (value) => value.toLocaleString();
2576
- palette = [];
2577
- // TODO: Hay que implementar un valor por defecto.
2578
- colorResolver;
2579
- result = {};
2580
- constructor(baseProduct) {
2581
- this.baseProduct = baseProduct;
2582
- }
2583
- reset() {
2584
- this.result = {};
2585
- }
2586
- addSeries(data, overrides) {
2587
- if (!data || !data.source || data.source.length === 0) {
2588
- return;
2589
- }
2590
- const sunburstData = mapHierarchicalData(data.source, data.dimensions);
2591
- const depth = getTreeDepth(sunburstData);
2592
- const levels = [];
2593
- for (let i = 0; i <= depth; i++) {
2594
- levels.push({
2595
- label: {
2596
- show: false,
2597
- },
2598
- });
2599
- }
2600
- const dynamiSerieOptions = {
2601
- name: '',
2602
- data: sunburstData,
2603
- levels: levels
2604
- };
2605
- const serie = merge$1({}, dynamiSerieOptions, overrides);
2606
- if (this.colorResolver) {
2607
- if (!serie.itemStyle) {
2608
- serie.itemStyle = {};
2609
- }
2610
- serie.itemStyle.color = this.colorResolver;
2611
- }
2612
- this.result.series = serie;
2613
- }
2614
- addTooltip(data, overrides) {
2615
- merge$1(overrides, {
2616
- formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
2617
- });
2618
- const tooltip = getTooltipOptions(overrides);
2619
- this.result.tooltip = tooltip;
2620
- }
2621
- addCommons() {
2622
- const opts = {
2623
- palette: this.palette,
2624
- };
2625
- merge$1(this.result, getCommons(opts));
2626
- }
2627
- addGraphic() { }
2628
- getResult() {
2629
- return this.result;
2630
- }
2631
- ;
2632
- addPolar() { }
2633
- addXAxis(data, overrides, type) { }
2634
- addYAxis(data, overrides, type) { }
2635
- addRadiusAxis(data, overrides) { }
2636
- addAngleAxis(data, overrides) { }
2637
- addLegend() { }
2638
- addDataZoom() { }
2639
- addDataset(data, opts) { }
2640
- // Setters
2641
- /**
2642
- * Permite inyectar un formateador de valores externo.
2643
- */
2644
- setValueFormatter(formatter) {
2645
- if (formatter) {
2646
- this.valueFormatter = formatter;
2647
- }
2648
- }
2649
- /**
2650
- * Permite inyectar una paleta de colores básica.
2651
- */
2652
- setPalette(palette) {
2653
- if (palette) {
2654
- this.palette = palette;
2655
- }
2656
- }
2657
- /**
2658
- * Permite inyectar un resolver de colores dinámico.
2659
- */
2660
- setColorResolver(resolver) {
2661
- if (resolver) {
2662
- this.colorResolver = resolver;
2663
- }
2664
- }
2665
- }
2666
-
2667
2886
  class EChartsSunburstComponent extends BaseEchartsComponent {
2668
2887
  baseSeriesOptions = {
2669
2888
  type: 'sunburst',
@@ -2712,158 +2931,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
2712
2931
  ], 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"] }]
2713
2932
  }] });
2714
2933
 
2715
- /**
2716
- * SankeyBuilder
2717
- *
2718
- * Builder concreto para el gráfico Sankey (diagrama de flujos de izquierda a derecha).
2719
- */
2720
- class SankeyBuilder {
2721
- baseProduct;
2722
- valueFormatter = (value) => value.toLocaleString();
2723
- palette = [];
2724
- colorResolver;
2725
- result = {};
2726
- constructor(baseProduct) {
2727
- this.baseProduct = baseProduct;
2728
- }
2729
- reset() {
2730
- this.result = {};
2731
- }
2732
- addSeries(data, overrides) {
2733
- if (!data || !data.source || data.source.length === 0) {
2734
- return;
2735
- }
2736
- // Identificar medidas (todas las dimensiones excepto 'category')
2737
- const measureKeys = data.dimensions
2738
- .filter((d) => d.name !== "category")
2739
- .map((d) => d.name);
2740
- // Función auxiliar para sumarizar valores de medidas en caso de haber más de una
2741
- const getNodeValue = (node) => {
2742
- return measureKeys.reduce((sum, key) => sum + (Number(node[key]) || 0), 0);
2743
- };
2744
- const nodesMap = new Map();
2745
- const linksMap = new Map();
2746
- // Función recursiva para aplanar datos jerárquicos a nodos y enlaces
2747
- const traverse = (nodeList, level, parentId) => {
2748
- for (const node of nodeList) {
2749
- const category = node.category;
2750
- const currentId = `${category}___${level}`;
2751
- const value = getNodeValue(node);
2752
- nodesMap.set(currentId, (nodesMap.get(currentId) || 0) + value);
2753
- if (parentId) {
2754
- const linkKey = `${parentId}--->${currentId}`;
2755
- if (linksMap.has(linkKey)) {
2756
- linksMap.get(linkKey).value += value;
2757
- }
2758
- else {
2759
- linksMap.set(linkKey, {
2760
- source: parentId,
2761
- target: currentId,
2762
- value: value,
2763
- });
2764
- }
2765
- }
2766
- if (node.children && node.children.length > 0) {
2767
- traverse(node.children, level + 1, currentId);
2768
- }
2769
- }
2770
- };
2771
- // Comenzar el recorrido en el nivel 0
2772
- traverse(data.source, 0);
2773
- // al menos un nivel de links para dibujar.
2774
- if (linksMap.size === 0)
2775
- return;
2776
- // Mapear nodos acumulados a la estructura requerida por ECharts (name y opcionalmente color, sin value redundante)
2777
- const nodes = Array.from(nodesMap.keys()).map((currentId) => {
2778
- const category = currentId.split("___")[0];
2779
- const nodeItem = {
2780
- name: currentId,
2781
- };
2782
- if (this.colorResolver) {
2783
- const color = this.colorResolver({ name: category, data: nodeItem });
2784
- if (color) {
2785
- nodeItem.itemStyle = { color };
2786
- }
2787
- }
2788
- return nodeItem;
2789
- });
2790
- const dynamicSerieOptions = {
2791
- type: "sankey",
2792
- orient: "horizontal", // De izquierda a derecha
2793
- draggable: true,
2794
- emphasis: {
2795
- focus: "adjacency",
2796
- },
2797
- lineStyle: {
2798
- color: "source",
2799
- opacity: 0.25,
2800
- curveness: 0.5,
2801
- },
2802
- label: {
2803
- show: true,
2804
- position: "right",
2805
- fontFamily: "'Inter', 'Roboto', 'Open Sans', sans-serif",
2806
- fontSize: 10,
2807
- formatter: (params) => {
2808
- // Remover el sufijo de nivel de la etiqueta visual
2809
- return params.name.split("___")[0];
2810
- },
2811
- },
2812
- roam: true,
2813
- data: nodes,
2814
- links: Array.from(linksMap.values()),
2815
- };
2816
- const serie = merge$1({}, dynamicSerieOptions, overrides);
2817
- if (this.colorResolver && !serie.itemStyle) {
2818
- serie.itemStyle = {};
2819
- }
2820
- if (this.colorResolver && serie.itemStyle) {
2821
- serie.itemStyle.color = this.colorResolver;
2822
- }
2823
- this.result.series = serie;
2824
- }
2825
- addTooltip(data, overrides) {
2826
- merge$1(overrides, {
2827
- formatter: getTooltipFormatter(overrides.trigger || 'item', data, this.valueFormatter),
2828
- });
2829
- const tooltip = getTooltipOptions(overrides);
2830
- this.result.tooltip = tooltip;
2831
- }
2832
- addPolar() { }
2833
- addXAxis(data, overrides, type) { }
2834
- addYAxis(data, overrides, type) { }
2835
- addRadiusAxis(data, overrides) { }
2836
- addAngleAxis(data, overrides) { }
2837
- addLegend() { }
2838
- addDataZoom() { }
2839
- addDataset(data, opts) { }
2840
- addCommons() {
2841
- const opts = {
2842
- palette: this.palette,
2843
- };
2844
- merge$1(this.result, getCommons(opts));
2845
- }
2846
- addGraphic() { }
2847
- getResult() {
2848
- return this.result;
2849
- }
2850
- setValueFormatter(formatter) {
2851
- if (formatter) {
2852
- this.valueFormatter = formatter;
2853
- }
2854
- }
2855
- setPalette(palette) {
2856
- if (palette) {
2857
- this.palette = palette;
2858
- }
2859
- }
2860
- setColorResolver(resolver) {
2861
- if (resolver) {
2862
- this.colorResolver = resolver;
2863
- }
2864
- }
2865
- }
2866
-
2867
2934
  class EchartsSankeyComponent extends BaseEchartsComponent {
2868
2935
  baseSeriesOptions = {
2869
2936
  type: 'sankey',