yw-charts-library 0.0.3 → 0.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.
@@ -94,7 +94,8 @@ const YwDashboardWidgetTypes = [
94
94
  { code: "chart-bar", description: "Chart Bar" },
95
95
  { code: "chart-line", description: "Chart Bar" },
96
96
  { code: "chart-doughnut", description: "Chart Doughnut" },
97
- { code: "chart-gauge", description: "Chart Gauge" }
97
+ { code: "chart-gauge", description: "Chart Gauge" },
98
+ { code: "chart-bubble", description: "Chart Bubble" }
98
99
  ];
99
100
 
100
101
  const YwDashboardWidgetFilterTypes = [
@@ -250,14 +251,14 @@ const resolveJoinedTableData = (allTablesData, configJoins) => {
250
251
  return out;
251
252
  };
252
253
  let currentRows = baseData.map((r) => prefixRow(r, baseTable));
253
- relations.forEach((rel) => {
254
+ for (const rel of relations) {
254
255
  const { leftTable, leftId, rightTable, rightId } = rel;
255
256
  if (!allTablesData[rightTable]) {
256
257
  throw new Error(`La tabla destino "${rightTable}" especificada en el join no existe en los datos.`);
257
258
  }
258
259
  const targetData = allTablesData[rightTable] || [];
259
260
  if (targetData.length === 0) {
260
- throw new Error(`La tabla destino "${rightTable}" está vacía.`);
261
+ return [];
261
262
  }
262
263
  if (targetData[0][rightId] === undefined) {
263
264
  throw new Error(`La columna "${rightId}" no existe en la tabla destino "${rightTable}".`);
@@ -270,18 +271,10 @@ const resolveJoinedTableData = (allTablesData, configJoins) => {
270
271
  }
271
272
  });
272
273
  let matchCount = 0;
273
- currentRows = currentRows.map((row) => {
274
- // let foreignKeyVal = row[leftId];
275
- // if (foreignKeyVal === undefined) {
276
- // const foundKey = Object.keys(row).find(
277
- // (k) => k === leftId || k.endsWith(`.${leftId}`),
278
- // );
279
- // if (foundKey) foreignKeyVal = row[foundKey];
280
- // }
281
- // REVSISAR COMO ESTA FUNCIONADO EL PARCHE
274
+ const nextRows = [];
275
+ currentRows.forEach((row) => {
282
276
  let foreignKeyVal = row[`${leftTable}.${leftId}`];
283
277
  if (foreignKeyVal === undefined) {
284
- // Si no está, aplicas tu respaldo anterior
285
278
  const foundKey = Object.keys(row).find((k) => k === leftId || k.endsWith(`.${leftId}`));
286
279
  if (foundKey)
287
280
  foreignKeyVal = row[foundKey];
@@ -289,14 +282,14 @@ const resolveJoinedTableData = (allTablesData, configJoins) => {
289
282
  if (foreignKeyVal !== undefined && targetMap.has(String(foreignKeyVal))) {
290
283
  matchCount++;
291
284
  const matchedRow = targetMap.get(String(foreignKeyVal));
292
- return { ...row, ...matchedRow };
285
+ nextRows.push({ ...row, ...matchedRow });
293
286
  }
294
- return row;
295
287
  });
288
+ currentRows = nextRows;
296
289
  if (matchCount === 0) {
297
- throw new Error(`Error de Join: No se encontraron coincidencias al intentar unir la tabla acumulada con "${rightTable}".`);
290
+ return [];
298
291
  }
299
- });
292
+ }
300
293
  return currentRows;
301
294
  };
302
295
  // ACCESO A PROPIEDADES ANIDADAS (SOPORTA NOTACIÓN DE PUNTOS Y TOLERANCIA DE PREFIJOS)
@@ -1716,13 +1709,17 @@ const parseDataPie = parseSyncFusionData$2;
1716
1709
  const detectCategoryKey = (row) => {
1717
1710
  if (!row)
1718
1711
  return undefined;
1712
+ const isDateKey = (k) => {
1713
+ const lk = k.toLowerCase();
1714
+ return lk.includes('fecha') || lk.includes('date') || lk.includes('time') || lk.includes('timestamp');
1715
+ };
1719
1716
  const candidates = ['x', 'name', 'label', 'category', 'categoria', 'sucursal', 'producto', 'key', 'title'];
1720
1717
  for (const c of candidates) {
1721
- if (row[c] !== undefined && row[c] !== null && typeof row[c] === 'string')
1718
+ if (row[c] !== undefined && row[c] !== null && typeof row[c] === 'string' && !isDateKey(c))
1722
1719
  return c;
1723
1720
  }
1724
1721
  for (const k of Object.keys(row)) {
1725
- if (typeof row[k] === 'string')
1722
+ if (typeof row[k] === 'string' && !isDateKey(k))
1726
1723
  return k;
1727
1724
  }
1728
1725
  return undefined;
@@ -1821,7 +1818,7 @@ const parseForSyncfusion$1 = (rawData, config) => {
1821
1818
  if (!row)
1822
1819
  return;
1823
1820
  let xVal = effectiveXKey ? getNestedValue(row, effectiveXKey) : undefined;
1824
- if (xVal === undefined) {
1821
+ if (xVal === undefined && !xKey) {
1825
1822
  const autoX = detectCategoryKey(row);
1826
1823
  if (autoX)
1827
1824
  xVal = row[autoX];
@@ -1974,10 +1971,23 @@ class PieChartSyncfusionComponent {
1974
1971
  this.chartTitle = '';
1975
1972
  this._lastWidth = 0;
1976
1973
  this._lastHeight = 0;
1974
+ this._dataSnapshot = '';
1977
1975
  }
1978
1976
  ngOnInit() {
1979
1977
  this.updateParsedData();
1980
1978
  }
1979
+ ngDoCheck() {
1980
+ try {
1981
+ const snap = JSON.stringify(this.chartData);
1982
+ if (snap !== this._dataSnapshot) {
1983
+ this._dataSnapshot = snap;
1984
+ this.updateParsedData();
1985
+ }
1986
+ }
1987
+ catch {
1988
+ // Ignorar si hay referencias circulares en los datos
1989
+ }
1990
+ }
1981
1991
  ngAfterViewInit() {
1982
1992
  if (typeof ResizeObserver === 'undefined')
1983
1993
  return;
@@ -2050,6 +2060,12 @@ class PieChartSyncfusionComponent {
2050
2060
  this.centerLabelSettings = undefined;
2051
2061
  this.chartTitle = this.config?.title || '';
2052
2062
  }
2063
+ this.cdr.markForCheck();
2064
+ if (this.chartInstance) {
2065
+ setTimeout(() => {
2066
+ this.chartInstance?.refresh();
2067
+ });
2068
+ }
2053
2069
  }
2054
2070
  onChartLoaded(args) {
2055
2071
  if (this.centerLabel?.show && args?.accumulation?.element?.id) {
@@ -2532,8 +2548,12 @@ class GaugeChartSyncfusionComponent {
2532
2548
  /** HTML con estilos inline para la annotation central del gauge */
2533
2549
  get annotationHtml() {
2534
2550
  const text = this.animatedLabelText || (this.gaugePoint?.text ?? '');
2551
+ return this.buildAnnotationHtml(text);
2552
+ }
2553
+ buildAnnotationHtml(text) {
2535
2554
  const size = this.currentLabelSize || this.visualConfig?.labelSize || '24px';
2536
- const weight = this.visualConfig?.labelWeight || (this.visualConfig?.labelBold ? 'bold' : 'normal');
2555
+ const isBold = this.visualConfig?.labelBold || this.visualConfig?.labelWeight === 'bold' || this.visualConfig?.labelWeight === '700';
2556
+ const weight = isBold ? 'bold' : (this.visualConfig?.labelWeight || 'normal');
2537
2557
  const color = this.visualConfig?.labelColor || '#1F2937';
2538
2558
  return `<div style="font-size:${size};font-weight:${weight};color:${color};text-align:center;font-family:inherit;line-height:1.1;white-space:nowrap;">${text}</div>`;
2539
2559
  }
@@ -2663,6 +2683,12 @@ class GaugeChartSyncfusionComponent {
2663
2683
  else {
2664
2684
  this.currentLabelSize = `${parsedSize}px`;
2665
2685
  }
2686
+ if (this.gaugeInstance && this.visualConfig?.showLabel && !this._isAnimating) {
2687
+ try {
2688
+ this.gaugeInstance.setAnnotationValue(0, 0, this.annotationHtml);
2689
+ }
2690
+ catch { }
2691
+ }
2666
2692
  this.cdr.markForCheck();
2667
2693
  return;
2668
2694
  }
@@ -2670,6 +2696,12 @@ class GaugeChartSyncfusionComponent {
2670
2696
  // Proporción estándar ideal (~7.5% del ancho del contenedor, acotado entre 13px y 26px)
2671
2697
  const base = Math.max(13, Math.min(26, Math.round(width * 0.075)));
2672
2698
  this.currentLabelSize = `${base}px`;
2699
+ if (this.gaugeInstance && this.visualConfig?.showLabel && !this._isAnimating) {
2700
+ try {
2701
+ this.gaugeInstance.setAnnotationValue(0, 0, this.annotationHtml);
2702
+ }
2703
+ catch { }
2704
+ }
2673
2705
  this.cdr.markForCheck();
2674
2706
  }
2675
2707
  /**
@@ -2759,7 +2791,7 @@ class GaugeChartSyncfusionComponent {
2759
2791
  this.animatedLabelText = labelText;
2760
2792
  if (this.gaugeInstance) {
2761
2793
  try {
2762
- this.gaugeInstance.setAnnotationValue(0, 0, labelText);
2794
+ this.gaugeInstance.setAnnotationValue(0, 0, this.buildAnnotationHtml(labelText));
2763
2795
  }
2764
2796
  catch {
2765
2797
  // Ignorar si la anotación aún no se ha montado
@@ -2776,7 +2808,7 @@ class GaugeChartSyncfusionComponent {
2776
2808
  this.animatedLabelText = finalLabel;
2777
2809
  if (this.gaugeInstance) {
2778
2810
  try {
2779
- this.gaugeInstance.setAnnotationValue(0, 0, finalLabel);
2811
+ this.gaugeInstance.setAnnotationValue(0, 0, this.buildAnnotationHtml(finalLabel));
2780
2812
  }
2781
2813
  catch { }
2782
2814
  }
@@ -2885,1822 +2917,1840 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
2885
2917
  args: ['config']
2886
2918
  }] } });
2887
2919
 
2888
- /*BEGIN - COMPONENTES VALIDOS PARA WIDGET*/
2889
- class YwDashboardWidgetComponent {
2890
- constructor() {
2891
- this.componentWidgetId = '';
2892
- this.typeComponent = '';
2893
- this.varShowConfigButtons = false;
2894
- this.styleWidget = input(DEFAULT_WIDGET_STYLE, ...(ngDevMode ? [{ debugName: "styleWidget" }] : []));
2895
- // Signal calculada que combina los valores recibidos con los valores por defecto
2896
- this.instanceStyleWidget = computed(() => ({
2897
- widgetBackgroundColor: this.styleWidget()?.widgetBackgroundColor ?? DEFAULT_WIDGET_STYLE.widgetBackgroundColor,
2898
- widgetBorderColor: this.styleWidget()?.widgetBorderColor ?? DEFAULT_WIDGET_STYLE.widgetBorderColor
2899
- }), ...(ngDevMode ? [{ debugName: "instanceStyleWidget" }] : []));
2900
- this.configWidget = {
2901
- widgetId: '',
2902
- title: '',
2903
- typeComponent: '',
2904
- showConfigButtons: false,
2905
- widgetStyle: DEFAULT_WIDGET_STYLE,
2906
- layoutConfig: { id: '', w: 0, h: 0, content: undefined },
2907
- controlConfig: {},
2908
- controlTables: []
2909
- };
2910
- this.controlConfig = {};
2911
- this.controlData = {};
2912
- this.isLocked = model(false, ...(ngDevMode ? [{ debugName: "isLocked" }] : []));
2913
- this.isMaximized = signal(false, ...(ngDevMode ? [{ debugName: "isMaximized" }] : []));
2914
- this.eventDeleteRequest = output();
2915
- this.eventLockToggleRequest = output();
2916
- this.eventMaximizeToggleRequest = output();
2917
- this.eventShowConfigFormRequest = output();
2920
+ const parseSyncFusionData = (allTablesData, configData_) => {
2921
+ if (!allTablesData || !configData_) {
2922
+ return { series: [], labelData: {} };
2918
2923
  }
2919
- ngOnInit() {
2920
- this.componentWidgetId = 'cmpnt-' + this.configWidget.widgetId;
2921
- this.typeComponent = this.configWidget.typeComponent;
2922
- this.dataWidget = { idComponent: this.componentWidgetId,
2923
- controlConfig: this.controlConfig,
2924
- controlData: this.controlData
2925
- };
2926
- console.log('DATOS INICIALES INIT:');
2927
- console.log(this.dataWidget);
2924
+ console.log("bubble data:--", allTablesData, configData_);
2925
+ // SI LO MANDAN COMO UN ARREGLO PLANO, LO ENVOLVEMOS AUTOMÁTICAMENTE
2926
+ if (Array.isArray(allTablesData)) {
2927
+ const defaultTableName = configData_?.configData?.table || 'default';
2928
+ allTablesData = { [defaultTableName]: allTablesData };
2928
2929
  }
2929
- ngAfterViewInit() {
2930
- this.varShowConfigButtons = this.configWidget.showConfigButtons || false;
2930
+ const { ruleColorPoint, configData, xLabelText, yLabelText, title, chartoColoredLine, opacity, emptyPointSettings } = configData_;
2931
+ console.log("configData_:.::", configData_);
2932
+ const cfg = configData || {};
2933
+ const { xAxis, yAxis, joins, configJoins, table, serie, tooltip, legends } = cfg;
2934
+ let series = [];
2935
+ // Función auxiliar robusta para obtener propiedades (soporta notación con puntos de los joins)
2936
+ // const getNestedValue = (obj: any, path: string) => {
2937
+ // if (!obj || !path) return undefined;
2938
+ // if (obj[path] !== undefined) return obj[path];
2939
+ // return path.split('.').reduce((acc, part) => (acc && acc[part] !== undefined ? acc[part] : undefined), obj);
2940
+ // };
2941
+ const sortByXAxis = (data) => {
2942
+ if (!xAxis)
2943
+ return data;
2944
+ return [...data].sort((a, b) => {
2945
+ const aValue = getNestedValue(a, xAxis);
2946
+ const bValue = getNestedValue(b, xAxis);
2947
+ if (aValue == null)
2948
+ return 1;
2949
+ if (bValue == null)
2950
+ return -1;
2951
+ return String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' });
2952
+ });
2953
+ };
2954
+ if (joins === true) {
2955
+ if (!configJoins) {
2956
+ series = [];
2957
+ }
2958
+ else {
2959
+ const unifiedTable = resolveJoinedTableData(allTablesData, configJoins);
2960
+ console.log('unifiedTable bubble', unifiedTable);
2961
+ if (unifiedTable && unifiedTable.length > 0) {
2962
+ // const validRawData = unifiedTable.filter(
2963
+ // (item: any) =>
2964
+ // item &&
2965
+ // xAxis &&
2966
+ // getNestedValue(item, xAxis) !== undefined &&
2967
+ // getNestedValue(item, xAxis) !== null,
2968
+ // );
2969
+ const validRawData = unifiedTable.filter((item) => item &&
2970
+ xAxis &&
2971
+ getNestedValue(item, xAxis) !== undefined &&
2972
+ getNestedValue(item, xAxis) !== null);
2973
+ const orderedRawData = sortByXAxis(validRawData);
2974
+ if (orderedRawData.length > 0) {
2975
+ if (serie) {
2976
+ // 2. Agrupamos los datos por el valor de la serie (ej. sucursal o vendedor)
2977
+ const groupedBySerie = orderedRawData.reduce((acc, item) => {
2978
+ const serieVal = getNestedValue(item, serie);
2979
+ const serieKey = serieVal !== undefined && serieVal !== null
2980
+ ? String(serieVal)
2981
+ : 'Desconocido';
2982
+ if (!acc[serieKey]) {
2983
+ acc[serieKey] = [];
2984
+ }
2985
+ acc[serieKey].push(item);
2986
+ return acc;
2987
+ }, {});
2988
+ series = Object.entries(groupedBySerie).map(([serieName, groupItems]) => {
2989
+ const orderedGroupItems = [...groupItems].sort((a, b) => {
2990
+ const aValue = getNestedValue(a, xAxis);
2991
+ const bValue = getNestedValue(b, xAxis);
2992
+ return String(aValue).localeCompare(String(bValue), undefined, {
2993
+ numeric: true,
2994
+ sensitivity: 'base'
2995
+ });
2996
+ });
2997
+ console.log("SERIES NAME:", orderedGroupItems);
2998
+ const dataSource = orderedGroupItems.map((item) => {
2999
+ const rawVal = getNestedValue(item, yAxis);
3000
+ const valorFinal = rawVal !== undefined
3001
+ ? typeof rawVal === 'number'
3002
+ ? rawVal
3003
+ : Number(rawVal) || 0
3004
+ : 0;
3005
+ const sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
3006
+ return {
3007
+ x: String(getNestedValue(item, xAxis)),
3008
+ y: valorFinal,
3009
+ size: sizeFinal,
3010
+ name: String(getNestedValue(item, xAxis)),
3011
+ // ...(chartoColoredLine
3012
+ // ? { color: getRandomProfessionalHex() }
3013
+ // : {})
3014
+ };
3015
+ });
3016
+ return {
3017
+ name: serieName === 'default' ? 'Serie 1' : serieName,
3018
+ dataSource: aggregateByX(dataSource),
3019
+ opacity: opacity,
3020
+ emptyPointSettings: emptyPointSettings,
3021
+ // dashArray: dashArray !== undefined ? dashArray : undefined,
3022
+ // width: width !== undefined ? width : undefined,
3023
+ // widthLine: widthLine !== undefined ? widthLine : undefined,
3024
+ };
3025
+ });
3026
+ }
3027
+ else {
3028
+ const dataSource = orderedRawData.map((item) => {
3029
+ let valorFinal = 0;
3030
+ let sizeFinal = 0;
3031
+ // const shouldColorLine = chartoColoredLine;
3032
+ const rawVal = getNestedValue(item, yAxis);
3033
+ // const rawSize = getNestedValue(item, size); // <--- Extraer el valor real
3034
+ if (rawVal !== undefined) {
3035
+ valorFinal = typeof rawVal === 'number' ? rawVal : Number(rawVal) || 0;
3036
+ }
3037
+ // if (rawSize !== undefined) {
3038
+ sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
3039
+ // }
3040
+ return {
3041
+ x: String(getNestedValue(item, xAxis)),
3042
+ y: valorFinal,
3043
+ size: sizeFinal, // <--- Valor numérico extraído
3044
+ name: String(getNestedValue(item, xAxis)),
3045
+ // ...(shouldColorLine ? { color: getRandomProfessionalHex() } : {})
3046
+ };
3047
+ });
3048
+ series = [
3049
+ {
3050
+ name: xAxis.split(".")[0] && xAxis !== 'default' ? xAxis.split(".")[0] : 'Serie Join',
3051
+ dataSource: aggregateByX(dataSource),
3052
+ opacity: opacity,
3053
+ emptyPointSettings: emptyPointSettings,
3054
+ // dashArray: dashArray !== undefined ? dashArray : undefined,
3055
+ // width: width !== undefined ? width : undefined,
3056
+ // widthLine: widthLine !== undefined ? widthLine : undefined,
3057
+ }
3058
+ ];
3059
+ }
3060
+ }
3061
+ }
3062
+ }
2931
3063
  }
2932
- ngOnChanges(changes) {
2933
- if (changes['configWidget']) {
2934
- //console.log('Nuevo valor configWidget:', this.configWidget);
2935
- this.varShowConfigButtons = this.configWidget.showConfigButtons || false;
2936
- ;
3064
+ else {
3065
+ let normalizedTables = [];
3066
+ if (Array.isArray(table)) {
3067
+ normalizedTables = table.filter((t) => typeof t === 'string' && t.trim() !== '');
2937
3068
  }
2938
- if (changes['controlConfig']) {
2939
- console.log('Nuevo valor controlConfig:', this.controlConfig);
3069
+ else if (typeof table === 'string' && table.trim() !== '') {
3070
+ normalizedTables = [table];
2940
3071
  }
2941
- if (changes['controlData']) {
2942
- //console.log('Nuevo valor controlData:', this.controlData);
2943
- this.dataWidget = { idComponent: this.componentWidgetId,
2944
- controlConfig: this.controlConfig,
2945
- controlData: this.controlData
2946
- };
3072
+ else {
3073
+ normalizedTables = Object.keys(allTablesData);
2947
3074
  }
2948
- }
2949
- /* BEGIN - BARRA DE EVENTOS DEL WIDGET */
2950
- //Eliminacion de Widget - Conectado al Dashboard
2951
- onDeleteClick() {
2952
- this.eventDeleteRequest.emit(this.configWidget.widgetId);
2953
- }
2954
- onLockClick() {
2955
- // Invertimos el estado local y notificamos al padre
2956
- const nextState = !this.isLocked();
2957
- this.isLocked.set(nextState);
2958
- this.eventLockToggleRequest.emit({ widgetId: this.configWidget.widgetId, shouldLock: nextState });
2959
- }
2960
- onMaximizeClick() {
2961
- const nextState = !this.isMaximized();
2962
- this.isMaximized.set(nextState);
2963
- this.eventMaximizeToggleRequest.emit({ widgetId: this.configWidget.widgetId, shouldMaximize: nextState });
2964
- }
2965
- onShowFormConfigClick() {
2966
- this.eventShowConfigFormRequest.emit(this.configWidget.widgetId);
2967
- }
2968
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2969
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardWidgetComponent, isStandalone: true, selector: "yw-dashboard-widget", inputs: { styleWidget: { classPropertyName: "styleWidget", publicName: "styleWidget", isSignal: true, isRequired: false, transformFunction: null }, configWidget: { classPropertyName: "configWidget", publicName: "configWidget", isSignal: false, isRequired: false, transformFunction: null }, controlConfig: { classPropertyName: "controlConfig", publicName: "controlConfig", isSignal: false, isRequired: false, transformFunction: null }, controlData: { classPropertyName: "controlData", publicName: "controlData", isSignal: false, isRequired: false, transformFunction: null }, isLocked: { classPropertyName: "isLocked", publicName: "isLocked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isLocked: "isLockedChange", eventDeleteRequest: "eventDeleteRequest", eventLockToggleRequest: "eventLockToggleRequest", eventMaximizeToggleRequest: "eventMaximizeToggleRequest", eventShowConfigFormRequest: "eventShowConfigFormRequest" }, host: { properties: { "style.--widget-bg": "instanceStyleWidget().widgetBackgroundColor", "style.--widget-border-color": "instanceStyleWidget().widgetBorderColor" } }, usesOnChanges: true, ngImport: i0, template: "\r\n<!-- <div class=\"widget-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\">{{ isLocked() ? '\uD83D\uDD12' : '\uD83D\uDD13' }}</button>\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\">{{ isMaximized() ? '\uD83D\uDDD7' : '\uD83D\uDDD6' }}</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div> -->\r\n\r\n<div class=\"widget-action-bar\">\r\n <!-- Bot\u00F3n Bloquear / Desbloquear -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\" [title]=\"isLocked() ? 'Desbloquear' : 'Bloquear'\">\r\n <svg *ngIf=\"isLocked(); else unlockedIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\r\n <ng-template #unlockedIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Maximizar / Restaurar -->\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\" [title]=\"isMaximized() ? 'Restaurar' : 'Maximizar'\">\r\n <svg *ngIf=\"isMaximized(); else maxIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\"></path></svg>\r\n <ng-template #maxIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Eliminar -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\" title=\"Eliminar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Configuraci\u00F3n -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\" title=\"Configurar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg>\r\n </button>\r\n</div>\r\n\r\n<div class=\"widget-content-wrapper\">\r\n @if ( typeComponent == 'dummy' ) {\r\n <ng-container *ngTemplateOutlet=\"testdummy; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'empty-visual' ) {\r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-bar' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbar; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-line' ) {\r\n <ng-container *ngTemplateOutlet=\"chartline; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-doughnut' ) {\r\n <ng-container *ngTemplateOutlet=\"chartdoughnut; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-gauge' ) {\r\n <ng-container *ngTemplateOutlet=\"chartgauge; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- DUMMY TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #testdummy let-control = \"control\">\r\n <lib-test-chart [idComponent]=\"control.idComponent\" > \r\n </lib-test-chart>\r\n</ng-template>\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BAR CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbar let-control = \"control\">\r\n <yw-bar-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-bar-chart>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartline let-control = \"control\">\r\n <yw-line-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-line-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE DOUGHNUT TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartdoughnut let-control = \"control\">\r\n <yw-pie-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-pie-chart>\r\n</ng-template>\r\n\r\n \r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE GAUGE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartgauge let-control = \"control\">\r\n <yw-gauge-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-gauge-chart>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;flex-direction:column;width:100%;overflow:hidden;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #007bff)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-content-wrapper{width:100%;flex-grow:1;height:0;display:flex;flex-direction:column}.widget-action-bar button,.widget-action-bar .btn-action,.widget-action-bar .btn-delete,.widget-action-bar .btn-config{background:transparent;border:1px solid #d9d9d9;border-radius:4px;cursor:pointer;width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;color:#595959;padding:0;transition:all .2s ease}.widget-action-bar button svg,.widget-action-bar .btn-action svg,.widget-action-bar .btn-delete svg,.widget-action-bar .btn-config svg{width:14px;height:14px}.widget-action-bar button:hover,.widget-action-bar .btn-action:hover,.widget-action-bar .btn-delete:hover,.widget-action-bar .btn-config:hover{background-color:#f5f5f5;color:#262626;border-color:#bfbfbf}.widget-action-bar button:active,.widget-action-bar .btn-action:active,.widget-action-bar .btn-delete:active,.widget-action-bar .btn-config:active{background-color:#e6e6e6}.widget-action-bar .btn-delete:hover{background-color:#fff1f0;color:#ff4d4f;border-color:#ffa39e}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TestChartComponent, selector: "lib-test-chart", inputs: ["idComponent"] }, { kind: "component", type: YwEmptyVisualComponent, selector: "yw-empty-visual", inputs: ["idComponent", "config"] }, { kind: "component", type: LineChartComponent, selector: "yw-line-chart", inputs: ["chartData", "config", "idComponent"] }, { kind: "component", type: BarChartComponent, selector: "yw-bar-chart", inputs: ["chartData", "config", "idComponent"] }, { kind: "component", type: PieChartComponent, selector: "yw-pie-chart", inputs: ["idComponent", "chartData", "config"] }, { kind: "component", type: GaugeChartComponent, selector: "yw-gauge-chart", inputs: ["idComponent", "chartData", "config"] }] }); }
2970
- }
2971
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardWidgetComponent, decorators: [{
2972
- type: Component,
2973
- args: [{ selector: 'yw-dashboard-widget', standalone: true, imports: [CommonModule,
2974
- TestChartComponent,
2975
- YwEmptyVisualComponent,
2976
- LineChartComponent,
2977
- BarChartComponent,
2978
- PieChartComponent,
2979
- GaugeChartComponent
2980
- ], host: {
2981
- '[style.--widget-bg]': 'instanceStyleWidget().widgetBackgroundColor',
2982
- '[style.--widget-border-color]': 'instanceStyleWidget().widgetBorderColor'
2983
- }, template: "\r\n<!-- <div class=\"widget-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\">{{ isLocked() ? '\uD83D\uDD12' : '\uD83D\uDD13' }}</button>\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\">{{ isMaximized() ? '\uD83D\uDDD7' : '\uD83D\uDDD6' }}</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div> -->\r\n\r\n<div class=\"widget-action-bar\">\r\n <!-- Bot\u00F3n Bloquear / Desbloquear -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\" [title]=\"isLocked() ? 'Desbloquear' : 'Bloquear'\">\r\n <svg *ngIf=\"isLocked(); else unlockedIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\r\n <ng-template #unlockedIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Maximizar / Restaurar -->\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\" [title]=\"isMaximized() ? 'Restaurar' : 'Maximizar'\">\r\n <svg *ngIf=\"isMaximized(); else maxIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\"></path></svg>\r\n <ng-template #maxIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Eliminar -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\" title=\"Eliminar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Configuraci\u00F3n -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\" title=\"Configurar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg>\r\n </button>\r\n</div>\r\n\r\n<div class=\"widget-content-wrapper\">\r\n @if ( typeComponent == 'dummy' ) {\r\n <ng-container *ngTemplateOutlet=\"testdummy; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'empty-visual' ) {\r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-bar' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbar; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-line' ) {\r\n <ng-container *ngTemplateOutlet=\"chartline; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-doughnut' ) {\r\n <ng-container *ngTemplateOutlet=\"chartdoughnut; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-gauge' ) {\r\n <ng-container *ngTemplateOutlet=\"chartgauge; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- DUMMY TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #testdummy let-control = \"control\">\r\n <lib-test-chart [idComponent]=\"control.idComponent\" > \r\n </lib-test-chart>\r\n</ng-template>\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BAR CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbar let-control = \"control\">\r\n <yw-bar-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-bar-chart>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartline let-control = \"control\">\r\n <yw-line-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-line-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE DOUGHNUT TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartdoughnut let-control = \"control\">\r\n <yw-pie-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-pie-chart>\r\n</ng-template>\r\n\r\n \r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE GAUGE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartgauge let-control = \"control\">\r\n <yw-gauge-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-gauge-chart>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;flex-direction:column;width:100%;overflow:hidden;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #007bff)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-content-wrapper{width:100%;flex-grow:1;height:0;display:flex;flex-direction:column}.widget-action-bar button,.widget-action-bar .btn-action,.widget-action-bar .btn-delete,.widget-action-bar .btn-config{background:transparent;border:1px solid #d9d9d9;border-radius:4px;cursor:pointer;width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;color:#595959;padding:0;transition:all .2s ease}.widget-action-bar button svg,.widget-action-bar .btn-action svg,.widget-action-bar .btn-delete svg,.widget-action-bar .btn-config svg{width:14px;height:14px}.widget-action-bar button:hover,.widget-action-bar .btn-action:hover,.widget-action-bar .btn-delete:hover,.widget-action-bar .btn-config:hover{background-color:#f5f5f5;color:#262626;border-color:#bfbfbf}.widget-action-bar button:active,.widget-action-bar .btn-action:active,.widget-action-bar .btn-delete:active,.widget-action-bar .btn-config:active{background-color:#e6e6e6}.widget-action-bar .btn-delete:hover{background-color:#fff1f0;color:#ff4d4f;border-color:#ffa39e}\n"] }]
2984
- }], ctorParameters: () => [], propDecorators: { styleWidget: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleWidget", required: false }] }], configWidget: [{
2985
- type: Input
2986
- }], controlConfig: [{
2987
- type: Input
2988
- }], controlData: [{
2989
- type: Input
2990
- }], isLocked: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLocked", required: false }] }, { type: i0.Output, args: ["isLockedChange"] }], eventDeleteRequest: [{ type: i0.Output, args: ["eventDeleteRequest"] }], eventLockToggleRequest: [{ type: i0.Output, args: ["eventLockToggleRequest"] }], eventMaximizeToggleRequest: [{ type: i0.Output, args: ["eventMaximizeToggleRequest"] }], eventShowConfigFormRequest: [{ type: i0.Output, args: ["eventShowConfigFormRequest"] }] } });
3075
+ series = normalizedTables
3076
+ .map((tableName) => {
3077
+ const rawData = (allTablesData && allTablesData[tableName]) ? allTablesData[tableName] : [];
3078
+ if (!rawData || rawData.length === 0)
3079
+ return null;
3080
+ const orderedRawData = rawData.filter((item) => item && xAxis && getNestedValue(item, xAxis) !== undefined && getNestedValue(item, xAxis) !== null);
3081
+ if (orderedRawData.length === 0)
3082
+ return null;
3083
+ const dataSource = orderedRawData.map((item) => {
3084
+ let valorFinal = 0;
3085
+ let sizeFinal = 0;
3086
+ const shouldColorLine = chartoColoredLine;
3087
+ const rawVal = getNestedValue(item, yAxis);
3088
+ // const rawSize = getNestedValue(item, size);
3089
+ if (rawVal !== undefined) {
3090
+ valorFinal = typeof rawVal === "number" ? rawVal : Number(rawVal) || 0;
3091
+ }
3092
+ // if (rawSize !== undefined) {
3093
+ sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
3094
+ // }
3095
+ return {
3096
+ x: String(getNestedValue(item, xAxis)),
3097
+ y: valorFinal,
3098
+ size: sizeFinal, // <--- Valor numérico extraído
3099
+ name: String(getNestedValue(item, xAxis))
3100
+ // ...(shouldColorLine ? { color: getRandomProfessionalHex() } : {})
3101
+ };
3102
+ });
3103
+ return {
3104
+ name: tableName === 'default' ? xAxis : tableName,
3105
+ dataSource: aggregateByX(dataSource),
3106
+ opacity: opacity,
3107
+ emptyPointSettings: emptyPointSettings,
3108
+ // dashArray: dashArray !== undefined ? dashArray : undefined,
3109
+ // width: width !== undefined ? width : undefined,
3110
+ // widthLine: widthLine !== undefined ? widthLine : undefined,
3111
+ };
3112
+ })
3113
+ .filter((item) => item !== null);
3114
+ }
3115
+ const labelData = {
3116
+ title: title || "",
3117
+ titleStyle: {
3118
+ size: '16px',
3119
+ fontWeight: '600',
3120
+ color: '#2b2b2b',
3121
+ fontFamily: 'Inherit',
3122
+ textAlignment: 'Center'
3123
+ },
3124
+ axisX: {
3125
+ valueType: 'Category',
3126
+ // title: typeof xLabelText === 'string' ? xLabelText : 'Categoría',
3127
+ // labelIntersectAction: 'Rotate90',
3128
+ // labelIntersectAction: 'Rotate45',
3129
+ majorGridLines: { width: 0 },
3130
+ majorTickLines: { width: 0 },
3131
+ lineStyle: { width: 0 },
3132
+ labelStyle: { color: '#64748B', size: '12px', fontFamily: 'Inherit' }
3133
+ },
3134
+ axisY: {
3135
+ title: typeof yLabelText === 'string' ? yLabelText : 'Valor',
3136
+ minimum: 0,
3137
+ edgeLabelPlacement: 'Shift',
3138
+ lineStyle: { width: 0 },
3139
+ majorTickLines: { width: 0 },
3140
+ minorTickLines: { width: 0 },
3141
+ majorGridLines: { width: 0.5, color: '#E2E8F0', dashArray: '4,4' },
3142
+ labelStyle: { color: '#94A3B8', size: '12px', fontFamily: 'Inherit' },
3143
+ titleStyle: { size: '12px', color: '#64748B', fontFamily: 'Inherit' }
3144
+ },
3145
+ marker: {
3146
+ visible: true,
3147
+ width: 8,
3148
+ height: 8,
3149
+ dataLabel: {
3150
+ visible: true,
3151
+ position: 'Top', // Centra el texto exactamente en el medio de la burbuja
3152
+ name: 'text', // Asegúrate de que apunte al campo de tu data que trae el nombre (ej: 'text' o 'name')
3153
+ font: {
3154
+ fontWeight: '600',
3155
+ color: '#334155', // Color del texto (oscuro para que contraste con el fondo claro) o '#FFFFFF' si prefieres blanco
3156
+ size: '12px',
3157
+ fontFamily: 'Inherit'
3158
+ }
3159
+ }
3160
+ },
3161
+ palettes: ['#6366F1', '#22D3EE', '#F59E0B', '#10B981', '#F43F5E'],
3162
+ border: { width: 0 },
3163
+ chartArea: { border: { width: 0 }, margin: { bottom: 12 } },
3164
+ tooltip: {
3165
+ ...(tooltip?.enable !== undefined ? { enable: tooltip.enable } : {}),
3166
+ ...(tooltip?.format ? { format: tooltip.format } : {}),
3167
+ ...(tooltip?.header ? { header: tooltip.header } : {}),
3168
+ ...(tooltip?.shared !== undefined ? { shared: tooltip.shared } : {}),
3169
+ enableHighlight: true,
3170
+ },
3171
+ legendSettings: {
3172
+ visible: legends?.visible !== undefined ? legends.visible : undefined,
3173
+ position: legends?.position !== undefined ? legends.position : undefined
3174
+ },
3175
+ ruleColorPoint: ruleColorPoint !== undefined ? ruleColorPoint : undefined
3176
+ };
3177
+ return {
3178
+ series,
3179
+ labelData
3180
+ };
3181
+ };
2991
3182
 
2992
- class YwBaseSlicerComponent {
2993
- constructor() {
2994
- // Inputs de configuración del rango de fechas
3183
+ class BubbleChartSyncfusionComponent {
3184
+ constructor(elRef, cdr) {
3185
+ this.elRef = elRef;
3186
+ this.cdr = cdr;
2995
3187
  this.idComponent = '';
2996
- this.dataType = 'date';
2997
- this.label = input('Fecha', ...(ngDevMode ? [{ debugName: "label" }] : []));
2998
- this.min = input(...(ngDevMode ? [undefined, { debugName: "min" }] : []));
2999
- this.max = input(...(ngDevMode ? [undefined, { debugName: "max" }] : []));
3000
- this.step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
3001
- this.minCurrent = input(...(ngDevMode ? [undefined, { debugName: "minCurrent" }] : []));
3002
- this.maxCurrent = input(...(ngDevMode ? [undefined, { debugName: "maxCurrent" }] : []));
3003
- this.minNumber = 0;
3004
- this.maxNumber = 1000;
3005
- this.minDate = '2020-01-01';
3006
- this.maxDate = '2022-12-31';
3007
- // Evento de salida
3008
- this.rangeChange = output();
3009
- // Signals para las fechas seleccionadas
3010
- this.startDate = signal('2020-01-01', ...(ngDevMode ? [{ debugName: "startDate" }] : []));
3011
- this.endDate = signal('2022-09-22', ...(ngDevMode ? [{ debugName: "endDate" }] : []));
3012
- // Signals para los numeros seleccionadas
3013
- this.startVal = signal(0, ...(ngDevMode ? [{ debugName: "startVal" }] : []));
3014
- this.endVal = signal(1000, ...(ngDevMode ? [{ debugName: "endVal" }] : []));
3015
- this.minTimestamp = computed(() => new Date(this.minDate).getTime(), ...(ngDevMode ? [{ debugName: "minTimestamp" }] : []));
3016
- this.maxTimestamp = computed(() => new Date(this.maxDate).getTime(), ...(ngDevMode ? [{ debugName: "maxTimestamp" }] : []));
3017
- this.startTimestamp = computed(() => new Date(this.startDate()).getTime(), ...(ngDevMode ? [{ debugName: "startTimestamp" }] : []));
3018
- this.endTimestamp = computed(() => new Date(this.endDate()).getTime(), ...(ngDevMode ? [{ debugName: "endTimestamp" }] : []));
3019
- // Inicializar valores al arrancar
3020
- effect(() => {
3021
- if (this.dataType == 'date') {
3022
- this.startDate.set(this.minCurrent() || this.minDate);
3023
- this.endDate.set(this.maxCurrent() || this.maxDate);
3024
- }
3025
- if (this.dataType == 'number') {
3026
- this.startVal.set(this.minCurrent() || this.minNumber);
3027
- this.endVal.set(this.maxCurrent() || this.maxNumber);
3028
- }
3029
- }, { allowSignalWrites: true });
3030
- // Notificar al padre cada vez que cambien los valores
3031
- effect(() => {
3032
- if (this.dataType == 'date') {
3033
- this.rangeChange.emit({
3034
- startDate: this.startDate(),
3035
- endDate: this.endDate()
3036
- });
3037
- }
3038
- if (this.dataType == 'number') {
3039
- this.rangeChange.emit({
3040
- minValue: this.startVal(),
3041
- maxValue: this.endVal()
3042
- });
3043
- }
3044
- });
3188
+ this.dataChartParse = [];
3189
+ this.currentLabelSize = '';
3190
+ this.currentWidgetWidth = 0; // Valor inicial por defecto
3045
3191
  }
3046
3192
  ngOnInit() {
3047
- if (this.dataType == 'date') {
3048
- this.minDate = this.min();
3049
- this.maxDate = this.max();
3050
- this.minTimestamp = computed(() => new Date(this.minDate).getTime(), ...(ngDevMode ? [{ debugName: "minTimestamp" }] : []));
3051
- this.maxTimestamp = computed(() => new Date(this.maxDate).getTime(), ...(ngDevMode ? [{ debugName: "maxTimestamp" }] : []));
3052
- this.startTimestamp = computed(() => new Date(this.startDate()).getTime(), ...(ngDevMode ? [{ debugName: "startTimestamp" }] : []));
3053
- this.endTimestamp = computed(() => new Date(this.endDate()).getTime(), ...(ngDevMode ? [{ debugName: "endTimestamp" }] : []));
3054
- }
3055
- if (this.dataType == 'number') {
3056
- this.minNumber = this.min();
3057
- this.maxNumber = this.max();
3058
- }
3059
- }
3060
- // Handlers para la entrada manual de fechas
3061
- onStartDateInput(value) {
3062
- if (value && value <= this.endDate()) {
3063
- this.startDate.set(value);
3064
- }
3193
+ this.updateParsedData();
3065
3194
  }
3066
- onEndDateInput(value) {
3067
- if (value && value >= this.startDate()) {
3068
- this.endDate.set(value);
3195
+ ngOnChanges(changes) {
3196
+ if (changes['chartData'] || changes['config']) {
3197
+ this.updateParsedData();
3069
3198
  }
3070
3199
  }
3071
- // Métodos para cambiar desde el Input Numérico
3072
- onStartInput(event) {
3073
- const value = Number(event.target.value);
3074
- if (!isNaN(value) && value <= this.endVal() && value >= this.min()) {
3075
- this.startVal.set(value);
3076
- }
3200
+ ngAfterViewInit() {
3201
+ this._startResizeObserver();
3077
3202
  }
3078
- onEndInput(event) {
3079
- const value = Number(event.target.value);
3080
- if (!isNaN(value) && value >= this.startVal() && value <= this.max()) {
3081
- this.endVal.set(value);
3082
- }
3203
+ ngOnDestroy() {
3204
+ this._resizeObserver?.disconnect();
3083
3205
  }
3084
- // Handlers para el movimiento del slider
3085
- onStartSliderChange(event) {
3086
- if (this.dataType == 'date') {
3087
- const val = Number(event.target.value);
3088
- const dateStr = new Date(val).toISOString().split('T')[0];
3089
- if (val < this.endTimestamp()) {
3090
- this.startDate.set(dateStr);
3206
+ updateParsedData() {
3207
+ if (this.chartData && this.config) {
3208
+ const rawParsed = parseSyncFusionData(this.chartData, this.config);
3209
+ this.dataChartParse = rawParsed.series;
3210
+ this.labelData = rawParsed.labelData;
3211
+ if (this.dataLabel && this.labelData) {
3212
+ this.labelData.dataLabel = this.dataLabel;
3091
3213
  }
3092
- }
3093
- if (this.dataType == 'number') {
3094
- const val = Number(event.target.value);
3095
- if (val < this.endVal()) {
3096
- this.startVal.set(val);
3214
+ this.cdr.markForCheck();
3215
+ if (this.chartInstance) {
3216
+ setTimeout(() => {
3217
+ this.chartInstance?.refresh();
3218
+ });
3097
3219
  }
3098
3220
  }
3099
3221
  }
3100
- onEndSliderChange(event) {
3101
- if (this.dataType == 'date') {
3102
- const val = Number(event.target.value);
3103
- const dateStr = new Date(val).toISOString().split('T')[0];
3104
- if (val > this.startTimestamp()) {
3105
- this.endDate.set(dateStr);
3106
- }
3107
- }
3108
- if (this.dataType == 'number') {
3109
- const val = Number(event.target.value);
3110
- if (val > this.startVal()) {
3111
- this.endVal.set(val);
3222
+ pointRender(args) {
3223
+ const yValue = Number(args.point.y);
3224
+ // =====================================================
3225
+ // EMPTY POINT / VALOR 0
3226
+ // Tiene prioridad sobre ruleColorPoint
3227
+ // =====================================================
3228
+ if (yValue === 0) {
3229
+ const emptyPoint = this.config.emptyPointSettings;
3230
+ if (emptyPoint && emptyPoint !== '') {
3231
+ args.fill = emptyPoint;
3112
3232
  }
3233
+ return;
3113
3234
  }
3235
+ // =====================================================
3236
+ // RULE COLOR POINT
3237
+ // =====================================================
3238
+ const configPoint = this.config.ruleColorPoint || null;
3239
+ if (!configPoint) {
3240
+ return;
3241
+ }
3242
+ let passesRule = false;
3243
+ switch (configPoint.rule) {
3244
+ case 'threshold':
3245
+ passesRule =
3246
+ yValue >= (configPoint.thresholdValue || 0);
3247
+ break;
3248
+ case 'pair':
3249
+ passesRule = yValue % 2 === 0;
3250
+ break;
3251
+ case 'range':
3252
+ const min = configPoint.minRange || 0;
3253
+ const max = configPoint.maxRange || 100;
3254
+ passesRule =
3255
+ yValue >= min &&
3256
+ yValue <= max;
3257
+ break;
3258
+ default:
3259
+ passesRule = true;
3260
+ }
3261
+ args.fill = passesRule
3262
+ ? (configPoint.trueColor || '#10B981')
3263
+ : (configPoint.falseColor || '#EF4444');
3114
3264
  }
3115
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwBaseSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3116
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwBaseSlicerComponent, isStandalone: true, selector: "yw-base-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, minCurrent: { classPropertyName: "minCurrent", publicName: "minCurrent", isSignal: true, isRequired: false, transformFunction: null }, maxCurrent: { classPropertyName: "maxCurrent", publicName: "maxCurrent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n <label class=\"filter-label\">{{ label() }}</label>\r\n\r\n <!-- Inputs de fecha superiores -->\r\n <div class=\"date-inputs-row\">\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"startDate()\"\r\n [min]=\"minDate\"\r\n [max]=\"endDate()\"\r\n (change)=\"onStartDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"startVal()\"\r\n [min]=\"minNumber\"\r\n [max]=\"endVal()\"\r\n [step]=\"step()\"\r\n (input)=\"onStartInput($event)\" \r\n />\r\n } \r\n </div>\r\n\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"endDate()\"\r\n [min]=\"startDate()\"\r\n [max]=\"maxDate\"\r\n (change)=\"onEndDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"endVal()\"\r\n [min]=\"startVal()\"\r\n [max]=\"maxNumber\"\r\n [step]=\"step()\"\r\n (input)=\"onEndInput($event)\" \r\n />\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dual Slider personalizado -->\r\n <div class=\"slider-container\">\r\n <div class=\"slider-track\"></div>\r\n @if (dataType === 'date') { \r\n <!-- Slider Inicio -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"startTimestamp()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider Fin -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"endTimestamp()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n }\r\n\r\n @if (dataType === 'number') { \r\n\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"startVal()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider M\u00E1ximo -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"endVal()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n\r\n }\r\n\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:360px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-label{font-size:13px;font-weight:600;color:#333}.date-inputs-row,.number-inputs-row{display:flex;gap:8px}.input-wrapper input[type=date]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=date]:focus{border-color:#a0aec0}.input-wrapper input[type=number]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;width:90px;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=number]:focus{border-color:#a0aec0}.slider-container{position:relative;width:100%;height:30px;display:flex;align-items:center;margin-top:4px}.slider-track{position:absolute;width:100%;height:2px;background-color:#666;border-radius:1px;z-index:1}.thumb{position:absolute;width:100%;appearance:none;-webkit-appearance:none;background:none;pointer-events:none;outline:none;margin:0;z-index:2}.thumb-right{z-index:3}.thumb::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box;transition:transform .1s ease}.thumb::-webkit-slider-thumb:hover{transform:scale(1.1);border-color:#333}.thumb::-moz-range-thumb{pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box}\n"] }); }
3117
- }
3118
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwBaseSlicerComponent, decorators: [{
3119
- type: Component,
3120
- args: [{ selector: 'yw-base-slicer', imports: [], host: {
3121
- '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3122
- }, template: "<div class=\"filter-container\">\r\n <label class=\"filter-label\">{{ label() }}</label>\r\n\r\n <!-- Inputs de fecha superiores -->\r\n <div class=\"date-inputs-row\">\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"startDate()\"\r\n [min]=\"minDate\"\r\n [max]=\"endDate()\"\r\n (change)=\"onStartDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"startVal()\"\r\n [min]=\"minNumber\"\r\n [max]=\"endVal()\"\r\n [step]=\"step()\"\r\n (input)=\"onStartInput($event)\" \r\n />\r\n } \r\n </div>\r\n\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"endDate()\"\r\n [min]=\"startDate()\"\r\n [max]=\"maxDate\"\r\n (change)=\"onEndDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"endVal()\"\r\n [min]=\"startVal()\"\r\n [max]=\"maxNumber\"\r\n [step]=\"step()\"\r\n (input)=\"onEndInput($event)\" \r\n />\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dual Slider personalizado -->\r\n <div class=\"slider-container\">\r\n <div class=\"slider-track\"></div>\r\n @if (dataType === 'date') { \r\n <!-- Slider Inicio -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"startTimestamp()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider Fin -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"endTimestamp()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n }\r\n\r\n @if (dataType === 'number') { \r\n\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"startVal()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider M\u00E1ximo -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"endVal()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n\r\n }\r\n\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:360px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-label{font-size:13px;font-weight:600;color:#333}.date-inputs-row,.number-inputs-row{display:flex;gap:8px}.input-wrapper input[type=date]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=date]:focus{border-color:#a0aec0}.input-wrapper input[type=number]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;width:90px;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=number]:focus{border-color:#a0aec0}.slider-container{position:relative;width:100%;height:30px;display:flex;align-items:center;margin-top:4px}.slider-track{position:absolute;width:100%;height:2px;background-color:#666;border-radius:1px;z-index:1}.thumb{position:absolute;width:100%;appearance:none;-webkit-appearance:none;background:none;pointer-events:none;outline:none;margin:0;z-index:2}.thumb-right{z-index:3}.thumb::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box;transition:transform .1s ease}.thumb::-webkit-slider-thumb:hover{transform:scale(1.1);border-color:#333}.thumb::-moz-range-thumb{pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box}\n"] }]
3123
- }], ctorParameters: () => [], propDecorators: { idComponent: [{
3124
- type: Input
3125
- }], dataType: [{
3126
- type: Input
3127
- }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], minCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "minCurrent", required: false }] }], maxCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxCurrent", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }] } });
3128
-
3129
- class YwButtonSlicerComponent {
3130
- constructor() {
3131
- // Configuración de entradas
3132
- this.idComponent = '';
3133
- this.label = input('Tipo de producto', ...(ngDevMode ? [{ debugName: "label" }] : []));
3134
- this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
3135
- this.allowMultiple = input(true, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : [])); // Permite cambiar a selección única si es necesario
3136
- // Evento de salida con la lista de IDs seleccionados
3137
- this.selectionChange = output();
3138
- // Signal con los IDs seleccionados
3139
- this.selectedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedIds" }] : []));
3140
- // Current IDs seleccionados
3141
- this.currentIds = input([], ...(ngDevMode ? [{ debugName: "currentIds" }] : []));
3142
- // Emitir el listado en Array cada vez que la Signal de selección cambie
3143
- effect(() => {
3144
- this.selectionChange.emit(Array.from(this.selectedIds()));
3145
- });
3146
- }
3147
- ngOnInit() {
3148
- if (this.currentIds() && this.currentIds().length > 0) {
3149
- this.selectedIds().clear();
3150
- this.currentIds().forEach((itemId) => {
3151
- this.selectedIds().add(itemId);
3265
+ _startResizeObserver() {
3266
+ if (typeof ResizeObserver === 'undefined')
3267
+ return;
3268
+ const hostEl = this.elRef.nativeElement;
3269
+ this._resizeObserver = new ResizeObserver((entries) => {
3270
+ window.requestAnimationFrame(() => {
3271
+ for (const entry of entries) {
3272
+ this.currentWidgetWidth = entry.contentRect.width;
3273
+ if (this.currentWidgetWidth > 0) {
3274
+ this._updateAdaptiveLabelSize(this.currentWidgetWidth);
3275
+ if (this.chartInstance) {
3276
+ // SI ACTIVAMSO EL REFRESH DA UN REBOTE AL REDIMENCIONAR
3277
+ this.chartInstance.refresh();
3278
+ }
3279
+ }
3280
+ }
3152
3281
  });
3282
+ });
3283
+ this._resizeObserver.observe(hostEl);
3284
+ }
3285
+ _updateAdaptiveLabelSize(width) {
3286
+ if (this.config?.labelSize) {
3287
+ const parsedSize = typeof this.config.labelSize === 'number'
3288
+ ? this.config.labelSize
3289
+ : parseFloat(this.config.labelSize);
3290
+ if (!isNaN(parsedSize)) {
3291
+ if (width < 260) {
3292
+ const scale = Math.max(0.65, width / 260);
3293
+ this.currentLabelSize = `${Math.round(parsedSize * scale)}px`;
3294
+ }
3295
+ else {
3296
+ this.currentLabelSize = `${parsedSize}px`;
3297
+ }
3298
+ this.cdr.markForCheck();
3299
+ return;
3300
+ }
3153
3301
  }
3302
+ // Proporción estándar ideal (~7.5% del ancho del contenedor, acotado entre 13px y 26px)
3303
+ const base = Math.max(13, Math.min(26, Math.round(width * 0.075)));
3304
+ this.currentLabelSize = `${base}px`;
3305
+ this.cdr.markForCheck();
3154
3306
  }
3155
- clearSelection() {
3156
- this.selectedIds().clear();
3157
- this.selectionChange.emit([]);
3307
+ refresh() {
3308
+ this.updateParsedData();
3158
3309
  }
3159
- // Toggle para seleccionar / deseleccionar
3160
- toggleSelection(id) {
3161
- const current = new Set(this.selectedIds());
3162
- if (this.allowMultiple()) {
3163
- if (current.has(id)) {
3164
- current.delete(id);
3310
+ // pointRender(args: any) {
3311
+ // if (args.point?.y === 0) {
3312
+ // args.fill = this.emptyPointSettings.fill;
3313
+ // args.border = {
3314
+ // width: this.emptyPointSettings.border?.width ?? 0,
3315
+ // color: this.emptyPointSettings.border?.color ?? ''
3316
+ // };
3317
+ // }
3318
+ // }
3319
+ axisLabelRender(args) {
3320
+ const umbralWidget = 700;
3321
+ if (this.currentWidgetWidth > umbralWidget) {
3322
+ return;
3323
+ }
3324
+ // Si la tarjeta es estrecha, aplicamos el recorte de etiquetas
3325
+ if (args.text && typeof args.text === 'string') {
3326
+ const palabras = args.text.split(' ');
3327
+ if (palabras.length > 1) {
3328
+ const primeraPalabra = palabras[0];
3329
+ const inicialSegunda = palabras[1].charAt(0).toUpperCase();
3330
+ args.text = `${primeraPalabra} ${inicialSegunda}.`;
3165
3331
  }
3166
3332
  else {
3167
- current.add(id);
3333
+ if (args.text.length > 10) {
3334
+ args.text = args.text.substring(0, 9) + '.';
3335
+ }
3168
3336
  }
3169
3337
  }
3170
- else {
3171
- // Si es selección única
3172
- current.clear();
3173
- current.add(id);
3174
- }
3175
- this.selectedIds.set(current);
3176
- }
3177
- isSelected(id) {
3178
- return this.selectedIds().has(id);
3179
3338
  }
3180
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwButtonSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3181
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwButtonSlicerComponent, isStandalone: true, selector: "yw-button-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, allowMultiple: { classPropertyName: "allowMultiple", publicName: "allowMultiple", isSignal: true, isRequired: false, transformFunction: null }, currentIds: { classPropertyName: "currentIds", publicName: "currentIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n \r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\"> \r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" >\uD83E\uDDF9</button> \r\n </div>\r\n </div>\r\n\r\n\r\n <!-- Contenedor con barra de desplazamiento interna -->\r\n <div class=\"grid-scroll-container\">\r\n <div class=\"buttons-grid\">\r\n @for (item of options(); track item.id) {\r\n <button \r\n type=\"button\" \r\n class=\"option-btn\" \r\n [class.selected]=\"isSelected(item.id)\"\r\n (click)=\"toggleSelection(item.id)\"\r\n [title]=\"item.label\">\r\n <span class=\"btn-text\">{{ item.label }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:320px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#333}.header-actions{display:flex;gap:4px}.grid-scroll-container{max-height:145px;overflow-y:auto;padding-right:4px}.buttons-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.option-btn{display:flex;align-items:center;justify-content:center;height:38px;padding:4px 6px;background-color:#fff;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;transition:all .15s ease-in-out;outline:none;box-sizing:border-box}.option-btn:hover{border-color:#9ca3af;background-color:#f9fafb}.btn-text{font-size:12px;color:#374151;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;text-align:center}.option-btn.selected{border-color:#2563eb;background-color:#eff6ff;box-shadow:0 0 0 1px #2563eb}.option-btn.selected .btn-text{color:#1d4ed8;font-weight:600}.grid-scroll-container::-webkit-scrollbar{width:6px}.grid-scroll-container::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb{background:#71717a;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb:hover{background:#52525b}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
3339
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartSyncfusionComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3340
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: BubbleChartSyncfusionComponent, isStandalone: true, selector: "yw-bubble-chart-syncfusion", inputs: { chartData: "chartData", config: "config", idComponent: "idComponent" }, providers: [BubbleSeriesService, CategoryService, CategoryService,
3341
+ TooltipService,
3342
+ LegendService,
3343
+ DateTimeService, DataLabelService], viewQueries: [{ propertyName: "chartInstance", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"control-section\">\r\n <ejs-chart \r\n #chart \r\n [primaryXAxis]=\"labelData.axisX\" \r\n [primaryYAxis]=\"labelData.axisY\" \r\n [title]=\"labelData.title\" \r\n [palettes]=\"labelData.palettes\"\r\n [chartArea]=\"labelData.chartArea\"\r\n [titleStyle]=\"labelData.titleStyle\"\r\n\r\n (pointRender)=\"pointRender($event)\" \r\n height=\"100%\"\r\n width=\"100%\"\r\n [legendSettings]=\"labelData.legendSettings\"\r\n (axisLabelRender)=\"axisLabelRender($event)\"\r\n\r\n [tooltip]=\"labelData.tooltip\">\r\n <e-series-collection>\r\n @for(series of dataChartParse; track $index){\r\n <e-series \r\n [opacity]=\"series.opacity\"\r\n [dataSource]='series.dataSource' \r\n type='Bubble' \r\n xName='x' \r\n yName='y' \r\n size='size'\r\n [name]='series.name' \r\n\r\n [marker]=\"labelData.marker\"\r\n \r\n >\r\n <!-- [dataLabel]='series.dataLabel' -->\r\n </e-series>\r\n\r\n }\r\n </e-series-collection>\r\n</ejs-chart>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden}.control-section{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden;background:#fff;border-radius:8px}:host ::ng-deep ejs-circulargauge{display:block;width:100%!important;height:100%!important;flex-grow:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartModule }, { kind: "component", type: i1.ChartComponent, selector: "ejs-chart", inputs: ["accessibility", "allowExport", "allowMultiSelection", "annotations", "axes", "background", "backgroundImage", "border", "chartArea", "columns", "crosshair", "currencyCode", "dataSource", "description", "enableAnimation", "enableAutoIntervalOnBothAxis", "enableCanvas", "enableExport", "enableHtmlSanitizer", "enablePersistence", "enableRtl", "enableSideBySidePlacement", "focusBorderColor", "focusBorderMargin", "focusBorderWidth", "height", "highlightColor", "highlightMode", "highlightPattern", "indicators", "isMultiSelect", "isTransposed", "legendSettings", "locale", "margin", "palettes", "primaryXAxis", "primaryYAxis", "rangeColorSettings", "rows", "selectedDataIndexes", "selectionMode", "selectionPattern", "series", "subTitle", "subTitleStyle", "tabIndex", "theme", "title", "titleStyle", "tooltip", "useGroupingSeparator", "width", "zoomSettings"], outputs: ["afterExport", "animationComplete", "annotationRender", "axisLabelClick", "axisLabelRender", "axisMultiLabelRender", "axisRangeCalculated", "beforeExport", "beforePrint", "beforeResize", "chartDoubleClick", "chartMouseClick", "chartMouseDown", "chartMouseLeave", "chartMouseMove", "chartMouseUp", "drag", "dragComplete", "dragEnd", "dragStart", "legendClick", "legendRender", "load", "loaded", "multiLevelLabelClick", "onZooming", "pointClick", "pointDoubleClick", "pointMove", "pointRender", "resized", "scrollChanged", "scrollEnd", "scrollStart", "selectionComplete", "seriesRender", "sharedTooltipRender", "textRender", "tooltipRender", "zoomComplete", "dataSourceChange"] }, { kind: "directive", type: i1.SeriesDirective, selector: "e-series-collection>e-series", inputs: ["accessibility", "animation", "bearFillColor", "binInterval", "border", "boxPlotMode", "bullFillColor", "cardinalSplineTension", "close", "colorName", "columnFacet", "columnSpacing", "columnWidth", "columnWidthInPixel", "connector", "cornerRadius", "dashArray", "dataSource", "dragSettings", "drawType", "emptyPointSettings", "enableComplexProperty", "enableSolidCandles", "enableTooltip", "errorBar", "fill", "groupName", "high", "intermediateSumIndexes", "isClosed", "legendImageUrl", "legendShape", "low", "marker", "maxRadius", "minRadius", "name", "negativeFillColor", "noRisers", "nonHighlightStyle", "opacity", "open", "paretoOptions", "pointColorMapping", "query", "segmentAxis", "segments", "selectionStyle", "showMean", "showNormalDistribution", "size", "splineType", "stackingGroup", "step", "sumIndexes", "summaryFillColor", "tooltipFormat", "tooltipMappingName", "trendlines", "type", "unSelectedStyle", "visible", "volume", "width", "xAxisName", "xName", "yAxisName", "yName", "zOrder"] }, { kind: "directive", type: i1.SeriesCollectionDirective, selector: "ej-chart>e-series-collection" }] }); }
3182
3344
  }
3183
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwButtonSlicerComponent, decorators: [{
3345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartSyncfusionComponent, decorators: [{
3184
3346
  type: Component,
3185
- args: [{ selector: 'yw-button-slicer', standalone: true, imports: [CommonModule], host: {
3186
- '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3187
- }, template: "<div class=\"filter-container\">\r\n \r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\"> \r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" >\uD83E\uDDF9</button> \r\n </div>\r\n </div>\r\n\r\n\r\n <!-- Contenedor con barra de desplazamiento interna -->\r\n <div class=\"grid-scroll-container\">\r\n <div class=\"buttons-grid\">\r\n @for (item of options(); track item.id) {\r\n <button \r\n type=\"button\" \r\n class=\"option-btn\" \r\n [class.selected]=\"isSelected(item.id)\"\r\n (click)=\"toggleSelection(item.id)\"\r\n [title]=\"item.label\">\r\n <span class=\"btn-text\">{{ item.label }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:320px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#333}.header-actions{display:flex;gap:4px}.grid-scroll-container{max-height:145px;overflow-y:auto;padding-right:4px}.buttons-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.option-btn{display:flex;align-items:center;justify-content:center;height:38px;padding:4px 6px;background-color:#fff;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;transition:all .15s ease-in-out;outline:none;box-sizing:border-box}.option-btn:hover{border-color:#9ca3af;background-color:#f9fafb}.btn-text{font-size:12px;color:#374151;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;text-align:center}.option-btn.selected{border-color:#2563eb;background-color:#eff6ff;box-shadow:0 0 0 1px #2563eb}.option-btn.selected .btn-text{color:#1d4ed8;font-weight:600}.grid-scroll-container::-webkit-scrollbar{width:6px}.grid-scroll-container::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb{background:#71717a;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb:hover{background:#52525b}\n"] }]
3188
- }], ctorParameters: () => [], propDecorators: { idComponent: [{
3189
- type: Input
3190
- }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], allowMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowMultiple", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], currentIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentIds", required: false }] }] } });
3347
+ args: [{ selector: 'yw-bubble-chart-syncfusion', standalone: true, imports: [CommonModule, ChartModule], providers: [BubbleSeriesService, CategoryService, CategoryService,
3348
+ TooltipService,
3349
+ LegendService,
3350
+ DateTimeService, DataLabelService], template: "<div class=\"control-section\">\r\n <ejs-chart \r\n #chart \r\n [primaryXAxis]=\"labelData.axisX\" \r\n [primaryYAxis]=\"labelData.axisY\" \r\n [title]=\"labelData.title\" \r\n [palettes]=\"labelData.palettes\"\r\n [chartArea]=\"labelData.chartArea\"\r\n [titleStyle]=\"labelData.titleStyle\"\r\n\r\n (pointRender)=\"pointRender($event)\" \r\n height=\"100%\"\r\n width=\"100%\"\r\n [legendSettings]=\"labelData.legendSettings\"\r\n (axisLabelRender)=\"axisLabelRender($event)\"\r\n\r\n [tooltip]=\"labelData.tooltip\">\r\n <e-series-collection>\r\n @for(series of dataChartParse; track $index){\r\n <e-series \r\n [opacity]=\"series.opacity\"\r\n [dataSource]='series.dataSource' \r\n type='Bubble' \r\n xName='x' \r\n yName='y' \r\n size='size'\r\n [name]='series.name' \r\n\r\n [marker]=\"labelData.marker\"\r\n \r\n >\r\n <!-- [dataLabel]='series.dataLabel' -->\r\n </e-series>\r\n\r\n }\r\n </e-series-collection>\r\n</ejs-chart>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden}.control-section{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden;background:#fff;border-radius:8px}:host ::ng-deep ejs-circulargauge{display:block;width:100%!important;height:100%!important;flex-grow:1}\n"] }]
3351
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { chartInstance: [{
3352
+ type: ViewChild,
3353
+ args: ['chart']
3354
+ }], chartData: [{
3355
+ type: Input,
3356
+ args: ['chartData']
3357
+ }], config: [{
3358
+ type: Input,
3359
+ args: ['config']
3360
+ }], idComponent: [{
3361
+ type: Input,
3362
+ args: ['idComponent']
3363
+ }] } });
3191
3364
 
3192
- class YwListSlicerComponent {
3365
+ // import { LineChartSyncfusionComponent } from '../../../../../adapters/charts/line-chart/syncfusion/visual/yw-line-chart-syncfusion.component';
3366
+ // import { YwLineMappingConfig } from '../../../../../models/config/chart/yw-line-chart-config.interface';
3367
+ class BubbleChartComponent {
3193
3368
  constructor() {
3194
- // Entradas generales
3195
3369
  this.idComponent = '';
3196
- this.label = input('Filtro Jerárquico', ...(ngDevMode ? [{ debugName: "label" }] : []));
3197
- this.clearTitleLabel = input('Limpiar Seleccion', ...(ngDevMode ? [{ debugName: "clearTitleLabel" }] : []));
3198
- // Opción 1: Entregar datos en árbol de texto directo
3199
- this.rawData = input([], ...(ngDevMode ? [{ debugName: "rawData" }] : []));
3200
- // Opción 2: Generar desde fechas
3201
- this.dataType = input('date', ...(ngDevMode ? [{ debugName: "dataType" }] : []));
3202
- this.minDate = input('', ...(ngDevMode ? [{ debugName: "minDate" }] : [])); // Formato 'YYYY-MM-DD'
3203
- this.maxDate = input('', ...(ngDevMode ? [{ debugName: "maxDate" }] : []));
3204
- this.dateHierarchyType = input('YEAR_TRIMESTER_MONTH', ...(ngDevMode ? [{ debugName: "dateHierarchyType" }] : []));
3205
- this.monthNames = input(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], ...(ngDevMode ? [{ debugName: "monthNames" }] : []));
3206
- // Evento de salida con el ID/Nodo seleccionado
3207
- this.selectionChange = output();
3208
- this.filterValueChange = output(); // Output 2 (Rangos o Hojas)
3209
- // ID del elemento seleccionado (Selección Simple)
3210
- this.selectedId = signal(null, ...(ngDevMode ? [{ debugName: "selectedId" }] : []));
3211
- this.currentSelectedId = input(null, ...(ngDevMode ? [{ debugName: "currentSelectedId" }] : []));
3212
- // Arbol de nodos computado
3213
- this.treeNodes = computed(() => {
3214
- if (this.dataType() == 'date' && this.minDate() && this.maxDate()) {
3215
- return this.generateDateHierarchy(this.minDate(), this.maxDate(), this.dateHierarchyType());
3216
- }
3217
- return this.rawData();
3218
- }, ...(ngDevMode ? [{ debugName: "treeNodes" }] : []));
3219
- effect(() => {
3220
- const currentId = this.selectedId();
3221
- if (!currentId) {
3222
- this.selectionChange.emit(null);
3223
- this.filterValueChange.emit(null);
3224
- return;
3225
- }
3226
- const node = this.findNodeById(this.treeNodes(), currentId);
3227
- this.selectionChange.emit(node);
3228
- if (node) {
3229
- // Emitir el segundo Output según el modo
3230
- const calculatedValue = this.processFilterOutput(node);
3231
- this.filterValueChange.emit(calculatedValue);
3232
- }
3233
- });
3234
3370
  }
3235
3371
  ngOnInit() {
3236
- if (this.currentSelectedId()) {
3237
- this.selectedId.set(this.currentSelectedId());
3238
- }
3239
- }
3240
- // Métodos de Selección y Expansión
3241
- toggleExpand(node, event) {
3242
- event.stopPropagation();
3243
- node.expanded = !node.expanded;
3244
- }
3245
- selectNode(node, event) {
3246
- event.stopPropagation();
3247
- this.selectedId.set(this.selectedId() === node.id ? null : node.id);
3372
+ console.log("EL ID DEL COMPONENTE:", this.idComponent);
3248
3373
  }
3249
- clearSelection() {
3250
- this.selectedId.set(null);
3251
- this.filterValueChange.emit(null);
3374
+ ngOnChanges(changes) {
3375
+ if (changes['chartData']) {
3376
+ console.log('change chartDataBubble:', changes['chartData'].currentValue);
3377
+ }
3378
+ if (changes['config']) {
3379
+ console.log('change configBubble:', changes['config'].currentValue);
3380
+ }
3252
3381
  }
3253
- // --- LÓGICA DE PROCESAMIENTO DE LAS HOJAS / RANGOS ---
3254
- processFilterOutput(selectedNode) {
3255
- // 1. Obtener todas las hojas (nodos del nivel más bajo) pertenecientes al bloque seleccionado
3256
- const leaves = this.getLeafNodes(selectedNode);
3257
- if (this.dataType() == 'date') {
3258
- // Extraer todas las fechas de las hojas del bloque
3259
- const dates = leaves
3260
- .map(leaf => leaf.value)
3261
- .filter(d => d instanceof Date)
3262
- .sort((a, b) => a.getTime() - b.getTime());
3263
- if (dates.length > 0) {
3264
- const minD = dates[0];
3265
- // Para la fecha máxima, tomamos el último día del mes correspondiente
3266
- const maxD = new Date(dates[dates.length - 1].getFullYear(), dates[dates.length - 1].getMonth() + 1, 0);
3267
- return {
3268
- type: 'DATE_RANGE',
3269
- dateRange: {
3270
- minDate: minD.toISOString().split('T')[0],
3271
- maxDate: maxD.toISOString().split('T')[0]
3272
- },
3273
- currentNodeId: selectedNode.id
3274
- };
3275
- }
3276
- }
3277
- // Modo Texto: Entregar arreglo con las hojas
3278
- return {
3279
- type: 'TEXT_LEAVES',
3280
- leafNodes: leaves,
3281
- leafIds: leaves.map(l => l.id),
3282
- currentNodeId: selectedNode.id
3283
- };
3284
- }
3285
- // Recorrido recursivo para obtener solo los nodos terminales (sin hijos)
3286
- getLeafNodes(node) {
3287
- if (!node.children || node.children.length === 0) {
3288
- return [node];
3289
- }
3290
- let leaves = [];
3291
- for (const child of node.children) {
3292
- leaves = leaves.concat(this.getLeafNodes(child));
3293
- }
3294
- return leaves;
3295
- }
3296
- findNodeById(nodes, id) {
3297
- for (const node of nodes) {
3298
- if (node.id === id)
3299
- return node;
3300
- if (node.children) {
3301
- const found = this.findNodeById(node.children, id);
3302
- if (found)
3303
- return found;
3304
- }
3305
- }
3306
- return null;
3307
- }
3308
- // Generador de Jerarquía por Fechas
3309
- generateDateHierarchy(startStr, endStr, type) {
3310
- const start = new Date(startStr);
3311
- const end = new Date(endStr);
3312
- const tree = [];
3313
- const monthNames = this.monthNames();
3314
- if (type === 'YEAR_TRIMESTER_MONTH') {
3315
- let current = new Date(start);
3316
- while (current <= end) {
3317
- const year = current.getFullYear();
3318
- let yearNode = tree.find(n => n.id === `Y_${year}`);
3319
- if (!yearNode) {
3320
- yearNode = { id: `Y_${year}`, label: `${year}`, children: [], expanded: false };
3321
- tree.push(yearNode);
3322
- }
3323
- const month = current.getMonth();
3324
- const qtrNum = Math.floor(month / 3) + 1;
3325
- let qtrNode = yearNode.children.find(n => n.id === `Q_${year}_${qtrNum}`);
3326
- if (!qtrNode) {
3327
- qtrNode = { id: `Q_${year}_${qtrNum}`, label: `Qtr ${qtrNum}`, children: [], expanded: false };
3328
- yearNode.children.push(qtrNode);
3329
- }
3330
- const monthId = `M_${year}_${month + 1}`;
3331
- if (!qtrNode.children.some(n => n.id === monthId)) {
3332
- qtrNode.children.push({
3333
- id: monthId,
3334
- label: monthNames[month],
3335
- value: new Date(year, month, 1) // Fecha inicial del mes
3336
- });
3337
- }
3338
- current.setMonth(current.getMonth() + 1);
3339
- }
3340
- }
3341
- if (type === 'YEAR_SEMESTER_MONTH') {
3342
- let current = new Date(start);
3343
- while (current <= end) {
3344
- const year = current.getFullYear();
3345
- let yearNode = tree.find(n => n.id === `Y_${year}`);
3346
- if (!yearNode) {
3347
- yearNode = { id: `Y_${year}`, label: `${year}`, children: [], expanded: false };
3348
- tree.push(yearNode);
3349
- }
3350
- const month = current.getMonth();
3351
- const qtrNum = Math.floor(month / 6) + 1;
3352
- let qtrNode = yearNode.children.find(n => n.id === `S_${year}_${qtrNum}`);
3353
- if (!qtrNode) {
3354
- qtrNode = { id: `S_${year}_${qtrNum}`, label: `S ${qtrNum}`, children: [], expanded: false };
3355
- yearNode.children.push(qtrNode);
3356
- }
3357
- const monthId = `M_${year}_${month + 1}`;
3358
- if (!qtrNode.children.some(n => n.id === monthId)) {
3359
- qtrNode.children.push({
3360
- id: monthId,
3361
- label: monthNames[month],
3362
- value: new Date(year, month, 1) // Fecha inicial del mes
3363
- });
3364
- }
3365
- current.setMonth(current.getMonth() + 1);
3366
- }
3367
- }
3368
- return tree;
3369
- }
3370
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwListSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3371
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwListSlicerComponent, isStandalone: true, selector: "yw-list-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, clearTitleLabel: { classPropertyName: "clearTitleLabel", publicName: "clearTitleLabel", isSignal: true, isRequired: false, transformFunction: null }, rawData: { classPropertyName: "rawData", publicName: "rawData", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateHierarchyType: { classPropertyName: "dateHierarchyType", publicName: "dateHierarchyType", isSignal: true, isRequired: false, transformFunction: null }, monthNames: { classPropertyName: "monthNames", publicName: "monthNames", isSignal: true, isRequired: false, transformFunction: null }, currentSelectedId: { classPropertyName: "currentSelectedId", publicName: "currentSelectedId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", filterValueChange: "filterValueChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n <!-- Cabecera con t\u00EDtulo y acciones de filtro -->\r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\">\r\n <!--<button class=\"icon-btn\" title=\"Filtro\">\uD83D\uDD3B</button>-->\r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" title=\"{{clearTitleLabel}}\">\uD83E\uDDF9</button>\r\n <!--<button class=\"icon-btn\" title=\"M\u00E1s opciones\">\u22EE</button>-->\r\n </div>\r\n </div>\r\n\r\n <!-- Vista en \u00C1rbol con scroll interno -->\r\n <div class=\"tree-scroll-container\">\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: treeNodes(), level: 0 }\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n<!-- Plantilla Recursiva para renderizar niveles del \u00C1rbol -->\r\n<ng-template #nodeListTemplate let-nodes let-level=\"level\">\r\n <div class=\"tree-level\">\r\n @for (node of nodes; track node.id) {\r\n <div class=\"tree-node-wrapper\">\r\n <!-- Fila de opci\u00F3n -->\r\n <div \r\n class=\"tree-node-row\" \r\n [class.selected]=\"selectedId() === node.id\"\r\n [style.padding-left.px]=\"level * 18 + 6\"\r\n (click)=\"selectNode(node, $event)\">\r\n \r\n <!-- Flecha expandir/colapsar (si tiene hijos) -->\r\n @if (node.children && node.children.length > 0) {\r\n <span class=\"chevron-icon\" (click)=\"toggleExpand(node, $event)\">\r\n {{ node.expanded ? '\uD83D\uDF83' : '\uD83D\uDF82' }}\r\n </span>\r\n } @else {\r\n <span class=\"chevron-spacer\"></span>\r\n }\r\n\r\n <!-- Radio Button (Selecci\u00F3n simple) -->\r\n <div class=\"radio-circle\" [class.checked]=\"selectedId() === node.id\">\r\n <div class=\"radio-inner\"></div>\r\n </div>\r\n\r\n <!-- Etiqueta del Nodo -->\r\n <span class=\"node-label\">{{ node.label }}</span>\r\n </div>\r\n\r\n <!-- Renderizado de hijos si est\u00E1 expandido -->\r\n @if (node.children && node.children.length > 0 && node.expanded) {\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: node.children, level: level + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;width:100%;max-width:320px;background:#fff}.filter-container{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:4px;background-color:#fff}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#252423}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;cursor:pointer;font-size:12px;color:#605e5c;padding:2px 4px;border-radius:2px}.icon-btn:hover{background-color:#f3f2f1}.tree-scroll-container{max-height:220px;overflow-y:auto;padding:4px 0}.tree-level{display:flex;flex-direction:column}.tree-node-row{display:flex;align-items:center;height:28px;cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px;transition:background-color .1s ease}.tree-node-row:hover{background-color:#f3f2f1}.tree-node-row.selected{background-color:#e1dfdd}.chevron-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:#323130}.chevron-spacer{width:16px}.radio-circle{width:14px;height:14px;border-radius:50%;border:1.5px solid #605e5c;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:#fff}.radio-circle.checked{border-color:#0078d4}.radio-circle.checked .radio-inner{width:6px;height:6px;border-radius:50%;background-color:#0078d4}.node-label{font-size:13px;color:#323130;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-scroll-container::-webkit-scrollbar{width:6px}.tree-scroll-container::-webkit-scrollbar-track{background:#f1f1f1}.tree-scroll-container::-webkit-scrollbar-thumb{background:#8a8886;border-radius:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
3382
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3383
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: BubbleChartComponent, isStandalone: true, selector: "yw-bubble-chart", inputs: { chartData: "chartData", config: "config", idComponent: "idComponent" }, usesOnChanges: true, ngImport: i0, template: "@if(config.provider==='syncfusion'){\r\n <div style=\"position: relative; width: 100%; height: 100%;\">\r\n <yw-bubble-chart-syncfusion \r\n [idComponent]=\"idComponent\"\r\n [chartData]=\"chartData\" \r\n [config]=\"config\" style=\"display: block; width: 100%; height: 100%;\">\r\n </yw-bubble-chart-syncfusion>\r\n</div>\r\n}", styles: [":host{display:block;width:100%;height:100%;min-height:260px;min-width:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BubbleChartSyncfusionComponent, selector: "yw-bubble-chart-syncfusion", inputs: ["chartData", "config", "idComponent"] }] }); }
3372
3384
  }
3373
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwListSlicerComponent, decorators: [{
3385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartComponent, decorators: [{
3374
3386
  type: Component,
3375
- args: [{ selector: 'yw-list-slicer', standalone: true, imports: [CommonModule], host: {
3376
- '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3377
- }, template: "<div class=\"filter-container\">\r\n <!-- Cabecera con t\u00EDtulo y acciones de filtro -->\r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\">\r\n <!--<button class=\"icon-btn\" title=\"Filtro\">\uD83D\uDD3B</button>-->\r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" title=\"{{clearTitleLabel}}\">\uD83E\uDDF9</button>\r\n <!--<button class=\"icon-btn\" title=\"M\u00E1s opciones\">\u22EE</button>-->\r\n </div>\r\n </div>\r\n\r\n <!-- Vista en \u00C1rbol con scroll interno -->\r\n <div class=\"tree-scroll-container\">\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: treeNodes(), level: 0 }\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n<!-- Plantilla Recursiva para renderizar niveles del \u00C1rbol -->\r\n<ng-template #nodeListTemplate let-nodes let-level=\"level\">\r\n <div class=\"tree-level\">\r\n @for (node of nodes; track node.id) {\r\n <div class=\"tree-node-wrapper\">\r\n <!-- Fila de opci\u00F3n -->\r\n <div \r\n class=\"tree-node-row\" \r\n [class.selected]=\"selectedId() === node.id\"\r\n [style.padding-left.px]=\"level * 18 + 6\"\r\n (click)=\"selectNode(node, $event)\">\r\n \r\n <!-- Flecha expandir/colapsar (si tiene hijos) -->\r\n @if (node.children && node.children.length > 0) {\r\n <span class=\"chevron-icon\" (click)=\"toggleExpand(node, $event)\">\r\n {{ node.expanded ? '\uD83D\uDF83' : '\uD83D\uDF82' }}\r\n </span>\r\n } @else {\r\n <span class=\"chevron-spacer\"></span>\r\n }\r\n\r\n <!-- Radio Button (Selecci\u00F3n simple) -->\r\n <div class=\"radio-circle\" [class.checked]=\"selectedId() === node.id\">\r\n <div class=\"radio-inner\"></div>\r\n </div>\r\n\r\n <!-- Etiqueta del Nodo -->\r\n <span class=\"node-label\">{{ node.label }}</span>\r\n </div>\r\n\r\n <!-- Renderizado de hijos si est\u00E1 expandido -->\r\n @if (node.children && node.children.length > 0 && node.expanded) {\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: node.children, level: level + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;width:100%;max-width:320px;background:#fff}.filter-container{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:4px;background-color:#fff}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#252423}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;cursor:pointer;font-size:12px;color:#605e5c;padding:2px 4px;border-radius:2px}.icon-btn:hover{background-color:#f3f2f1}.tree-scroll-container{max-height:220px;overflow-y:auto;padding:4px 0}.tree-level{display:flex;flex-direction:column}.tree-node-row{display:flex;align-items:center;height:28px;cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px;transition:background-color .1s ease}.tree-node-row:hover{background-color:#f3f2f1}.tree-node-row.selected{background-color:#e1dfdd}.chevron-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:#323130}.chevron-spacer{width:16px}.radio-circle{width:14px;height:14px;border-radius:50%;border:1.5px solid #605e5c;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:#fff}.radio-circle.checked{border-color:#0078d4}.radio-circle.checked .radio-inner{width:6px;height:6px;border-radius:50%;background-color:#0078d4}.node-label{font-size:13px;color:#323130;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-scroll-container::-webkit-scrollbar{width:6px}.tree-scroll-container::-webkit-scrollbar-track{background:#f1f1f1}.tree-scroll-container::-webkit-scrollbar-thumb{background:#8a8886;border-radius:3px}\n"] }]
3378
- }], ctorParameters: () => [], propDecorators: { idComponent: [{
3379
- type: Input
3380
- }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], clearTitleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearTitleLabel", required: false }] }], rawData: [{ type: i0.Input, args: [{ isSignal: true, alias: "rawData", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateHierarchyType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateHierarchyType", required: false }] }], monthNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthNames", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], filterValueChange: [{ type: i0.Output, args: ["filterValueChange"] }], currentSelectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSelectedId", required: false }] }] } });
3387
+ args: [{ selector: 'yw-bubble-chart', standalone: true, imports: [CommonModule, BubbleChartSyncfusionComponent], template: "@if(config.provider==='syncfusion'){\r\n <div style=\"position: relative; width: 100%; height: 100%;\">\r\n <yw-bubble-chart-syncfusion \r\n [idComponent]=\"idComponent\"\r\n [chartData]=\"chartData\" \r\n [config]=\"config\" style=\"display: block; width: 100%; height: 100%;\">\r\n </yw-bubble-chart-syncfusion>\r\n</div>\r\n}", styles: [":host{display:block;width:100%;height:100%;min-height:260px;min-width:0;overflow:hidden}\n"] }]
3388
+ }], propDecorators: { chartData: [{
3389
+ type: Input,
3390
+ args: ['chartData']
3391
+ }], config: [{
3392
+ type: Input,
3393
+ args: ['config']
3394
+ }], idComponent: [{
3395
+ type: Input,
3396
+ args: ['idComponent']
3397
+ }] } });
3381
3398
 
3382
- class YwDashboardFilterWidgetComponent {
3399
+ /*BEGIN - COMPONENTES VALIDOS PARA WIDGET*/
3400
+ class YwDashboardWidgetComponent {
3383
3401
  constructor() {
3384
3402
  this.componentWidgetId = '';
3385
3403
  this.typeComponent = '';
3386
3404
  this.varShowConfigButtons = false;
3405
+ this.styleWidget = input(DEFAULT_WIDGET_STYLE, ...(ngDevMode ? [{ debugName: "styleWidget" }] : []));
3406
+ // Signal calculada que combina los valores recibidos con los valores por defecto
3407
+ this.instanceStyleWidget = computed(() => ({
3408
+ widgetBackgroundColor: this.styleWidget()?.widgetBackgroundColor ?? DEFAULT_WIDGET_STYLE.widgetBackgroundColor,
3409
+ widgetBorderColor: this.styleWidget()?.widgetBorderColor ?? DEFAULT_WIDGET_STYLE.widgetBorderColor
3410
+ }), ...(ngDevMode ? [{ debugName: "instanceStyleWidget" }] : []));
3387
3411
  this.configWidget = {
3388
3412
  widgetId: '',
3389
- label: '',
3413
+ title: '',
3390
3414
  typeComponent: '',
3391
- controlTable: '',
3415
+ showConfigButtons: false,
3416
+ widgetStyle: DEFAULT_WIDGET_STYLE,
3417
+ layoutConfig: { id: '', w: 0, h: 0, content: undefined },
3418
+ controlConfig: {},
3419
+ controlTables: []
3392
3420
  };
3393
- this.controlConfig = input(...(ngDevMode ? [undefined, { debugName: "controlConfig" }] : []));
3394
- this.controlData = [];
3421
+ this.controlConfig = {};
3422
+ this.controlData = {};
3423
+ this.isLocked = model(false, ...(ngDevMode ? [{ debugName: "isLocked" }] : []));
3424
+ this.isMaximized = signal(false, ...(ngDevMode ? [{ debugName: "isMaximized" }] : []));
3395
3425
  this.eventDeleteRequest = output();
3426
+ this.eventLockToggleRequest = output();
3427
+ this.eventMaximizeToggleRequest = output();
3396
3428
  this.eventShowConfigFormRequest = output();
3397
- this.selectionChange = output();
3398
- effect(() => {
3399
- const value_controlConfig = this.fnFormatConfigData();
3400
- this.dataWidget = { idComponent: this.componentWidgetId,
3401
- configWidget: this.configWidget,
3402
- controlConfig: value_controlConfig
3403
- };
3404
- });
3405
3429
  }
3406
3430
  ngOnInit() {
3407
- this.componentWidgetId = this.configWidget.widgetId;
3431
+ this.componentWidgetId = 'cmpnt-' + this.configWidget.widgetId;
3408
3432
  this.typeComponent = this.configWidget.typeComponent;
3409
- const value_controlConfig = this.fnFormatConfigData();
3410
3433
  this.dataWidget = { idComponent: this.componentWidgetId,
3411
- configWidget: this.configWidget,
3412
- controlConfig: value_controlConfig
3434
+ controlConfig: this.controlConfig,
3435
+ controlData: this.controlData
3413
3436
  };
3437
+ // console.log('DATOS INICIALES INIT:');
3438
+ // console.log(this.dataWidget);
3414
3439
  }
3415
- /*
3416
- Los Datos a este componente llegan a un nivel basico, sin embargo es necesario configurar la informacion, para que se adapte a los componentes.
3417
- */
3418
- fnFormatConfigData() {
3419
- let responsedata = {};
3420
- const typeComponent = this.configWidget.typeComponent;
3421
- if (typeComponent == 'filter-slicer') {
3422
- const dataType = this.controlConfig().dataType;
3423
- const currentData = this.controlConfig();
3424
- if (dataType == 'date') {
3425
- const fieldName = this.controlConfig().filterField;
3426
- const fechas = this.controlData.map((d) => new Date(d[fieldName]).getTime());
3427
- const val_min = new Date(Math.min(...fechas)).toISOString().split("T")[0];
3428
- const val_max = new Date(Math.max(...fechas)).toISOString().split("T")[0];
3429
- responsedata = { dataType: dataType, min: val_min, max: val_max, minCurrent: currentData?.minCurrent, maxCurrent: currentData?.maxCurrent };
3430
- }
3431
- if (dataType == 'number') {
3432
- const fieldName = this.controlConfig().filterField;
3433
- const valStep = this.controlConfig().step;
3434
- const DataNumbers = this.controlData.map((d) => d[fieldName]);
3435
- const val_min = Math.min(...DataNumbers);
3436
- const val_max = Math.max(...DataNumbers);
3437
- responsedata = { dataType: dataType, min: val_min, max: val_max, step: valStep, minCurrent: currentData?.minCurrent, maxCurrent: currentData?.maxCurrent };
3438
- }
3440
+ ngAfterViewInit() {
3441
+ this.varShowConfigButtons = this.configWidget.showConfigButtons || false;
3442
+ }
3443
+ ngOnChanges(changes) {
3444
+ if (changes['configWidget']) {
3445
+ //console.log('Nuevo valor configWidget:', this.configWidget);
3446
+ this.varShowConfigButtons = this.configWidget.showConfigButtons || false;
3447
+ ;
3439
3448
  }
3440
- if (typeComponent == 'filter-button') {
3441
- const fieldName = this.controlConfig().filterField;
3442
- const fieldNameId = this.controlConfig().filterFieldId;
3443
- const val_allowMultiple = this.controlConfig().allowMultiple;
3444
- const currentData = this.controlConfig();
3445
- let listoptions = this.controlData.map((item) => { return { 'id': item[fieldNameId], 'label': item[fieldName] }; });
3446
- const listoptionsunicos = [...new Map(listoptions.map(d => [d.id, d])).values()];
3447
- responsedata = { options: listoptionsunicos, allowMultiple: val_allowMultiple, currentIds: currentData?.currentIds };
3449
+ if (changes['controlConfig']) {
3450
+ // console.log('Nuevo valor controlConfig:', this.controlConfig);
3448
3451
  }
3449
- if (typeComponent == 'filter-list') {
3450
- const dataType = this.controlConfig().dataType;
3451
- const currentData = this.controlConfig();
3452
- if (dataType == 'date') {
3453
- const fieldName = this.controlConfig().filterField;
3454
- const val_dateHierarchyType = this.controlConfig().dateHierarchyType;
3455
- const fechas = this.controlData.map((d) => new Date(d[fieldName]).getTime());
3456
- const val_min = new Date(Math.min(...fechas)).toISOString().split("T")[0];
3457
- const val_max = new Date(Math.max(...fechas)).toISOString().split("T")[0];
3458
- responsedata = { dataType: dataType, minDate: val_min, maxDate: val_max, dateHierarchyType: val_dateHierarchyType, currentSelectedId: currentData.currentSelectedId };
3459
- }
3460
- if (dataType == 'text') {
3461
- const fieldName1 = this.controlConfig().filterField;
3462
- const fieldName2 = this.controlConfig().filterFieldN2;
3463
- const fieldName3 = this.controlConfig().filterFieldN3;
3464
- let foundN2 = false;
3465
- let foundN3 = false;
3466
- let lsizeN2 = 0;
3467
- let lsizeN3 = 0;
3468
- let nodebase = { id: '', label: '' };
3469
- let nodeN2 = { id: '', label: '' };
3470
- let nodeN3 = { id: '', label: '' };
3471
- let listNivel1 = [];
3472
- let listNivel2 = [];
3473
- let listNivel3 = [];
3474
- this.controlData.forEach((item) => {
3475
- nodebase = { id: item[fieldName1], label: item[fieldName1] };
3476
- //NIVEL 2
3477
- if (fieldName2) {
3478
- foundN2 = false;
3479
- lsizeN2 = Object.keys(listNivel2).length;
3480
- for (let i = 0; i < lsizeN2; i++) {
3481
- const itemN2 = listNivel2[i];
3482
- if (itemN2.id == item[fieldName2]) {
3483
- itemN2.children.push(nodebase);
3484
- nodeN2 = itemN2;
3485
- foundN2 = true;
3486
- break;
3487
- }
3488
- }
3489
- ;
3490
- if (foundN2 == false) {
3491
- nodeN2 = { id: item[fieldName2], label: item[fieldName2], expanded: true, children: [nodebase] };
3492
- if (fieldName3) {
3493
- nodeN2.parentId = item[fieldName3];
3494
- }
3495
- listNivel2.push(nodeN2);
3496
- }
3497
- }
3498
- else {
3499
- listNivel1.push(nodebase);
3500
- }
3501
- });
3502
- //NIVEL 1 - Basico no hay Jerarquia
3503
- responsedata = { dataType: dataType, rawData: listNivel1, currentSelectedId: currentData.currentSelectedId };
3504
- //NIVEL 2 - Jerarquia de 2 niveles
3505
- if (fieldName2) {
3506
- responsedata = { dataType: dataType, rawData: listNivel2, currentSelectedId: currentData.currentSelectedId };
3507
- }
3508
- //NIVEL 3 - Jerarquia de 3 niveles
3509
- if (fieldName3) {
3510
- listNivel2.forEach((item) => {
3511
- nodebase = item;
3512
- foundN3 = false;
3513
- lsizeN3 = Object.keys(listNivel3).length;
3514
- for (let i = 0; i < lsizeN3; i++) {
3515
- const itemN3 = listNivel3[i];
3516
- if (itemN3.id == item.parentId) {
3517
- itemN3.children.push(nodebase);
3518
- foundN3 = true;
3519
- break;
3520
- }
3521
- }
3522
- ;
3523
- if (foundN3 == false) {
3524
- nodeN3 = { id: item[fieldName3], label: item[fieldName3], expanded: true, children: [nodebase] };
3525
- listNivel3.push(nodeN3);
3526
- }
3527
- });
3528
- responsedata = { dataType: dataType, rawData: listNivel3, currentSelectedId: currentData.currentSelectedId };
3529
- }
3530
- }
3452
+ if (changes['controlData']) {
3453
+ //console.log('Nuevo valor controlData:', this.controlData);
3454
+ this.dataWidget = { idComponent: this.componentWidgetId,
3455
+ controlConfig: this.controlConfig,
3456
+ controlData: this.controlData
3457
+ };
3531
3458
  }
3532
- return responsedata;
3533
- }
3534
- //Filtro Slicer
3535
- onFilterSlicerChange(range) {
3536
- console.log('Filtro actualizado:', range);
3537
- this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: range });
3538
- }
3539
- //Filtro Button
3540
- onFilterButtonChange(selectedIds) {
3541
- console.log('Tipos seleccionados:', selectedIds);
3542
- this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: selectedIds });
3543
3459
  }
3544
- //Filtro Lista - 1
3545
- onFilterListChange(selectedData) {
3546
- console.log('Tipos seleccionados:', selectedData);
3547
- // Filtrar la información del dashboard
3548
- //this.selectionChange.emit({widgetId:this.componentWidgetId,eventResponse:selectedData});
3460
+ /* BEGIN - BARRA DE EVENTOS DEL WIDGET */
3461
+ //Eliminacion de Widget - Conectado al Dashboard
3462
+ onDeleteClick() {
3463
+ this.eventDeleteRequest.emit(this.configWidget.widgetId);
3549
3464
  }
3550
- //Filtro Lista - 2
3551
- onFilterListCalculated(data) {
3552
- if (!data) {
3553
- this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: null });
3554
- return;
3555
- }
3556
- if (data.type === 'DATE_RANGE') {
3557
- //console.log('Rango a filtrar en SQL/Dashboard:', data.dateRange?.minDate, 'hasta', data.dateRange?.maxDate);
3558
- this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: { minDate: data.dateRange?.minDate, maxDate: data.dateRange?.maxDate, currentNodeId: data.currentNodeId } });
3559
- }
3560
- else if (data.type === 'TEXT_LEAVES') {
3561
- //console.log('Lista de elementos terminales seleccionados:', data.leafIds);
3562
- this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: { ids: data.leafIds, currentNodeId: data.currentNodeId } });
3563
- }
3465
+ onLockClick() {
3466
+ // Invertimos el estado local y notificamos al padre
3467
+ const nextState = !this.isLocked();
3468
+ this.isLocked.set(nextState);
3469
+ this.eventLockToggleRequest.emit({ widgetId: this.configWidget.widgetId, shouldLock: nextState });
3564
3470
  }
3565
- onDeleteClick() {
3471
+ onMaximizeClick() {
3472
+ const nextState = !this.isMaximized();
3473
+ this.isMaximized.set(nextState);
3474
+ this.eventMaximizeToggleRequest.emit({ widgetId: this.configWidget.widgetId, shouldMaximize: nextState });
3566
3475
  }
3567
3476
  onShowFormConfigClick() {
3477
+ this.eventShowConfigFormRequest.emit(this.configWidget.widgetId);
3568
3478
  }
3569
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3570
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardFilterWidgetComponent, isStandalone: true, selector: "yw-dashboard-filter-widget", inputs: { configWidget: { classPropertyName: "configWidget", publicName: "configWidget", isSignal: false, isRequired: false, transformFunction: null }, controlConfig: { classPropertyName: "controlConfig", publicName: "controlConfig", isSignal: true, isRequired: false, transformFunction: null }, controlData: { classPropertyName: "controlData", publicName: "controlData", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { eventDeleteRequest: "eventDeleteRequest", eventShowConfigFormRequest: "eventShowConfigFormRequest", selectionChange: "selectionChange" }, ngImport: i0, template: "\r\n<div class=\"widget-filter-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div>\r\n<div class=\"widget-filter-content-wrapper\">\r\n @if ( typeComponent == 'empty-visual' ) { \r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-slicer' ) { \r\n <ng-container *ngTemplateOutlet=\"filterslicer; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-button' ) { \r\n <ng-container *ngTemplateOutlet=\"filterbutton; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-list' ) { \r\n <ng-container *ngTemplateOutlet=\"filterlist; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER SLICER TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterslicer let-control = \"control\"> \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\" \r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\" \r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n @if (control.controlConfig.dataType === 'number') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\"\r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\"\r\n [step]=\"control.controlConfig.step\"\r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER BUTTON TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterbutton let-control = \"control\"> \r\n <yw-button-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [options]=\"control.controlConfig.options\"\r\n [allowMultiple]=\"control.controlConfig.allowMultiple\"\r\n [currentIds]=\"control.controlConfig.currentIds\"\r\n (selectionChange)=\"onFilterButtonChange($event)\" \r\n >\r\n </yw-button-slicer>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER LIST TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterlist let-control = \"control\"> \r\n \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [minDate]=\"control.controlConfig.minDate\"\r\n [maxDate]=\"control.controlConfig.maxDate\"\r\n [dateHierarchyType]=\"control.controlConfig.dateHierarchyType\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n @if (control.controlConfig.dataType === 'text') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\"\r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [rawData]=\"control.controlConfig.rawData\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #040404);border-radius:var(--widget-border-radius, 8px);padding:var(--widget-padding, 10px)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-filter-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-filter-content-wrapper{width:100%;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: YwEmptyVisualComponent, selector: "yw-empty-visual", inputs: ["idComponent", "config"] }, { kind: "component", type: YwBaseSlicerComponent, selector: "yw-base-slicer", inputs: ["idComponent", "dataType", "label", "min", "max", "step", "minCurrent", "maxCurrent"], outputs: ["rangeChange"] }, { kind: "component", type: YwButtonSlicerComponent, selector: "yw-button-slicer", inputs: ["idComponent", "label", "options", "allowMultiple", "currentIds"], outputs: ["selectionChange"] }, { kind: "component", type: YwListSlicerComponent, selector: "yw-list-slicer", inputs: ["idComponent", "label", "clearTitleLabel", "rawData", "dataType", "minDate", "maxDate", "dateHierarchyType", "monthNames", "currentSelectedId"], outputs: ["selectionChange", "filterValueChange"] }] }); }
3479
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3480
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardWidgetComponent, isStandalone: true, selector: "yw-dashboard-widget", inputs: { styleWidget: { classPropertyName: "styleWidget", publicName: "styleWidget", isSignal: true, isRequired: false, transformFunction: null }, configWidget: { classPropertyName: "configWidget", publicName: "configWidget", isSignal: false, isRequired: false, transformFunction: null }, controlConfig: { classPropertyName: "controlConfig", publicName: "controlConfig", isSignal: false, isRequired: false, transformFunction: null }, controlData: { classPropertyName: "controlData", publicName: "controlData", isSignal: false, isRequired: false, transformFunction: null }, isLocked: { classPropertyName: "isLocked", publicName: "isLocked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isLocked: "isLockedChange", eventDeleteRequest: "eventDeleteRequest", eventLockToggleRequest: "eventLockToggleRequest", eventMaximizeToggleRequest: "eventMaximizeToggleRequest", eventShowConfigFormRequest: "eventShowConfigFormRequest" }, host: { properties: { "style.--widget-bg": "instanceStyleWidget().widgetBackgroundColor", "style.--widget-border-color": "instanceStyleWidget().widgetBorderColor" } }, usesOnChanges: true, ngImport: i0, template: "\r\n<!-- <div class=\"widget-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\">{{ isLocked() ? '\uD83D\uDD12' : '\uD83D\uDD13' }}</button>\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\">{{ isMaximized() ? '\uD83D\uDDD7' : '\uD83D\uDDD6' }}</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div> -->\r\n\r\n<div class=\"widget-action-bar\">\r\n <!-- Bot\u00F3n Bloquear / Desbloquear -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\" [title]=\"isLocked() ? 'Desbloquear' : 'Bloquear'\">\r\n <svg *ngIf=\"isLocked(); else unlockedIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\r\n <ng-template #unlockedIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Maximizar / Restaurar -->\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\" [title]=\"isMaximized() ? 'Restaurar' : 'Maximizar'\">\r\n <svg *ngIf=\"isMaximized(); else maxIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\"></path></svg>\r\n <ng-template #maxIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Eliminar -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\" title=\"Eliminar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Configuraci\u00F3n -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\" title=\"Configurar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg>\r\n </button>\r\n</div>\r\n\r\n<div class=\"widget-content-wrapper\">\r\n @if ( typeComponent == 'dummy' ) {\r\n <ng-container *ngTemplateOutlet=\"testdummy; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'empty-visual' ) {\r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-bar' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbar; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-line' ) {\r\n <ng-container *ngTemplateOutlet=\"chartline; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-doughnut' ) {\r\n <ng-container *ngTemplateOutlet=\"chartdoughnut; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-gauge' ) {\r\n <ng-container *ngTemplateOutlet=\"chartgauge; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-bubble' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbubble; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- DUMMY TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #testdummy let-control = \"control\">\r\n <lib-test-chart [idComponent]=\"control.idComponent\" > \r\n </lib-test-chart>\r\n</ng-template>\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BAR CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbar let-control = \"control\">\r\n <yw-bar-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-bar-chart>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartline let-control = \"control\">\r\n <yw-line-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-line-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE DOUGHNUT TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartdoughnut let-control = \"control\">\r\n <yw-pie-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-pie-chart>\r\n</ng-template>\r\n\r\n \r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE GAUGE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartgauge let-control = \"control\">\r\n <yw-gauge-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-gauge-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BUBBLE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbubble let-control=\"control\">\r\n \r\n <yw-bubble-chart \r\n [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\">\r\n </yw-bubble-chart>\r\n</ng-template> ", styles: ["@charset \"UTF-8\";:host{display:block;flex-direction:column;width:100%;overflow:hidden;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #007bff)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-content-wrapper{width:100%;flex-grow:1;height:0;display:flex;flex-direction:column}.widget-action-bar button,.widget-action-bar .btn-action,.widget-action-bar .btn-delete,.widget-action-bar .btn-config{background:transparent;border:1px solid #d9d9d9;border-radius:4px;cursor:pointer;width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;color:#595959;padding:0;transition:all .2s ease}.widget-action-bar button svg,.widget-action-bar .btn-action svg,.widget-action-bar .btn-delete svg,.widget-action-bar .btn-config svg{width:14px;height:14px}.widget-action-bar button:hover,.widget-action-bar .btn-action:hover,.widget-action-bar .btn-delete:hover,.widget-action-bar .btn-config:hover{background-color:#f5f5f5;color:#262626;border-color:#bfbfbf}.widget-action-bar button:active,.widget-action-bar .btn-action:active,.widget-action-bar .btn-delete:active,.widget-action-bar .btn-config:active{background-color:#e6e6e6}.widget-action-bar .btn-delete:hover{background-color:#fff1f0;color:#ff4d4f;border-color:#ffa39e}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TestChartComponent, selector: "lib-test-chart", inputs: ["idComponent"] }, { kind: "component", type: YwEmptyVisualComponent, selector: "yw-empty-visual", inputs: ["idComponent", "config"] }, { kind: "component", type: LineChartComponent, selector: "yw-line-chart", inputs: ["chartData", "config", "idComponent"] }, { kind: "component", type: BarChartComponent, selector: "yw-bar-chart", inputs: ["chartData", "config", "idComponent"] }, { kind: "component", type: PieChartComponent, selector: "yw-pie-chart", inputs: ["idComponent", "chartData", "config"] }, { kind: "component", type: GaugeChartComponent, selector: "yw-gauge-chart", inputs: ["idComponent", "chartData", "config"] }, { kind: "component", type: BubbleChartComponent, selector: "yw-bubble-chart", inputs: ["chartData", "config", "idComponent"] }] }); }
3571
3481
  }
3572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterWidgetComponent, decorators: [{
3482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardWidgetComponent, decorators: [{
3573
3483
  type: Component,
3574
- args: [{ selector: 'yw-dashboard-filter-widget', standalone: true, imports: [CommonModule,
3484
+ args: [{ selector: 'yw-dashboard-widget', standalone: true, imports: [CommonModule,
3485
+ TestChartComponent,
3575
3486
  YwEmptyVisualComponent,
3576
- YwBaseSlicerComponent,
3577
- YwButtonSlicerComponent,
3578
- YwListSlicerComponent,
3579
- ], template: "\r\n<div class=\"widget-filter-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div>\r\n<div class=\"widget-filter-content-wrapper\">\r\n @if ( typeComponent == 'empty-visual' ) { \r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-slicer' ) { \r\n <ng-container *ngTemplateOutlet=\"filterslicer; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-button' ) { \r\n <ng-container *ngTemplateOutlet=\"filterbutton; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-list' ) { \r\n <ng-container *ngTemplateOutlet=\"filterlist; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER SLICER TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterslicer let-control = \"control\"> \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\" \r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\" \r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n @if (control.controlConfig.dataType === 'number') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\"\r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\"\r\n [step]=\"control.controlConfig.step\"\r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER BUTTON TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterbutton let-control = \"control\"> \r\n <yw-button-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [options]=\"control.controlConfig.options\"\r\n [allowMultiple]=\"control.controlConfig.allowMultiple\"\r\n [currentIds]=\"control.controlConfig.currentIds\"\r\n (selectionChange)=\"onFilterButtonChange($event)\" \r\n >\r\n </yw-button-slicer>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER LIST TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterlist let-control = \"control\"> \r\n \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [minDate]=\"control.controlConfig.minDate\"\r\n [maxDate]=\"control.controlConfig.maxDate\"\r\n [dateHierarchyType]=\"control.controlConfig.dateHierarchyType\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n @if (control.controlConfig.dataType === 'text') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\"\r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [rawData]=\"control.controlConfig.rawData\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #040404);border-radius:var(--widget-border-radius, 8px);padding:var(--widget-padding, 10px)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-filter-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-filter-content-wrapper{width:100%;display:flex;flex-direction:column}\n"] }]
3580
- }], ctorParameters: () => [], propDecorators: { configWidget: [{
3487
+ LineChartComponent,
3488
+ BarChartComponent,
3489
+ PieChartComponent,
3490
+ GaugeChartComponent, BubbleChartComponent], host: {
3491
+ '[style.--widget-bg]': 'instanceStyleWidget().widgetBackgroundColor',
3492
+ '[style.--widget-border-color]': 'instanceStyleWidget().widgetBorderColor'
3493
+ }, template: "\r\n<!-- <div class=\"widget-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\">{{ isLocked() ? '\uD83D\uDD12' : '\uD83D\uDD13' }}</button>\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\">{{ isMaximized() ? '\uD83D\uDDD7' : '\uD83D\uDDD6' }}</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div> -->\r\n\r\n<div class=\"widget-action-bar\">\r\n <!-- Bot\u00F3n Bloquear / Desbloquear -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-action\" (click)=\"onLockClick()\" [title]=\"isLocked() ? 'Desbloquear' : 'Bloquear'\">\r\n <svg *ngIf=\"isLocked(); else unlockedIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\r\n <ng-template #unlockedIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Maximizar / Restaurar -->\r\n <button class=\"btn-action\" (click)=\"onMaximizeClick()\" [title]=\"isMaximized() ? 'Restaurar' : 'Maximizar'\">\r\n <svg *ngIf=\"isMaximized(); else maxIcon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\"></path></svg>\r\n <ng-template #maxIcon>\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"></path></svg>\r\n </ng-template>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Eliminar -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\" title=\"Eliminar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>\r\n </button>\r\n\r\n <!-- Bot\u00F3n Configuraci\u00F3n -->\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\" title=\"Configurar\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg>\r\n </button>\r\n</div>\r\n\r\n<div class=\"widget-content-wrapper\">\r\n @if ( typeComponent == 'dummy' ) {\r\n <ng-container *ngTemplateOutlet=\"testdummy; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'empty-visual' ) {\r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-bar' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbar; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-line' ) {\r\n <ng-container *ngTemplateOutlet=\"chartline; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'chart-doughnut' ) {\r\n <ng-container *ngTemplateOutlet=\"chartdoughnut; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-gauge' ) {\r\n <ng-container *ngTemplateOutlet=\"chartgauge; context: { control: dataWidget }\"></ng-container>\r\n } \r\n @if ( typeComponent == 'chart-bubble' ) {\r\n <ng-container *ngTemplateOutlet=\"chartbubble; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- DUMMY TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #testdummy let-control = \"control\">\r\n <lib-test-chart [idComponent]=\"control.idComponent\" > \r\n </lib-test-chart>\r\n</ng-template>\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BAR CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbar let-control = \"control\">\r\n <yw-bar-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-bar-chart>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE CHART TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartline let-control = \"control\">\r\n <yw-line-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-line-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE DOUGHNUT TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartdoughnut let-control = \"control\">\r\n <yw-pie-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-pie-chart>\r\n</ng-template>\r\n\r\n \r\n<!--------------------------------------------------------------->\r\n<!---------------------- LINE GAUGE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartgauge let-control = \"control\">\r\n <yw-gauge-chart [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\" \r\n >\r\n </yw-gauge-chart>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- BUBBLE TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #chartbubble let-control=\"control\">\r\n \r\n <yw-bubble-chart \r\n [idComponent]=\"control.idComponent\"\r\n [chartData]=\"control.controlData\"\r\n [config]=\"control.controlConfig\">\r\n </yw-bubble-chart>\r\n</ng-template> ", styles: ["@charset \"UTF-8\";:host{display:block;flex-direction:column;width:100%;overflow:hidden;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #007bff)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-content-wrapper{width:100%;flex-grow:1;height:0;display:flex;flex-direction:column}.widget-action-bar button,.widget-action-bar .btn-action,.widget-action-bar .btn-delete,.widget-action-bar .btn-config{background:transparent;border:1px solid #d9d9d9;border-radius:4px;cursor:pointer;width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;color:#595959;padding:0;transition:all .2s ease}.widget-action-bar button svg,.widget-action-bar .btn-action svg,.widget-action-bar .btn-delete svg,.widget-action-bar .btn-config svg{width:14px;height:14px}.widget-action-bar button:hover,.widget-action-bar .btn-action:hover,.widget-action-bar .btn-delete:hover,.widget-action-bar .btn-config:hover{background-color:#f5f5f5;color:#262626;border-color:#bfbfbf}.widget-action-bar button:active,.widget-action-bar .btn-action:active,.widget-action-bar .btn-delete:active,.widget-action-bar .btn-config:active{background-color:#e6e6e6}.widget-action-bar .btn-delete:hover{background-color:#fff1f0;color:#ff4d4f;border-color:#ffa39e}\n"] }]
3494
+ }], ctorParameters: () => [], propDecorators: { styleWidget: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleWidget", required: false }] }], configWidget: [{
3581
3495
  type: Input
3582
- }], controlConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlConfig", required: false }] }], controlData: [{
3496
+ }], controlConfig: [{
3583
3497
  type: Input
3584
- }], eventDeleteRequest: [{ type: i0.Output, args: ["eventDeleteRequest"] }], eventShowConfigFormRequest: [{ type: i0.Output, args: ["eventShowConfigFormRequest"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
3498
+ }], controlData: [{
3499
+ type: Input
3500
+ }], isLocked: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLocked", required: false }] }, { type: i0.Output, args: ["isLockedChange"] }], eventDeleteRequest: [{ type: i0.Output, args: ["eventDeleteRequest"] }], eventLockToggleRequest: [{ type: i0.Output, args: ["eventLockToggleRequest"] }], eventMaximizeToggleRequest: [{ type: i0.Output, args: ["eventMaximizeToggleRequest"] }], eventShowConfigFormRequest: [{ type: i0.Output, args: ["eventShowConfigFormRequest"] }] } });
3585
3501
 
3586
- class YwDashboardFilterComponent {
3502
+ class YwBaseSlicerComponent {
3587
3503
  constructor() {
3588
- this.dashboardFilterConfig = {
3589
- showConfigButtons: false,
3590
- lockPositionWidgets: false,
3591
- controlListConfig: []
3592
- };
3593
- this.dashboardData = [];
3594
- this.filterSelectionChange = output();
3595
- this.controlListConfig = [];
3596
- }
3597
- ngOnInit() {
3598
- this.controlListConfig = [];
3599
- this.dashboardFilterConfig.controlListConfig.forEach((item) => {
3600
- const tableName = item.controlTable;
3601
- const prmcontrolData = this.fn_getDataForWidgetFilterComponent(tableName, this.dashboardData);
3602
- const prmconfigWidget = { ...item };
3603
- if (item.controlFilterData) {
3604
- item.configComponent = this.fnSetControlFilterCurrentValues(prmconfigWidget);
3605
- }
3606
- const configControl = { configWidget: prmconfigWidget,
3607
- controlData: prmcontrolData,
3608
- controlConfig: item.configComponent
3609
- };
3610
- this.controlListConfig.push(configControl);
3611
- });
3612
- }
3613
- //Filtrar Datos por Componente del Widget
3614
- fn_getDataForWidgetFilterComponent(prmTableName, prmdashboardData) {
3615
- let dataresponse = [];
3616
- const ldsize = prmdashboardData.length;
3617
- prmdashboardData.forEach((curTableRef) => {
3618
- if (prmTableName.localeCompare(curTableRef.tableName) == 0) {
3619
- dataresponse = curTableRef.tableData;
3504
+ // Inputs de configuración del rango de fechas
3505
+ this.idComponent = '';
3506
+ this.dataType = 'date';
3507
+ this.label = input('Fecha', ...(ngDevMode ? [{ debugName: "label" }] : []));
3508
+ this.min = input(...(ngDevMode ? [undefined, { debugName: "min" }] : []));
3509
+ this.max = input(...(ngDevMode ? [undefined, { debugName: "max" }] : []));
3510
+ this.step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
3511
+ this.minCurrent = input(...(ngDevMode ? [undefined, { debugName: "minCurrent" }] : []));
3512
+ this.maxCurrent = input(...(ngDevMode ? [undefined, { debugName: "maxCurrent" }] : []));
3513
+ this.minNumber = 0;
3514
+ this.maxNumber = 1000;
3515
+ this.minDate = '2020-01-01';
3516
+ this.maxDate = '2022-12-31';
3517
+ // Evento de salida
3518
+ this.rangeChange = output();
3519
+ // Signals para las fechas seleccionadas
3520
+ this.startDate = signal('2020-01-01', ...(ngDevMode ? [{ debugName: "startDate" }] : []));
3521
+ this.endDate = signal('2022-09-22', ...(ngDevMode ? [{ debugName: "endDate" }] : []));
3522
+ // Signals para los numeros seleccionadas
3523
+ this.startVal = signal(0, ...(ngDevMode ? [{ debugName: "startVal" }] : []));
3524
+ this.endVal = signal(1000, ...(ngDevMode ? [{ debugName: "endVal" }] : []));
3525
+ this.minTimestamp = computed(() => new Date(this.minDate).getTime(), ...(ngDevMode ? [{ debugName: "minTimestamp" }] : []));
3526
+ this.maxTimestamp = computed(() => new Date(this.maxDate).getTime(), ...(ngDevMode ? [{ debugName: "maxTimestamp" }] : []));
3527
+ this.startTimestamp = computed(() => new Date(this.startDate()).getTime(), ...(ngDevMode ? [{ debugName: "startTimestamp" }] : []));
3528
+ this.endTimestamp = computed(() => new Date(this.endDate()).getTime(), ...(ngDevMode ? [{ debugName: "endTimestamp" }] : []));
3529
+ // Inicializar valores al arrancar
3530
+ effect(() => {
3531
+ if (this.dataType == 'date') {
3532
+ this.startDate.set(this.minCurrent() || this.minDate);
3533
+ this.endDate.set(this.maxCurrent() || this.maxDate);
3620
3534
  }
3621
- });
3622
- return dataresponse;
3623
- }
3624
- onFilterChange(eventData) {
3625
- this.filterSelectionChange.emit({ widgetId: eventData.widgetId, eventResponse: eventData.eventResponse });
3626
- }
3627
- fnSetControlFilterCurrentValues(prmControlConfig) {
3628
- if (prmControlConfig.typeComponent == 'filter-slicer') {
3629
- let curConfigComponent = prmControlConfig.configComponent;
3630
- if (prmControlConfig.configComponent.dataType == 'date') {
3631
- curConfigComponent.minCurrent = prmControlConfig.controlFilterData['startDate'];
3632
- curConfigComponent.maxCurrent = prmControlConfig.controlFilterData['endDate'];
3535
+ if (this.dataType == 'number') {
3536
+ this.startVal.set(this.minCurrent() || this.minNumber);
3537
+ this.endVal.set(this.maxCurrent() || this.maxNumber);
3633
3538
  }
3634
- if (prmControlConfig.configComponent.dataType == 'number') {
3635
- curConfigComponent.minCurrent = prmControlConfig.controlFilterData['minValue'];
3636
- curConfigComponent.maxCurrent = prmControlConfig.controlFilterData['maxValue'];
3539
+ }, { allowSignalWrites: true });
3540
+ // Notificar al padre cada vez que cambien los valores
3541
+ effect(() => {
3542
+ if (this.dataType == 'date') {
3543
+ this.rangeChange.emit({
3544
+ startDate: this.startDate(),
3545
+ endDate: this.endDate()
3546
+ });
3637
3547
  }
3638
- return curConfigComponent;
3639
- }
3640
- if (prmControlConfig.typeComponent == 'filter-button') {
3641
- let curConfigComponent = prmControlConfig.configComponent;
3642
- curConfigComponent.currentIds = prmControlConfig.controlFilterData || [];
3643
- return curConfigComponent;
3644
- }
3645
- if (prmControlConfig.typeComponent == 'filter-list') {
3646
- let curConfigComponent = prmControlConfig.configComponent;
3647
- curConfigComponent.currentSelectedId = prmControlConfig.controlFilterData['currentNodeId'];
3648
- return curConfigComponent;
3649
- }
3650
- }
3651
- handleClearFilter() {
3652
- this.controlListConfig = [];
3653
- this.dashboardFilterConfig.controlListConfig.forEach((item) => {
3654
- const tableName = item.controlTable;
3655
- const prmcontrolData = this.fn_getDataForWidgetFilterComponent(tableName, this.dashboardData);
3656
- const prmconfigWidget = { ...item };
3657
- if (item.controlFilterData) {
3658
- item.configComponent = this.fnSetControlFilterClearValues(prmconfigWidget);
3548
+ if (this.dataType == 'number') {
3549
+ this.rangeChange.emit({
3550
+ minValue: this.startVal(),
3551
+ maxValue: this.endVal()
3552
+ });
3659
3553
  }
3660
- const configControl = { configWidget: prmconfigWidget,
3661
- controlData: prmcontrolData,
3662
- controlConfig: item.configComponent
3663
- };
3664
- this.controlListConfig.push(configControl);
3665
3554
  });
3666
3555
  }
3667
- fnSetControlFilterClearValues(prmControlConfig) {
3668
- if (prmControlConfig.typeComponent == 'filter-slicer') {
3669
- let curConfigComponent = prmControlConfig.configComponent;
3670
- curConfigComponent.minCurrent = null;
3671
- curConfigComponent.maxCurrent = null;
3672
- return curConfigComponent;
3673
- }
3674
- if (prmControlConfig.typeComponent == 'filter-button') {
3675
- let curConfigComponent = prmControlConfig.configComponent;
3676
- curConfigComponent.currentIds = [];
3677
- return curConfigComponent;
3556
+ ngOnInit() {
3557
+ if (this.dataType == 'date') {
3558
+ this.minDate = this.min();
3559
+ this.maxDate = this.max();
3560
+ this.minTimestamp = computed(() => new Date(this.minDate).getTime(), ...(ngDevMode ? [{ debugName: "minTimestamp" }] : []));
3561
+ this.maxTimestamp = computed(() => new Date(this.maxDate).getTime(), ...(ngDevMode ? [{ debugName: "maxTimestamp" }] : []));
3562
+ this.startTimestamp = computed(() => new Date(this.startDate()).getTime(), ...(ngDevMode ? [{ debugName: "startTimestamp" }] : []));
3563
+ this.endTimestamp = computed(() => new Date(this.endDate()).getTime(), ...(ngDevMode ? [{ debugName: "endTimestamp" }] : []));
3678
3564
  }
3679
- if (prmControlConfig.typeComponent == 'filter-list') {
3680
- let curConfigComponent = prmControlConfig.configComponent;
3681
- curConfigComponent.currentSelectedId = null;
3682
- return curConfigComponent;
3565
+ if (this.dataType == 'number') {
3566
+ this.minNumber = this.min();
3567
+ this.maxNumber = this.max();
3683
3568
  }
3684
3569
  }
3685
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3686
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardFilterComponent, isStandalone: true, selector: "yw-dashboard-filter", inputs: { dashboardFilterConfig: "dashboardFilterConfig", dashboardData: "dashboardData" }, outputs: { filterSelectionChange: "filterSelectionChange" }, ngImport: i0, template: "\r\n <div class=\"dashboard-filter-content-bar\">\r\n @if ( dashboardFilterConfig.showConfigButtons ) { \r\n <button nz-button nzType=\"primary\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n }\r\n <button nz-button \r\n nzType=\"default\" \r\n nzShape=\"circle\" \r\n (click)=\"handleClearFilter()\" \r\n class=\"btn-clean\" \r\n > \r\n <!-- Icono de Borrador (Eraser) activo / relleno --> \r\n <svg \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M16.24 3.56a2.12 2.12 0 0 1 3 0l1.2 1.2a2.12 2.12 0 0 1 0 3l-8.5 8.5H6.5a1.5 1.5 0 0 1-1.5-1.5v-5.44l11.24-11.24zM19 19H5a1 1 0 0 1 0-2h14a1 1 0 0 1 0 2z\"/>\r\n </svg>\r\n \r\n </button>\r\n </div>\r\n\r\n <div class=\"dashboard-filter-content-wrapper\">\r\n @for ( colFilter of controlListConfig; track colFilter) { \r\n <div class=\"dashboard-filter-content-wrapper-item\">\r\n \r\n <yw-dashboard-filter-widget \r\n [configWidget]=\"colFilter.configWidget\"\r\n [controlConfig]=\"colFilter.controlConfig\"\r\n [controlData]=\"colFilter.controlData\"\r\n (selectionChange)=\"onFilterChange($event)\"\r\n > \r\n </yw-dashboard-filter-widget>\r\n\r\n </div>\r\n }\r\n </div>", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.dashboard-filter-content-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%;box-sizing:border-box}.dashboard-filter-content-wrapper{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;width:100%;display:flex;flex-direction:column;box-sizing:border-box}.dashboard-filter-content-wrapper-item{padding-bottom:5px}.btn-clean{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.btn-clean.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.btn-clean.active:hover{background-color:#40a9ff;border-color:#40a9ff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: YwDashboardFilterWidgetComponent, selector: "yw-dashboard-filter-widget", inputs: ["configWidget", "controlConfig", "controlData"], outputs: ["eventDeleteRequest", "eventShowConfigFormRequest", "selectionChange"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i5.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i6.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i7.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }] }); }
3570
+ // Handlers para la entrada manual de fechas
3571
+ onStartDateInput(value) {
3572
+ if (value && value <= this.endDate()) {
3573
+ this.startDate.set(value);
3574
+ }
3575
+ }
3576
+ onEndDateInput(value) {
3577
+ if (value && value >= this.startDate()) {
3578
+ this.endDate.set(value);
3579
+ }
3580
+ }
3581
+ // Métodos para cambiar desde el Input Numérico
3582
+ onStartInput(event) {
3583
+ const value = Number(event.target.value);
3584
+ if (!isNaN(value) && value <= this.endVal() && value >= this.min()) {
3585
+ this.startVal.set(value);
3586
+ }
3587
+ }
3588
+ onEndInput(event) {
3589
+ const value = Number(event.target.value);
3590
+ if (!isNaN(value) && value >= this.startVal() && value <= this.max()) {
3591
+ this.endVal.set(value);
3592
+ }
3593
+ }
3594
+ // Handlers para el movimiento del slider
3595
+ onStartSliderChange(event) {
3596
+ if (this.dataType == 'date') {
3597
+ const val = Number(event.target.value);
3598
+ const dateStr = new Date(val).toISOString().split('T')[0];
3599
+ if (val < this.endTimestamp()) {
3600
+ this.startDate.set(dateStr);
3601
+ }
3602
+ }
3603
+ if (this.dataType == 'number') {
3604
+ const val = Number(event.target.value);
3605
+ if (val < this.endVal()) {
3606
+ this.startVal.set(val);
3607
+ }
3608
+ }
3609
+ }
3610
+ onEndSliderChange(event) {
3611
+ if (this.dataType == 'date') {
3612
+ const val = Number(event.target.value);
3613
+ const dateStr = new Date(val).toISOString().split('T')[0];
3614
+ if (val > this.startTimestamp()) {
3615
+ this.endDate.set(dateStr);
3616
+ }
3617
+ }
3618
+ if (this.dataType == 'number') {
3619
+ const val = Number(event.target.value);
3620
+ if (val > this.startVal()) {
3621
+ this.endVal.set(val);
3622
+ }
3623
+ }
3624
+ }
3625
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwBaseSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3626
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwBaseSlicerComponent, isStandalone: true, selector: "yw-base-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, minCurrent: { classPropertyName: "minCurrent", publicName: "minCurrent", isSignal: true, isRequired: false, transformFunction: null }, maxCurrent: { classPropertyName: "maxCurrent", publicName: "maxCurrent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n <label class=\"filter-label\">{{ label() }}</label>\r\n\r\n <!-- Inputs de fecha superiores -->\r\n <div class=\"date-inputs-row\">\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"startDate()\"\r\n [min]=\"minDate\"\r\n [max]=\"endDate()\"\r\n (change)=\"onStartDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"startVal()\"\r\n [min]=\"minNumber\"\r\n [max]=\"endVal()\"\r\n [step]=\"step()\"\r\n (input)=\"onStartInput($event)\" \r\n />\r\n } \r\n </div>\r\n\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"endDate()\"\r\n [min]=\"startDate()\"\r\n [max]=\"maxDate\"\r\n (change)=\"onEndDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"endVal()\"\r\n [min]=\"startVal()\"\r\n [max]=\"maxNumber\"\r\n [step]=\"step()\"\r\n (input)=\"onEndInput($event)\" \r\n />\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dual Slider personalizado -->\r\n <div class=\"slider-container\">\r\n <div class=\"slider-track\"></div>\r\n @if (dataType === 'date') { \r\n <!-- Slider Inicio -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"startTimestamp()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider Fin -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"endTimestamp()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n }\r\n\r\n @if (dataType === 'number') { \r\n\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"startVal()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider M\u00E1ximo -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"endVal()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n\r\n }\r\n\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:360px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-label{font-size:13px;font-weight:600;color:#333}.date-inputs-row,.number-inputs-row{display:flex;gap:8px}.input-wrapper input[type=date]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=date]:focus{border-color:#a0aec0}.input-wrapper input[type=number]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;width:90px;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=number]:focus{border-color:#a0aec0}.slider-container{position:relative;width:100%;height:30px;display:flex;align-items:center;margin-top:4px}.slider-track{position:absolute;width:100%;height:2px;background-color:#666;border-radius:1px;z-index:1}.thumb{position:absolute;width:100%;appearance:none;-webkit-appearance:none;background:none;pointer-events:none;outline:none;margin:0;z-index:2}.thumb-right{z-index:3}.thumb::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box;transition:transform .1s ease}.thumb::-webkit-slider-thumb:hover{transform:scale(1.1);border-color:#333}.thumb::-moz-range-thumb{pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box}\n"] }); }
3687
3627
  }
3688
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterComponent, decorators: [{
3628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwBaseSlicerComponent, decorators: [{
3689
3629
  type: Component,
3690
- args: [{ selector: 'yw-dashboard-filter', standalone: true, imports: [CommonModule,
3691
- YwDashboardFilterWidgetComponent,
3692
- NzIconModule,
3693
- NzButtonModule,
3694
- ], template: "\r\n <div class=\"dashboard-filter-content-bar\">\r\n @if ( dashboardFilterConfig.showConfigButtons ) { \r\n <button nz-button nzType=\"primary\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n }\r\n <button nz-button \r\n nzType=\"default\" \r\n nzShape=\"circle\" \r\n (click)=\"handleClearFilter()\" \r\n class=\"btn-clean\" \r\n > \r\n <!-- Icono de Borrador (Eraser) activo / relleno --> \r\n <svg \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M16.24 3.56a2.12 2.12 0 0 1 3 0l1.2 1.2a2.12 2.12 0 0 1 0 3l-8.5 8.5H6.5a1.5 1.5 0 0 1-1.5-1.5v-5.44l11.24-11.24zM19 19H5a1 1 0 0 1 0-2h14a1 1 0 0 1 0 2z\"/>\r\n </svg>\r\n \r\n </button>\r\n </div>\r\n\r\n <div class=\"dashboard-filter-content-wrapper\">\r\n @for ( colFilter of controlListConfig; track colFilter) { \r\n <div class=\"dashboard-filter-content-wrapper-item\">\r\n \r\n <yw-dashboard-filter-widget \r\n [configWidget]=\"colFilter.configWidget\"\r\n [controlConfig]=\"colFilter.controlConfig\"\r\n [controlData]=\"colFilter.controlData\"\r\n (selectionChange)=\"onFilterChange($event)\"\r\n > \r\n </yw-dashboard-filter-widget>\r\n\r\n </div>\r\n }\r\n </div>", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.dashboard-filter-content-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%;box-sizing:border-box}.dashboard-filter-content-wrapper{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;width:100%;display:flex;flex-direction:column;box-sizing:border-box}.dashboard-filter-content-wrapper-item{padding-bottom:5px}.btn-clean{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.btn-clean.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.btn-clean.active:hover{background-color:#40a9ff;border-color:#40a9ff}\n"] }]
3695
- }], ctorParameters: () => [], propDecorators: { dashboardFilterConfig: [{
3630
+ args: [{ selector: 'yw-base-slicer', imports: [], host: {
3631
+ '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3632
+ }, template: "<div class=\"filter-container\">\r\n <label class=\"filter-label\">{{ label() }}</label>\r\n\r\n <!-- Inputs de fecha superiores -->\r\n <div class=\"date-inputs-row\">\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"startDate()\"\r\n [min]=\"minDate\"\r\n [max]=\"endDate()\"\r\n (change)=\"onStartDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"startVal()\"\r\n [min]=\"minNumber\"\r\n [max]=\"endVal()\"\r\n [step]=\"step()\"\r\n (input)=\"onStartInput($event)\" \r\n />\r\n } \r\n </div>\r\n\r\n <div class=\"input-wrapper\">\r\n @if (dataType === 'date') { \r\n <input \r\n type=\"date\" \r\n [value]=\"endDate()\"\r\n [min]=\"startDate()\"\r\n [max]=\"maxDate\"\r\n (change)=\"onEndDateInput($any($event.target).value)\" \r\n />\r\n }\r\n @if (dataType === 'number') { \r\n <input \r\n type=\"number\" \r\n [value]=\"endVal()\"\r\n [min]=\"startVal()\"\r\n [max]=\"maxNumber\"\r\n [step]=\"step()\"\r\n (input)=\"onEndInput($event)\" \r\n />\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dual Slider personalizado -->\r\n <div class=\"slider-container\">\r\n <div class=\"slider-track\"></div>\r\n @if (dataType === 'date') { \r\n <!-- Slider Inicio -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"startTimestamp()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider Fin -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minTimestamp()\" \r\n [max]=\"maxTimestamp()\" \r\n [value]=\"endTimestamp()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n }\r\n\r\n @if (dataType === 'number') { \r\n\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"startVal()\"\r\n (input)=\"onStartSliderChange($event)\"\r\n class=\"thumb thumb-left\"\r\n />\r\n\r\n <!-- Slider M\u00E1ximo -->\r\n <input \r\n type=\"range\" \r\n [min]=\"minNumber\" \r\n [max]=\"maxNumber\" \r\n [step]=\"step()\"\r\n [value]=\"endVal()\"\r\n (input)=\"onEndSliderChange($event)\"\r\n class=\"thumb thumb-right\"\r\n />\r\n\r\n }\r\n\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:360px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-label{font-size:13px;font-weight:600;color:#333}.date-inputs-row,.number-inputs-row{display:flex;gap:8px}.input-wrapper input[type=date]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=date]:focus{border-color:#a0aec0}.input-wrapper input[type=number]{border:1px solid #e2e8f0;border-radius:2px;padding:4px 8px;font-size:13px;color:#333;width:90px;outline:none;background-color:#fff;box-shadow:0 1px 2px #0000000d}.input-wrapper input[type=number]:focus{border-color:#a0aec0}.slider-container{position:relative;width:100%;height:30px;display:flex;align-items:center;margin-top:4px}.slider-track{position:absolute;width:100%;height:2px;background-color:#666;border-radius:1px;z-index:1}.thumb{position:absolute;width:100%;appearance:none;-webkit-appearance:none;background:none;pointer-events:none;outline:none;margin:0;z-index:2}.thumb-right{z-index:3}.thumb::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box;transition:transform .1s ease}.thumb::-webkit-slider-thumb:hover{transform:scale(1.1);border-color:#333}.thumb::-moz-range-thumb{pointer-events:auto;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #666666;cursor:pointer;box-sizing:border-box}\n"] }]
3633
+ }], ctorParameters: () => [], propDecorators: { idComponent: [{
3696
3634
  type: Input
3697
- }], dashboardData: [{
3635
+ }], dataType: [{
3698
3636
  type: Input
3699
- }], filterSelectionChange: [{ type: i0.Output, args: ["filterSelectionChange"] }] } });
3637
+ }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], minCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "minCurrent", required: false }] }], maxCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxCurrent", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }] } });
3700
3638
 
3701
- /* END - FILTROS */
3702
- class YwDashboardComponent {
3703
- /* */
3704
- constructor(environmentInjector, appRef) {
3705
- //Configurar Bloqueo de Widgets
3706
- /*
3639
+ class YwButtonSlicerComponent {
3640
+ constructor() {
3641
+ // Configuración de entradas
3642
+ this.idComponent = '';
3643
+ this.label = input('Tipo de producto', ...(ngDevMode ? [{ debugName: "label" }] : []));
3644
+ this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
3645
+ this.allowMultiple = input(true, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : [])); // Permite cambiar a selección única si es necesario
3646
+ // Evento de salida con la lista de IDs seleccionados
3647
+ this.selectionChange = output();
3648
+ // Signal con los IDs seleccionados
3649
+ this.selectedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedIds" }] : []));
3650
+ // Current IDs seleccionados
3651
+ this.currentIds = input([], ...(ngDevMode ? [{ debugName: "currentIds" }] : []));
3652
+ // Emitir el listado en Array cada vez que la Signal de selección cambie
3707
3653
  effect(() => {
3708
- const isLocked = this.allIsLocked();
3709
- console.log('El estado de bloqueo cambió a:', isLocked);
3710
- this.fn_lockPositionWidgets(isLocked);
3654
+ this.selectionChange.emit(Array.from(this.selectedIds()));
3711
3655
  });
3712
- */
3713
- this.environmentInjector = environmentInjector;
3714
- this.appRef = appRef;
3715
- this.widgetsActivos = new Map();
3716
- this.showControls = input(false, ...(ngDevMode ? [{ debugName: "showControls" }] : []));
3717
- this.showFilter = input(false, ...(ngDevMode ? [{ debugName: "showFilter" }] : []));
3718
- this.allIsLocked = signal(false, ...(ngDevMode ? [{ debugName: "allIsLocked" }] : []));
3719
- this.drawerfiltervisible = false;
3720
- this.drawerconfigvisible = false;
3721
- this.drawerCurrentWidgetObject = {};
3722
- this.isLocked = false;
3723
- this.countWidget = 1;
3724
- this.layoutConfig = {
3725
- margin: 10,
3726
- cellHeight: 100,
3727
- columns: 24
3728
- };
3729
- /* ejemplo de Items
3730
- items: [
3731
- { id: 'div-1', x: 0, y: 0, w: 14, h: 2, content: 'DIV 1' , contentData : {}},
3732
- { id: 'div-2', x: 5, y: 2, w: 19, h: 1, content: 'DIV 2' , contentData : {}},
3733
- { id: 'div-3', x: 0, y: 3, w: 22, h: 1, content: 'DIV 3', contentData : {} }
3734
- ]
3735
- */
3736
- this.dashboardStyle = {
3737
- canvasBackgroundColor: "#f5f5f5",
3738
- widgetBackgroundColor: "#ffffff",
3739
- widgetBorderColor: "#007bff"
3740
- };
3741
- this.dashboardConfig = {
3742
- showConfigButtons: false,
3743
- lockPositionWidgets: false,
3744
- layoutConfig: {
3745
- margin: 0,
3746
- cellHeight: 0,
3747
- columns: 0
3748
- },
3749
- controlListConfig: []
3750
- };
3751
- this.dashboardData = [];
3752
- this.dashboardItems = [];
3753
- /* REF FILTROS */
3754
- this.dashboardFilterConfig = {
3755
- showConfigButtons: false,
3756
- lockPositionWidgets: false,
3757
- controlListConfig: []
3758
- };
3759
3656
  }
3760
3657
  ngOnInit() {
3761
- }
3762
- ngOnChanges(changes) {
3763
- if (changes['dashboardConfig']) {
3764
- console.log('Nuevo valor dashboardConfig:', this.dashboardConfig);
3765
- //this.initCanvasGrid();
3766
- }
3767
- if (changes['dashboardData']) {
3768
- console.log('Nuevo valor dashboardData:', this.dashboardData);
3769
- //this.initCanvasGrid();
3658
+ if (this.currentIds() && this.currentIds().length > 0) {
3659
+ this.selectedIds().clear();
3660
+ this.currentIds().forEach((itemId) => {
3661
+ this.selectedIds().add(itemId);
3662
+ });
3770
3663
  }
3771
3664
  }
3772
- ngAfterViewInit() {
3773
- this.initCanvasGrid();
3774
- }
3775
- initCanvasGrid() {
3776
- this.layoutConfig = this.dashboardConfig.layoutConfig;
3777
- // Opciones para restringir colisiones y comportamiento
3778
- let options = {
3779
- column: this.layoutConfig.columns,
3780
- cellHeight: this.layoutConfig.cellHeight,
3781
- margin: this.layoutConfig.margin,
3782
- float: true, // Evita que los divs floten automáticamente hacia arriba
3783
- //noOverlap: true, // CLAVE: Bloquea el movimiento si colisiona con otro DIV
3784
- resizable: { handles: 'e, se, s, sw, w, nw, n, ne', autoHide: true } // Permite redimensionar desde todos los bordes
3785
- };
3786
- if (this.layoutConfig.columnOpts) {
3787
- options = {
3788
- column: this.layoutConfig.columns,
3789
- cellHeight: this.layoutConfig.cellHeight,
3790
- margin: this.layoutConfig.margin,
3791
- columnOpts: {
3792
- breakpointForWindow: this.layoutConfig.columnOpts.breakpointForWindow, // Mide el ancho de la ventana gráfica
3793
- breakpoints: this.layoutConfig.columnOpts.breakpoints,
3794
- layout: this.layoutConfig.columnOpts.layout || 'list', // Mantiene el orden de los widgets secuencialmente al colapsar
3795
- },
3796
- float: true, // Evita que los divs floten automáticamente hacia arriba
3797
- //noOverlap: true, // CLAVE: Bloquea el movimiento si colisiona con otro DIV
3798
- resizable: { handles: 'e, se, s, sw, w, nw, n, ne', autoHide: true } // Permite redimensionar desde todos los bordes
3799
- };
3800
- }
3801
- /*EXAMPLE OF "columnOpts"
3802
- columnOpts: {
3803
- breakpointForWindow: true,
3804
- breakpoints: [
3805
- { w: 768, c: 1 },
3806
- { w: 992, c: 6 },
3807
- { w: 1200, c: this.layoutConfig.columns } // 👈 Usa tu variable para consistencia en Desktop
3808
- ],
3809
- layout: 'list'
3810
- }
3811
- */
3812
- // Inicializar el canvas
3813
- this.grid = GridStack.init(options, this.gridContainer.nativeElement);
3814
- // Cargar los elementos iniciales desde el JSON
3815
- //this.loadLayoutFromJSON(this.dashboardItems);
3816
- this.loadLayoutFromJSON(this.dashboardConfig, this.dashboardStyle);
3817
- //Evaluar Bloqueo de Widgets en Inicializacion
3818
- if (this.dashboardConfig.lockPositionWidgets) {
3819
- this.fn_lockPositionWidgets(this.dashboardConfig.lockPositionWidgets);
3820
- }
3821
- // Listener para detectar cambios y actualizar el JSON
3822
- this.grid.on('change', (event, items) => {
3823
- this.saveLayoutToJSON();
3824
- });
3825
- //Listener para detectar cuando cambia las dimenciones de un widget
3826
- this.grid.on('resizestop', (event, el) => {
3827
- // Disparamos el evento nativo del navegador de forma controlada
3828
- window.dispatchEvent(new Event('resize'));
3829
- });
3665
+ clearSelection() {
3666
+ this.selectedIds().clear();
3667
+ this.selectionChange.emit([]);
3830
3668
  }
3831
- //Filtrar Datos por Componente del Widget
3832
- fn_getDataForWidgetComponent(listTables, prmDashboardData) {
3833
- let dataresponse = new Map();
3834
- const ldsize = prmDashboardData.length;
3835
- const ltsize = listTables.length;
3836
- if (ltsize > 0) {
3837
- listTables.forEach((curTableName) => {
3838
- prmDashboardData.forEach((curTableRef) => {
3839
- if (curTableName.localeCompare(curTableRef.tableName) == 0) {
3840
- dataresponse.set(curTableRef.tableName, curTableRef.tableData);
3841
- }
3842
- });
3843
- });
3669
+ // Toggle para seleccionar / deseleccionar
3670
+ toggleSelection(id) {
3671
+ const current = new Set(this.selectedIds());
3672
+ if (this.allowMultiple()) {
3673
+ if (current.has(id)) {
3674
+ current.delete(id);
3675
+ }
3676
+ else {
3677
+ current.add(id);
3678
+ }
3844
3679
  }
3845
3680
  else {
3846
- prmDashboardData.forEach((curTableRef) => {
3847
- dataresponse.set(curTableRef.tableName, curTableRef.tableData);
3848
- });
3681
+ // Si es selección única
3682
+ current.clear();
3683
+ current.add(id);
3849
3684
  }
3850
- const object_base_response = Object.fromEntries(dataresponse);
3851
- return object_base_response;
3685
+ this.selectedIds.set(current);
3852
3686
  }
3853
- fn_getDataForWidgetComponent_back(listTables) {
3854
- let dataresponse = [];
3855
- const ldsize = this.dashboardData.length;
3856
- const ltsize = listTables.length;
3857
- if (ltsize > 0) {
3858
- listTables.forEach((curTableName) => {
3859
- this.dashboardData.forEach((curTableData) => {
3860
- if (curTableName.localeCompare(curTableData.tableName) == 0) {
3861
- dataresponse.push(curTableData);
3862
- }
3863
- });
3864
- });
3687
+ isSelected(id) {
3688
+ return this.selectedIds().has(id);
3689
+ }
3690
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwButtonSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3691
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwButtonSlicerComponent, isStandalone: true, selector: "yw-button-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, allowMultiple: { classPropertyName: "allowMultiple", publicName: "allowMultiple", isSignal: true, isRequired: false, transformFunction: null }, currentIds: { classPropertyName: "currentIds", publicName: "currentIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n \r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\"> \r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" >\uD83E\uDDF9</button> \r\n </div>\r\n </div>\r\n\r\n\r\n <!-- Contenedor con barra de desplazamiento interna -->\r\n <div class=\"grid-scroll-container\">\r\n <div class=\"buttons-grid\">\r\n @for (item of options(); track item.id) {\r\n <button \r\n type=\"button\" \r\n class=\"option-btn\" \r\n [class.selected]=\"isSelected(item.id)\"\r\n (click)=\"toggleSelection(item.id)\"\r\n [title]=\"item.label\">\r\n <span class=\"btn-text\">{{ item.label }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:320px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#333}.header-actions{display:flex;gap:4px}.grid-scroll-container{max-height:145px;overflow-y:auto;padding-right:4px}.buttons-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.option-btn{display:flex;align-items:center;justify-content:center;height:38px;padding:4px 6px;background-color:#fff;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;transition:all .15s ease-in-out;outline:none;box-sizing:border-box}.option-btn:hover{border-color:#9ca3af;background-color:#f9fafb}.btn-text{font-size:12px;color:#374151;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;text-align:center}.option-btn.selected{border-color:#2563eb;background-color:#eff6ff;box-shadow:0 0 0 1px #2563eb}.option-btn.selected .btn-text{color:#1d4ed8;font-weight:600}.grid-scroll-container::-webkit-scrollbar{width:6px}.grid-scroll-container::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb{background:#71717a;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb:hover{background:#52525b}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
3692
+ }
3693
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwButtonSlicerComponent, decorators: [{
3694
+ type: Component,
3695
+ args: [{ selector: 'yw-button-slicer', standalone: true, imports: [CommonModule], host: {
3696
+ '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3697
+ }, template: "<div class=\"filter-container\">\r\n \r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\"> \r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" >\uD83E\uDDF9</button> \r\n </div>\r\n </div>\r\n\r\n\r\n <!-- Contenedor con barra de desplazamiento interna -->\r\n <div class=\"grid-scroll-container\">\r\n <div class=\"buttons-grid\">\r\n @for (item of options(); track item.id) {\r\n <button \r\n type=\"button\" \r\n class=\"option-btn\" \r\n [class.selected]=\"isSelected(item.id)\"\r\n (click)=\"toggleSelection(item.id)\"\r\n [title]=\"item.label\">\r\n <span class=\"btn-text\">{{ item.label }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Arial,Helvetica,sans-serif;width:100%;max-width:320px}.filter-container{display:flex;flex-direction:column;gap:8px}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#333}.header-actions{display:flex;gap:4px}.grid-scroll-container{max-height:145px;overflow-y:auto;padding-right:4px}.buttons-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.option-btn{display:flex;align-items:center;justify-content:center;height:38px;padding:4px 6px;background-color:#fff;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;transition:all .15s ease-in-out;outline:none;box-sizing:border-box}.option-btn:hover{border-color:#9ca3af;background-color:#f9fafb}.btn-text{font-size:12px;color:#374151;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;text-align:center}.option-btn.selected{border-color:#2563eb;background-color:#eff6ff;box-shadow:0 0 0 1px #2563eb}.option-btn.selected .btn-text{color:#1d4ed8;font-weight:600}.grid-scroll-container::-webkit-scrollbar{width:6px}.grid-scroll-container::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb{background:#71717a;border-radius:4px}.grid-scroll-container::-webkit-scrollbar-thumb:hover{background:#52525b}\n"] }]
3698
+ }], ctorParameters: () => [], propDecorators: { idComponent: [{
3699
+ type: Input
3700
+ }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], allowMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowMultiple", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], currentIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentIds", required: false }] }] } });
3701
+
3702
+ class YwListSlicerComponent {
3703
+ constructor() {
3704
+ // Entradas generales
3705
+ this.idComponent = '';
3706
+ this.label = input('Filtro Jerárquico', ...(ngDevMode ? [{ debugName: "label" }] : []));
3707
+ this.clearTitleLabel = input('Limpiar Seleccion', ...(ngDevMode ? [{ debugName: "clearTitleLabel" }] : []));
3708
+ // Opción 1: Entregar datos en árbol de texto directo
3709
+ this.rawData = input([], ...(ngDevMode ? [{ debugName: "rawData" }] : []));
3710
+ // Opción 2: Generar desde fechas
3711
+ this.dataType = input('date', ...(ngDevMode ? [{ debugName: "dataType" }] : []));
3712
+ this.minDate = input('', ...(ngDevMode ? [{ debugName: "minDate" }] : [])); // Formato 'YYYY-MM-DD'
3713
+ this.maxDate = input('', ...(ngDevMode ? [{ debugName: "maxDate" }] : []));
3714
+ this.dateHierarchyType = input('YEAR_TRIMESTER_MONTH', ...(ngDevMode ? [{ debugName: "dateHierarchyType" }] : []));
3715
+ this.monthNames = input(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], ...(ngDevMode ? [{ debugName: "monthNames" }] : []));
3716
+ // Evento de salida con el ID/Nodo seleccionado
3717
+ this.selectionChange = output();
3718
+ this.filterValueChange = output(); // Output 2 (Rangos o Hojas)
3719
+ // ID del elemento seleccionado (Selección Simple)
3720
+ this.selectedId = signal(null, ...(ngDevMode ? [{ debugName: "selectedId" }] : []));
3721
+ this.currentSelectedId = input(null, ...(ngDevMode ? [{ debugName: "currentSelectedId" }] : []));
3722
+ // Arbol de nodos computado
3723
+ this.treeNodes = computed(() => {
3724
+ if (this.dataType() == 'date' && this.minDate() && this.maxDate()) {
3725
+ return this.generateDateHierarchy(this.minDate(), this.maxDate(), this.dateHierarchyType());
3726
+ }
3727
+ return this.rawData();
3728
+ }, ...(ngDevMode ? [{ debugName: "treeNodes" }] : []));
3729
+ effect(() => {
3730
+ const currentId = this.selectedId();
3731
+ if (!currentId) {
3732
+ this.selectionChange.emit(null);
3733
+ this.filterValueChange.emit(null);
3734
+ return;
3735
+ }
3736
+ const node = this.findNodeById(this.treeNodes(), currentId);
3737
+ this.selectionChange.emit(node);
3738
+ if (node) {
3739
+ // Emitir el segundo Output según el modo
3740
+ const calculatedValue = this.processFilterOutput(node);
3741
+ this.filterValueChange.emit(calculatedValue);
3742
+ }
3743
+ });
3744
+ }
3745
+ ngOnInit() {
3746
+ if (this.currentSelectedId()) {
3747
+ this.selectedId.set(this.currentSelectedId());
3865
3748
  }
3866
- else {
3867
- return this.dashboardData;
3749
+ }
3750
+ // Métodos de Selección y Expansión
3751
+ toggleExpand(node, event) {
3752
+ event.stopPropagation();
3753
+ node.expanded = !node.expanded;
3754
+ }
3755
+ selectNode(node, event) {
3756
+ event.stopPropagation();
3757
+ this.selectedId.set(this.selectedId() === node.id ? null : node.id);
3758
+ }
3759
+ clearSelection() {
3760
+ this.selectedId.set(null);
3761
+ this.filterValueChange.emit(null);
3762
+ }
3763
+ // --- LÓGICA DE PROCESAMIENTO DE LAS HOJAS / RANGOS ---
3764
+ processFilterOutput(selectedNode) {
3765
+ // 1. Obtener todas las hojas (nodos del nivel más bajo) pertenecientes al bloque seleccionado
3766
+ const leaves = this.getLeafNodes(selectedNode);
3767
+ if (this.dataType() == 'date') {
3768
+ // Extraer todas las fechas de las hojas del bloque
3769
+ const dates = leaves
3770
+ .map(leaf => leaf.value)
3771
+ .filter(d => d instanceof Date)
3772
+ .sort((a, b) => a.getTime() - b.getTime());
3773
+ if (dates.length > 0) {
3774
+ const minD = dates[0];
3775
+ // Para la fecha máxima, tomamos el último día del mes correspondiente
3776
+ const maxD = new Date(dates[dates.length - 1].getFullYear(), dates[dates.length - 1].getMonth() + 1, 0);
3777
+ return {
3778
+ type: 'DATE_RANGE',
3779
+ dateRange: {
3780
+ minDate: minD.toISOString().split('T')[0],
3781
+ maxDate: maxD.toISOString().split('T')[0]
3782
+ },
3783
+ currentNodeId: selectedNode.id
3784
+ };
3785
+ }
3868
3786
  }
3869
- return dataresponse;
3787
+ // Modo Texto: Entregar arreglo con las hojas
3788
+ return {
3789
+ type: 'TEXT_LEAVES',
3790
+ leafNodes: leaves,
3791
+ leafIds: leaves.map(l => l.id),
3792
+ currentNodeId: selectedNode.id
3793
+ };
3870
3794
  }
3871
- // Carga elementos desde la configuración JSON
3872
- //public loadLayoutFromJSON(dashboardItems: YwWidgetLayoutInterface[], ): void {
3873
- loadLayoutFromJSON(prmDashboardConfig, prmDashboardStyle) {
3874
- this.grid.removeAll();
3875
- const widgets = [];
3876
- this.grid.load(widgets);
3877
- const lsize = prmDashboardConfig.controlListConfig.length;
3878
- if (lsize > 0) {
3879
- prmDashboardConfig.controlListConfig.forEach((widgetConfig) => {
3880
- //Agregar uno por uno, para poder cargar los parametros internos de los componentes.
3881
- const controlData = this.fn_getDataForWidgetComponent(widgetConfig.controlTables, this.dashboardData);
3882
- //Sobre Escribir el ID Correcto en Layaout
3883
- widgetConfig.layoutConfig.id = widgetConfig.widgetId;
3884
- //Evaluar Mostrar Eventos
3885
- if (widgetConfig.showConfigButtons == null || widgetConfig.showConfigButtons == undefined) {
3886
- widgetConfig.showConfigButtons = prmDashboardConfig.showConfigButtons;
3795
+ // Recorrido recursivo para obtener solo los nodos terminales (sin hijos)
3796
+ getLeafNodes(node) {
3797
+ if (!node.children || node.children.length === 0) {
3798
+ return [node];
3799
+ }
3800
+ let leaves = [];
3801
+ for (const child of node.children) {
3802
+ leaves = leaves.concat(this.getLeafNodes(child));
3803
+ }
3804
+ return leaves;
3805
+ }
3806
+ findNodeById(nodes, id) {
3807
+ for (const node of nodes) {
3808
+ if (node.id === id)
3809
+ return node;
3810
+ if (node.children) {
3811
+ const found = this.findNodeById(node.children, id);
3812
+ if (found)
3813
+ return found;
3814
+ }
3815
+ }
3816
+ return null;
3817
+ }
3818
+ // Generador de Jerarquía por Fechas
3819
+ generateDateHierarchy(startStr, endStr, type) {
3820
+ const start = new Date(startStr);
3821
+ const end = new Date(endStr);
3822
+ const tree = [];
3823
+ const monthNames = this.monthNames();
3824
+ if (type === 'YEAR_TRIMESTER_MONTH') {
3825
+ let current = new Date(start);
3826
+ while (current <= end) {
3827
+ const year = current.getFullYear();
3828
+ let yearNode = tree.find(n => n.id === `Y_${year}`);
3829
+ if (!yearNode) {
3830
+ yearNode = { id: `Y_${year}`, label: `${year}`, children: [], expanded: false };
3831
+ tree.push(yearNode);
3887
3832
  }
3888
- //Evalua Asignacion de Estilos
3889
- if (widgetConfig.widgetStyle == null || widgetConfig.widgetStyle == undefined) {
3890
- widgetConfig['widgetStyle'] = {};
3891
- widgetConfig['widgetStyle']['widgetBackgroundColor'] = prmDashboardStyle.widgetBackgroundColor;
3892
- widgetConfig['widgetStyle']['widgetBorderColor'] = prmDashboardStyle.widgetBorderColor;
3833
+ const month = current.getMonth();
3834
+ const qtrNum = Math.floor(month / 3) + 1;
3835
+ let qtrNode = yearNode.children.find(n => n.id === `Q_${year}_${qtrNum}`);
3836
+ if (!qtrNode) {
3837
+ qtrNode = { id: `Q_${year}_${qtrNum}`, label: `Qtr ${qtrNum}`, children: [], expanded: false };
3838
+ yearNode.children.push(qtrNode);
3893
3839
  }
3894
- this.eventAddWidget(widgetConfig, widgetConfig.controlConfig, controlData, widgetConfig.layoutConfig);
3895
- });
3840
+ const monthId = `M_${year}_${month + 1}`;
3841
+ if (!qtrNode.children.some(n => n.id === monthId)) {
3842
+ qtrNode.children.push({
3843
+ id: monthId,
3844
+ label: monthNames[month],
3845
+ value: new Date(year, month, 1) // Fecha inicial del mes
3846
+ });
3847
+ }
3848
+ current.setMonth(current.getMonth() + 1);
3849
+ }
3896
3850
  }
3851
+ if (type === 'YEAR_SEMESTER_MONTH') {
3852
+ let current = new Date(start);
3853
+ while (current <= end) {
3854
+ const year = current.getFullYear();
3855
+ let yearNode = tree.find(n => n.id === `Y_${year}`);
3856
+ if (!yearNode) {
3857
+ yearNode = { id: `Y_${year}`, label: `${year}`, children: [], expanded: false };
3858
+ tree.push(yearNode);
3859
+ }
3860
+ const month = current.getMonth();
3861
+ const qtrNum = Math.floor(month / 6) + 1;
3862
+ let qtrNode = yearNode.children.find(n => n.id === `S_${year}_${qtrNum}`);
3863
+ if (!qtrNode) {
3864
+ qtrNode = { id: `S_${year}_${qtrNum}`, label: `S ${qtrNum}`, children: [], expanded: false };
3865
+ yearNode.children.push(qtrNode);
3866
+ }
3867
+ const monthId = `M_${year}_${month + 1}`;
3868
+ if (!qtrNode.children.some(n => n.id === monthId)) {
3869
+ qtrNode.children.push({
3870
+ id: monthId,
3871
+ label: monthNames[month],
3872
+ value: new Date(year, month, 1) // Fecha inicial del mes
3873
+ });
3874
+ }
3875
+ current.setMonth(current.getMonth() + 1);
3876
+ }
3877
+ }
3878
+ return tree;
3897
3879
  }
3898
- // Guarda los elementos desde la configuración JSON
3899
- saveLayoutToJSON() {
3900
- const currentWidgets = this.grid.save(false);
3901
- this.dashboardItems = currentWidgets.map(w => ({
3902
- id: w.id,
3903
- x: w.x || 0,
3904
- y: w.y || 0,
3905
- w: w.w || 1,
3906
- h: w.h || 1,
3907
- content: w.content,
3908
- contentData: {}
3909
- }));
3910
- console.log('JSON Guardado:', JSON.stringify(this.dashboardItems));
3911
- return this.dashboardItems;
3912
- }
3913
- /*BUTTON ADD WIDGET*/
3914
- fn_btn_addWidget() {
3915
- this.countWidget++;
3916
- const newWidgetId = 'widget-' + this.countWidget;
3917
- let newItem = {
3918
- id: newWidgetId, autoPosition: true, w: 6, h: 3,
3919
- content: ''
3920
- };
3921
- //Datos de Widget y sus Contenidos
3922
- const widgetConfig = {
3923
- widgetId: newWidgetId,
3924
- title: '',
3925
- typeComponent: 'empty-visual',
3926
- showConfigButtons: true,
3927
- widgetStyle: DEFAULT_WIDGET_STYLE,
3928
- layoutConfig: {
3929
- id: '',
3930
- w: 0,
3931
- h: 0,
3932
- content: undefined
3933
- },
3934
- controlConfig: {},
3935
- controlTables: []
3880
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwListSlicerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3881
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwListSlicerComponent, isStandalone: true, selector: "yw-list-slicer", inputs: { idComponent: { classPropertyName: "idComponent", publicName: "idComponent", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, clearTitleLabel: { classPropertyName: "clearTitleLabel", publicName: "clearTitleLabel", isSignal: true, isRequired: false, transformFunction: null }, rawData: { classPropertyName: "rawData", publicName: "rawData", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateHierarchyType: { classPropertyName: "dateHierarchyType", publicName: "dateHierarchyType", isSignal: true, isRequired: false, transformFunction: null }, monthNames: { classPropertyName: "monthNames", publicName: "monthNames", isSignal: true, isRequired: false, transformFunction: null }, currentSelectedId: { classPropertyName: "currentSelectedId", publicName: "currentSelectedId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", filterValueChange: "filterValueChange" }, host: { properties: { "attr.id": "idComponent" } }, ngImport: i0, template: "<div class=\"filter-container\">\r\n <!-- Cabecera con t\u00EDtulo y acciones de filtro -->\r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\">\r\n <!--<button class=\"icon-btn\" title=\"Filtro\">\uD83D\uDD3B</button>-->\r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" title=\"{{clearTitleLabel}}\">\uD83E\uDDF9</button>\r\n <!--<button class=\"icon-btn\" title=\"M\u00E1s opciones\">\u22EE</button>-->\r\n </div>\r\n </div>\r\n\r\n <!-- Vista en \u00C1rbol con scroll interno -->\r\n <div class=\"tree-scroll-container\">\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: treeNodes(), level: 0 }\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n<!-- Plantilla Recursiva para renderizar niveles del \u00C1rbol -->\r\n<ng-template #nodeListTemplate let-nodes let-level=\"level\">\r\n <div class=\"tree-level\">\r\n @for (node of nodes; track node.id) {\r\n <div class=\"tree-node-wrapper\">\r\n <!-- Fila de opci\u00F3n -->\r\n <div \r\n class=\"tree-node-row\" \r\n [class.selected]=\"selectedId() === node.id\"\r\n [style.padding-left.px]=\"level * 18 + 6\"\r\n (click)=\"selectNode(node, $event)\">\r\n \r\n <!-- Flecha expandir/colapsar (si tiene hijos) -->\r\n @if (node.children && node.children.length > 0) {\r\n <span class=\"chevron-icon\" (click)=\"toggleExpand(node, $event)\">\r\n {{ node.expanded ? '\uD83D\uDF83' : '\uD83D\uDF82' }}\r\n </span>\r\n } @else {\r\n <span class=\"chevron-spacer\"></span>\r\n }\r\n\r\n <!-- Radio Button (Selecci\u00F3n simple) -->\r\n <div class=\"radio-circle\" [class.checked]=\"selectedId() === node.id\">\r\n <div class=\"radio-inner\"></div>\r\n </div>\r\n\r\n <!-- Etiqueta del Nodo -->\r\n <span class=\"node-label\">{{ node.label }}</span>\r\n </div>\r\n\r\n <!-- Renderizado de hijos si est\u00E1 expandido -->\r\n @if (node.children && node.children.length > 0 && node.expanded) {\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: node.children, level: level + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;width:100%;max-width:320px;background:#fff}.filter-container{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:4px;background-color:#fff}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#252423}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;cursor:pointer;font-size:12px;color:#605e5c;padding:2px 4px;border-radius:2px}.icon-btn:hover{background-color:#f3f2f1}.tree-scroll-container{max-height:220px;overflow-y:auto;padding:4px 0}.tree-level{display:flex;flex-direction:column}.tree-node-row{display:flex;align-items:center;height:28px;cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px;transition:background-color .1s ease}.tree-node-row:hover{background-color:#f3f2f1}.tree-node-row.selected{background-color:#e1dfdd}.chevron-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:#323130}.chevron-spacer{width:16px}.radio-circle{width:14px;height:14px;border-radius:50%;border:1.5px solid #605e5c;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:#fff}.radio-circle.checked{border-color:#0078d4}.radio-circle.checked .radio-inner{width:6px;height:6px;border-radius:50%;background-color:#0078d4}.node-label{font-size:13px;color:#323130;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-scroll-container::-webkit-scrollbar{width:6px}.tree-scroll-container::-webkit-scrollbar-track{background:#f1f1f1}.tree-scroll-container::-webkit-scrollbar-thumb{background:#8a8886;border-radius:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
3882
+ }
3883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwListSlicerComponent, decorators: [{
3884
+ type: Component,
3885
+ args: [{ selector: 'yw-list-slicer', standalone: true, imports: [CommonModule], host: {
3886
+ '[attr.id]': 'idComponent' // Vincula el atributo id al valor de la propiedad
3887
+ }, template: "<div class=\"filter-container\">\r\n <!-- Cabecera con t\u00EDtulo y acciones de filtro -->\r\n <div class=\"filter-header\">\r\n <span class=\"filter-label\">{{ label() }}</span>\r\n <div class=\"header-actions\">\r\n <!--<button class=\"icon-btn\" title=\"Filtro\">\uD83D\uDD3B</button>-->\r\n <button class=\"icon-btn\" (click)=\"clearSelection()\" title=\"{{clearTitleLabel}}\">\uD83E\uDDF9</button>\r\n <!--<button class=\"icon-btn\" title=\"M\u00E1s opciones\">\u22EE</button>-->\r\n </div>\r\n </div>\r\n\r\n <!-- Vista en \u00C1rbol con scroll interno -->\r\n <div class=\"tree-scroll-container\">\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: treeNodes(), level: 0 }\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n<!-- Plantilla Recursiva para renderizar niveles del \u00C1rbol -->\r\n<ng-template #nodeListTemplate let-nodes let-level=\"level\">\r\n <div class=\"tree-level\">\r\n @for (node of nodes; track node.id) {\r\n <div class=\"tree-node-wrapper\">\r\n <!-- Fila de opci\u00F3n -->\r\n <div \r\n class=\"tree-node-row\" \r\n [class.selected]=\"selectedId() === node.id\"\r\n [style.padding-left.px]=\"level * 18 + 6\"\r\n (click)=\"selectNode(node, $event)\">\r\n \r\n <!-- Flecha expandir/colapsar (si tiene hijos) -->\r\n @if (node.children && node.children.length > 0) {\r\n <span class=\"chevron-icon\" (click)=\"toggleExpand(node, $event)\">\r\n {{ node.expanded ? '\uD83D\uDF83' : '\uD83D\uDF82' }}\r\n </span>\r\n } @else {\r\n <span class=\"chevron-spacer\"></span>\r\n }\r\n\r\n <!-- Radio Button (Selecci\u00F3n simple) -->\r\n <div class=\"radio-circle\" [class.checked]=\"selectedId() === node.id\">\r\n <div class=\"radio-inner\"></div>\r\n </div>\r\n\r\n <!-- Etiqueta del Nodo -->\r\n <span class=\"node-label\">{{ node.label }}</span>\r\n </div>\r\n\r\n <!-- Renderizado de hijos si est\u00E1 expandido -->\r\n @if (node.children && node.children.length > 0 && node.expanded) {\r\n <ng-container *ngTemplateOutlet=\"nodeListTemplate; context: { $implicit: node.children, level: level + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;width:100%;max-width:320px;background:#fff}.filter-container{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:4px;background-color:#fff}.filter-header{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid #f0f0f0}.filter-label{font-size:13px;font-weight:600;color:#252423}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;cursor:pointer;font-size:12px;color:#605e5c;padding:2px 4px;border-radius:2px}.icon-btn:hover{background-color:#f3f2f1}.tree-scroll-container{max-height:220px;overflow-y:auto;padding:4px 0}.tree-level{display:flex;flex-direction:column}.tree-node-row{display:flex;align-items:center;height:28px;cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px;transition:background-color .1s ease}.tree-node-row:hover{background-color:#f3f2f1}.tree-node-row.selected{background-color:#e1dfdd}.chevron-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:#323130}.chevron-spacer{width:16px}.radio-circle{width:14px;height:14px;border-radius:50%;border:1.5px solid #605e5c;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:#fff}.radio-circle.checked{border-color:#0078d4}.radio-circle.checked .radio-inner{width:6px;height:6px;border-radius:50%;background-color:#0078d4}.node-label{font-size:13px;color:#323130;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-scroll-container::-webkit-scrollbar{width:6px}.tree-scroll-container::-webkit-scrollbar-track{background:#f1f1f1}.tree-scroll-container::-webkit-scrollbar-thumb{background:#8a8886;border-radius:3px}\n"] }]
3888
+ }], ctorParameters: () => [], propDecorators: { idComponent: [{
3889
+ type: Input
3890
+ }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], clearTitleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearTitleLabel", required: false }] }], rawData: [{ type: i0.Input, args: [{ isSignal: true, alias: "rawData", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateHierarchyType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateHierarchyType", required: false }] }], monthNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthNames", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], filterValueChange: [{ type: i0.Output, args: ["filterValueChange"] }], currentSelectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSelectedId", required: false }] }] } });
3891
+
3892
+ class YwDashboardFilterWidgetComponent {
3893
+ constructor() {
3894
+ this.componentWidgetId = '';
3895
+ this.typeComponent = '';
3896
+ this.varShowConfigButtons = false;
3897
+ this.configWidget = {
3898
+ widgetId: '',
3899
+ label: '',
3900
+ typeComponent: '',
3901
+ controlTable: '',
3936
3902
  };
3937
- const controlConfig = {};
3938
- const controlData = {};
3939
- this.eventAddWidget(widgetConfig, controlConfig, controlData, newItem);
3940
- }
3941
- /*BUTTON DELETE WIDGET*/
3942
- fn_btn_deleteWidget() {
3943
- const newWidgetId = 'widget-' + this.countWidget;
3944
- this.eventRemoveWidgetById(newWidgetId);
3945
- this.countWidget--;
3903
+ this.controlConfig = input(...(ngDevMode ? [undefined, { debugName: "controlConfig" }] : []));
3904
+ this.controlData = [];
3905
+ this.eventDeleteRequest = output();
3906
+ this.eventShowConfigFormRequest = output();
3907
+ this.selectionChange = output();
3908
+ effect(() => {
3909
+ const value_controlConfig = this.fnFormatConfigData();
3910
+ this.dataWidget = { idComponent: this.componentWidgetId,
3911
+ configWidget: this.configWidget,
3912
+ controlConfig: value_controlConfig
3913
+ };
3914
+ });
3946
3915
  }
3947
- /*BUTTON BLOCK WIDGETS*/
3948
- fn_btn_lockPositionWidgets() {
3949
- this.isLocked = !this.isLocked;
3950
- const shouldLock = !this.allIsLocked();
3951
- this.allIsLocked.set(shouldLock);
3952
- this.fn_lockPositionWidgets(shouldLock);
3953
- console.log(`All widgets have been visually and functionally locked: ${shouldLock}`);
3916
+ ngOnInit() {
3917
+ this.componentWidgetId = this.configWidget.widgetId;
3918
+ this.typeComponent = this.configWidget.typeComponent;
3919
+ const value_controlConfig = this.fnFormatConfigData();
3920
+ this.dataWidget = { idComponent: this.componentWidgetId,
3921
+ configWidget: this.configWidget,
3922
+ controlConfig: value_controlConfig
3923
+ };
3954
3924
  }
3955
- fn_lockPositionWidgets(prmAllIsLocked) {
3956
- const shouldLock = prmAllIsLocked;
3957
- // 1. Perform the functional Gridstack task on the core grid layout
3958
- this.grid.movable('.grid-stack-item', !shouldLock);
3959
- this.grid.resizable('.grid-stack-item', !shouldLock);
3960
- // 2. Broadcast the state change down to every active dynamic child component
3961
- this.widgetsActivos.forEach((componentRef) => {
3962
- componentRef.setInput('isLocked', shouldLock);
3963
- });
3964
- console.log(`All widgets have been visually and functionally locked - por TS Config: ${shouldLock}`);
3925
+ /*
3926
+ Los Datos a este componente llegan a un nivel basico, sin embargo es necesario configurar la informacion, para que se adapte a los componentes.
3927
+ */
3928
+ fnFormatConfigData() {
3929
+ let responsedata = {};
3930
+ const typeComponent = this.configWidget.typeComponent;
3931
+ if (typeComponent == 'filter-slicer') {
3932
+ const dataType = this.controlConfig().dataType;
3933
+ const currentData = this.controlConfig();
3934
+ if (dataType == 'date') {
3935
+ const fieldName = this.controlConfig().filterField;
3936
+ const fechas = this.controlData.map((d) => new Date(d[fieldName]).getTime());
3937
+ const val_min = new Date(Math.min(...fechas)).toISOString().split("T")[0];
3938
+ const val_max = new Date(Math.max(...fechas)).toISOString().split("T")[0];
3939
+ responsedata = { dataType: dataType, min: val_min, max: val_max, minCurrent: currentData?.minCurrent, maxCurrent: currentData?.maxCurrent };
3940
+ }
3941
+ if (dataType == 'number') {
3942
+ const fieldName = this.controlConfig().filterField;
3943
+ const valStep = this.controlConfig().step;
3944
+ const DataNumbers = this.controlData.map((d) => d[fieldName]);
3945
+ const val_min = Math.min(...DataNumbers);
3946
+ const val_max = Math.max(...DataNumbers);
3947
+ responsedata = { dataType: dataType, min: val_min, max: val_max, step: valStep, minCurrent: currentData?.minCurrent, maxCurrent: currentData?.maxCurrent };
3948
+ }
3949
+ }
3950
+ if (typeComponent == 'filter-button') {
3951
+ const fieldName = this.controlConfig().filterField;
3952
+ const fieldNameId = this.controlConfig().filterFieldId;
3953
+ const val_allowMultiple = this.controlConfig().allowMultiple;
3954
+ const currentData = this.controlConfig();
3955
+ let listoptions = this.controlData.map((item) => { return { 'id': item[fieldNameId], 'label': item[fieldName] }; });
3956
+ const listoptionsunicos = [...new Map(listoptions.map(d => [d.id, d])).values()];
3957
+ responsedata = { options: listoptionsunicos, allowMultiple: val_allowMultiple, currentIds: currentData?.currentIds };
3958
+ }
3959
+ if (typeComponent == 'filter-list') {
3960
+ const dataType = this.controlConfig().dataType;
3961
+ const currentData = this.controlConfig();
3962
+ if (dataType == 'date') {
3963
+ const fieldName = this.controlConfig().filterField;
3964
+ const val_dateHierarchyType = this.controlConfig().dateHierarchyType;
3965
+ const fechas = this.controlData.map((d) => new Date(d[fieldName]).getTime());
3966
+ const val_min = new Date(Math.min(...fechas)).toISOString().split("T")[0];
3967
+ const val_max = new Date(Math.max(...fechas)).toISOString().split("T")[0];
3968
+ responsedata = { dataType: dataType, minDate: val_min, maxDate: val_max, dateHierarchyType: val_dateHierarchyType, currentSelectedId: currentData.currentSelectedId };
3969
+ }
3970
+ if (dataType == 'text') {
3971
+ const fieldName1 = this.controlConfig().filterField;
3972
+ const fieldName2 = this.controlConfig().filterFieldN2;
3973
+ const fieldName3 = this.controlConfig().filterFieldN3;
3974
+ let foundN2 = false;
3975
+ let foundN3 = false;
3976
+ let lsizeN2 = 0;
3977
+ let lsizeN3 = 0;
3978
+ let nodebase = { id: '', label: '' };
3979
+ let nodeN2 = { id: '', label: '' };
3980
+ let nodeN3 = { id: '', label: '' };
3981
+ let listNivel1 = [];
3982
+ let listNivel2 = [];
3983
+ let listNivel3 = [];
3984
+ this.controlData.forEach((item) => {
3985
+ nodebase = { id: item[fieldName1], label: item[fieldName1] };
3986
+ //NIVEL 2
3987
+ if (fieldName2) {
3988
+ foundN2 = false;
3989
+ lsizeN2 = Object.keys(listNivel2).length;
3990
+ for (let i = 0; i < lsizeN2; i++) {
3991
+ const itemN2 = listNivel2[i];
3992
+ if (itemN2.id == item[fieldName2]) {
3993
+ itemN2.children.push(nodebase);
3994
+ nodeN2 = itemN2;
3995
+ foundN2 = true;
3996
+ break;
3997
+ }
3998
+ }
3999
+ ;
4000
+ if (foundN2 == false) {
4001
+ nodeN2 = { id: item[fieldName2], label: item[fieldName2], expanded: true, children: [nodebase] };
4002
+ if (fieldName3) {
4003
+ nodeN2.parentId = item[fieldName3];
4004
+ }
4005
+ listNivel2.push(nodeN2);
4006
+ }
4007
+ }
4008
+ else {
4009
+ listNivel1.push(nodebase);
4010
+ }
4011
+ });
4012
+ //NIVEL 1 - Basico no hay Jerarquia
4013
+ responsedata = { dataType: dataType, rawData: listNivel1, currentSelectedId: currentData.currentSelectedId };
4014
+ //NIVEL 2 - Jerarquia de 2 niveles
4015
+ if (fieldName2) {
4016
+ responsedata = { dataType: dataType, rawData: listNivel2, currentSelectedId: currentData.currentSelectedId };
4017
+ }
4018
+ //NIVEL 3 - Jerarquia de 3 niveles
4019
+ if (fieldName3) {
4020
+ listNivel2.forEach((item) => {
4021
+ nodebase = item;
4022
+ foundN3 = false;
4023
+ lsizeN3 = Object.keys(listNivel3).length;
4024
+ for (let i = 0; i < lsizeN3; i++) {
4025
+ const itemN3 = listNivel3[i];
4026
+ if (itemN3.id == item.parentId) {
4027
+ itemN3.children.push(nodebase);
4028
+ foundN3 = true;
4029
+ break;
4030
+ }
4031
+ }
4032
+ ;
4033
+ if (foundN3 == false) {
4034
+ nodeN3 = { id: item[fieldName3], label: item[fieldName3], expanded: true, children: [nodebase] };
4035
+ listNivel3.push(nodeN3);
4036
+ }
4037
+ });
4038
+ responsedata = { dataType: dataType, rawData: listNivel3, currentSelectedId: currentData.currentSelectedId };
4039
+ }
4040
+ }
4041
+ }
4042
+ return responsedata;
3965
4043
  }
3966
- /*BUTTON UPDATE WIDGET - CONTROL CONFIG */
3967
- fn_btn_updateWidgetControlConfig(idWidget) {
3968
- let newControlConfig = {};
3969
- /*MODIFICAR METODO PARA CARGAR INFO DEL FORMULARIO*/
3970
- newControlConfig['provider'] = 'syncfusion';
3971
- this.eventUpdateWidgetControlConfig(idWidget, newControlConfig);
4044
+ //Filtro Slicer
4045
+ onFilterSlicerChange(range) {
4046
+ console.log('Filtro actualizado:', range);
4047
+ this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: range });
3972
4048
  }
3973
- /*BUTTON UPDATE WIDGET - CONTROL CONFIG */
3974
- fn_btn_updateWidgetControlData(idWidget) {
3975
- let newControlData = [];
3976
- /*MODIFICAR METODO PARA CARGAR INFO DEL FORMULARIO*/
3977
- newControlData = [
3978
- { month: 'Ene', sales: 35, expenses: 28 },
3979
- { month: 'Feb', sales: 28, expenses: 22 },
3980
- { month: 'Mar', sales: 34, expenses: 25 },
3981
- { month: 'Abr', sales: 32, expenses: 27 },
3982
- { month: 'May', sales: 40, expenses: 30 },
3983
- { month: 'Jun', sales: 32, expenses: 26 },
3984
- { month: 'Jul', sales: 45, expenses: 32 },
3985
- { month: 'Ago', sales: 38, expenses: 29 },
3986
- { month: 'Sep', sales: 42, expenses: 31 },
3987
- { month: 'Oct', sales: 48, expenses: 35 },
3988
- { month: 'Nov', sales: 52, expenses: 38 },
3989
- { month: 'Dic', sales: 58, expenses: 42 },
3990
- ];
3991
- this.eventUpdateWidgetControlData(idWidget, newControlData);
4049
+ //Filtro Button
4050
+ onFilterButtonChange(selectedIds) {
4051
+ console.log('Tipos seleccionados:', selectedIds);
4052
+ this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: selectedIds });
3992
4053
  }
3993
- /****************************************************** */
3994
- /*AGREGAR WIDGET*/
3995
- eventAddWidget(widgetConfig, controlConfig, controlData, item) {
3996
- // 1. Agregar el contenedor del widget a Gridstack
3997
- const el = this.grid.addWidget(item);
3998
- // 2. Obtener el contenedor interno generado por Gridstack
3999
- const contentElement = el.querySelector('.grid-stack-item-content');
4000
- if (contentElement) {
4001
- // 3. Crear dinámicamente la instancia del componente Angular
4002
- const componentRef = createComponent(YwDashboardWidgetComponent, {
4003
- environmentInjector: this.environmentInjector, // Requerido para resolver dependencias
4004
- hostElement: contentElement // Renderiza directamente aquí dentro
4005
- });
4006
- // 4. Pasar las propiedades/Inputs al componente creado
4007
- //Evaluar Estilos
4008
- componentRef.setInput('styleWidget', widgetConfig.widgetStyle);
4009
- //componentRef.instance.configWidget = widgetConfig;
4010
- componentRef.setInput('configWidget', widgetConfig);
4011
- componentRef.setInput('controlConfig', controlConfig);
4012
- componentRef.setInput('controlData', controlData);
4013
- /* BEGIN - Eventos que provienen desde widget */
4014
- componentRef.instance.eventDeleteRequest.subscribe((idWidget) => {
4015
- // Ejecutamos la función de borrado que ya programamos en el paso anterior
4016
- this.eventRemoveWidgetById(idWidget);
4017
- });
4018
- componentRef.instance.eventLockToggleRequest.subscribe((event) => {
4019
- this.eventToggleLockWidget(event.widgetId, event.shouldLock);
4020
- });
4021
- componentRef.instance.eventMaximizeToggleRequest.subscribe((event) => {
4022
- this.eventToggleMaximizeWidget(event.widgetId, event.shouldMaximize);
4023
- });
4024
- //Mostrar
4025
- componentRef.instance.eventShowConfigFormRequest.subscribe((idWidget) => {
4026
- this.eventShowFormConfigWidget(idWidget);
4027
- });
4028
- /* END - Eventos que provienen desde widget */
4029
- // 5. Mover los nodos del DOM generados por Angular dentro del DIV del Widget
4030
- this.appRef.attachView(componentRef.hostView);
4031
- // Guardar la referencia de Componentes para hacer operaciones con estas.
4032
- this.widgetsActivos.set(item.id, componentRef);
4033
- //El componente interno no aparece bien dimensionado, con esto disparamos el evento para que se ajuste a las dimenciones correctas
4034
- setTimeout(() => {
4035
- window.dispatchEvent(new Event('resize'));
4036
- }, 50);
4037
- }
4054
+ //Filtro Lista - 1
4055
+ onFilterListChange(selectedData) {
4056
+ console.log('Tipos seleccionados:', selectedData);
4057
+ // Filtrar la información del dashboard
4058
+ //this.selectionChange.emit({widgetId:this.componentWidgetId,eventResponse:selectedData});
4038
4059
  }
4039
- /*UPDATE CONTROLCONFIG WIDGET*/
4040
- eventUpdateWidgetControlConfig(idWidget, newControlConfig) {
4041
- //Obtener la referencia del componente almacenada en el Map
4042
- const componentRef = this.widgetsActivos.get(idWidget);
4043
- if (!componentRef) {
4044
- console.warn(`No se encontró un widget activo con el ID: ${idWidget}`);
4060
+ //Filtro Lista - 2
4061
+ onFilterListCalculated(data) {
4062
+ if (!data) {
4063
+ this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: null });
4045
4064
  return;
4046
4065
  }
4047
- //Actualizar el Input usando la API oficial setInput
4048
- componentRef.setInput('controlConfig', newControlConfig);
4049
- // NOTA: setInput dispara automáticamente la detección de cambios (ChangeDetectionStrategy.OnPush).
4050
- // Si deseas asegurarte manualmente, puedes forzar un render:
4051
- // componentRef.changeDetectorRef.detectChanges();
4052
- }
4053
- /*UPDATE CONTROL DATA WIDGET*/
4054
- eventUpdateWidgetControlData(idWidget, newControlData) {
4055
- //Obtener la referencia del componente almacenada en el Map
4056
- const componentRef = this.widgetsActivos.get(idWidget);
4057
- if (!componentRef) {
4058
- console.warn(`No se encontró un widget activo con el ID: ${idWidget}`);
4059
- return;
4066
+ if (data.type === 'DATE_RANGE') {
4067
+ //console.log('Rango a filtrar en SQL/Dashboard:', data.dateRange?.minDate, 'hasta', data.dateRange?.maxDate);
4068
+ this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: { minDate: data.dateRange?.minDate, maxDate: data.dateRange?.maxDate, currentNodeId: data.currentNodeId } });
4069
+ }
4070
+ else if (data.type === 'TEXT_LEAVES') {
4071
+ //console.log('Lista de elementos terminales seleccionados:', data.leafIds);
4072
+ this.selectionChange.emit({ widgetId: this.componentWidgetId, eventResponse: { ids: data.leafIds, currentNodeId: data.currentNodeId } });
4060
4073
  }
4061
- //Actualizar el Input usando la API oficial setInput
4062
- componentRef.setInput('controlData', newControlData);
4063
- // NOTA: setInput dispara automáticamente la detección de cambios (ChangeDetectionStrategy.OnPush).
4064
- // Si deseas asegurarte manualmente, puedes forzar un render:
4065
- componentRef.changeDetectorRef.detectChanges();
4066
- }
4067
- /****************************************************** */
4068
- /* BEGIN - DRAWER */
4069
- handleShowFormFilterDrawer() {
4070
- this.drawerfiltervisible = true;
4071
4074
  }
4072
- handleCloseFormFilterDrawer() {
4073
- this.drawerfiltervisible = false;
4075
+ onDeleteClick() {
4074
4076
  }
4075
- handleCloseFormDrawer() {
4076
- this.drawerconfigvisible = false;
4077
+ onShowFormConfigClick() {
4077
4078
  }
4078
- fnGetDrawerWidth(prm_percent) {
4079
- const curWidth = window.innerWidth;
4080
- let newWidth = curWidth;
4081
- if (prm_percent) {
4082
- newWidth = Math.floor(curWidth * prm_percent / 100);
4083
- }
4084
- if (newWidth < 400) {
4085
- newWidth = curWidth;
4086
- }
4087
- return newWidth;
4079
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4080
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardFilterWidgetComponent, isStandalone: true, selector: "yw-dashboard-filter-widget", inputs: { configWidget: { classPropertyName: "configWidget", publicName: "configWidget", isSignal: false, isRequired: false, transformFunction: null }, controlConfig: { classPropertyName: "controlConfig", publicName: "controlConfig", isSignal: true, isRequired: false, transformFunction: null }, controlData: { classPropertyName: "controlData", publicName: "controlData", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { eventDeleteRequest: "eventDeleteRequest", eventShowConfigFormRequest: "eventShowConfigFormRequest", selectionChange: "selectionChange" }, ngImport: i0, template: "\r\n<div class=\"widget-filter-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div>\r\n<div class=\"widget-filter-content-wrapper\">\r\n @if ( typeComponent == 'empty-visual' ) { \r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-slicer' ) { \r\n <ng-container *ngTemplateOutlet=\"filterslicer; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-button' ) { \r\n <ng-container *ngTemplateOutlet=\"filterbutton; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-list' ) { \r\n <ng-container *ngTemplateOutlet=\"filterlist; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER SLICER TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterslicer let-control = \"control\"> \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\" \r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\" \r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n @if (control.controlConfig.dataType === 'number') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\"\r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\"\r\n [step]=\"control.controlConfig.step\"\r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER BUTTON TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterbutton let-control = \"control\"> \r\n <yw-button-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [options]=\"control.controlConfig.options\"\r\n [allowMultiple]=\"control.controlConfig.allowMultiple\"\r\n [currentIds]=\"control.controlConfig.currentIds\"\r\n (selectionChange)=\"onFilterButtonChange($event)\" \r\n >\r\n </yw-button-slicer>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER LIST TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterlist let-control = \"control\"> \r\n \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [minDate]=\"control.controlConfig.minDate\"\r\n [maxDate]=\"control.controlConfig.maxDate\"\r\n [dateHierarchyType]=\"control.controlConfig.dateHierarchyType\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n @if (control.controlConfig.dataType === 'text') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\"\r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [rawData]=\"control.controlConfig.rawData\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #040404);border-radius:var(--widget-border-radius, 8px);padding:var(--widget-padding, 10px)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-filter-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-filter-content-wrapper{width:100%;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: YwEmptyVisualComponent, selector: "yw-empty-visual", inputs: ["idComponent", "config"] }, { kind: "component", type: YwBaseSlicerComponent, selector: "yw-base-slicer", inputs: ["idComponent", "dataType", "label", "min", "max", "step", "minCurrent", "maxCurrent"], outputs: ["rangeChange"] }, { kind: "component", type: YwButtonSlicerComponent, selector: "yw-button-slicer", inputs: ["idComponent", "label", "options", "allowMultiple", "currentIds"], outputs: ["selectionChange"] }, { kind: "component", type: YwListSlicerComponent, selector: "yw-list-slicer", inputs: ["idComponent", "label", "clearTitleLabel", "rawData", "dataType", "minDate", "maxDate", "dateHierarchyType", "monthNames", "currentSelectedId"], outputs: ["selectionChange", "filterValueChange"] }] }); }
4081
+ }
4082
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterWidgetComponent, decorators: [{
4083
+ type: Component,
4084
+ args: [{ selector: 'yw-dashboard-filter-widget', standalone: true, imports: [CommonModule,
4085
+ YwEmptyVisualComponent,
4086
+ YwBaseSlicerComponent,
4087
+ YwButtonSlicerComponent,
4088
+ YwListSlicerComponent,
4089
+ ], template: "\r\n<div class=\"widget-filter-action-bar\"> \r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-delete\" (click)=\"onDeleteClick()\">\uD83D\uDDD1\uFE0F</button>\r\n <button [hidden]=\"!varShowConfigButtons\" class=\"btn-config\" (click)=\"onShowFormConfigClick()\">\u2699\uFE0F</button>\r\n</div>\r\n<div class=\"widget-filter-content-wrapper\">\r\n @if ( typeComponent == 'empty-visual' ) { \r\n <ng-container *ngTemplateOutlet=\"emptyvisual; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-slicer' ) { \r\n <ng-container *ngTemplateOutlet=\"filterslicer; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-button' ) { \r\n <ng-container *ngTemplateOutlet=\"filterbutton; context: { control: dataWidget }\"></ng-container>\r\n }\r\n @if ( typeComponent == 'filter-list' ) { \r\n <ng-container *ngTemplateOutlet=\"filterlist; context: { control: dataWidget }\"></ng-container>\r\n } \r\n \r\n</div>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- EMPTY VISUAL TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #emptyvisual let-control = \"control\">\r\n <yw-empty-visual [idComponent]=\"control.idComponent\"\r\n [config]=\"control.controlConfig\" \r\n > \r\n </yw-empty-visual>\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER SLICER TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterslicer let-control = \"control\"> \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\" \r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\" \r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n @if (control.controlConfig.dataType === 'number') { \r\n <yw-base-slicer [idComponent]=\"control.idComponent\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [label]=\"control.configWidget.label\"\r\n [min]=\"control.controlConfig.min\"\r\n [max]=\"control.controlConfig.max\"\r\n [minCurrent]=\"control.controlConfig.minCurrent\"\r\n [maxCurrent]=\"control.controlConfig.maxCurrent\"\r\n [step]=\"control.controlConfig.step\"\r\n (rangeChange)=\"onFilterSlicerChange($event)\"\r\n >\r\n </yw-base-slicer>\r\n }\r\n</ng-template>\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER BUTTON TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterbutton let-control = \"control\"> \r\n <yw-button-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [options]=\"control.controlConfig.options\"\r\n [allowMultiple]=\"control.controlConfig.allowMultiple\"\r\n [currentIds]=\"control.controlConfig.currentIds\"\r\n (selectionChange)=\"onFilterButtonChange($event)\" \r\n >\r\n </yw-button-slicer>\r\n</ng-template>\r\n\r\n\r\n<!--------------------------------------------------------------->\r\n<!---------------------- FILTER LIST TEMPLATE ---------------------->\r\n<!--------------------------------------------------------------->\r\n<ng-template #filterlist let-control = \"control\"> \r\n \r\n @if (control.controlConfig.dataType === 'date') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\" \r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [minDate]=\"control.controlConfig.minDate\"\r\n [maxDate]=\"control.controlConfig.maxDate\"\r\n [dateHierarchyType]=\"control.controlConfig.dateHierarchyType\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n @if (control.controlConfig.dataType === 'text') { \r\n <yw-list-slicer [idComponent]=\"control.idComponent\"\r\n [label]=\"control.configWidget.label\"\r\n [dataType]=\"control.controlConfig.dataType\"\r\n [rawData]=\"control.controlConfig.rawData\"\r\n [currentSelectedId]=\"control.controlConfig.currentSelectedId\"\r\n (selectionChange)=\"onFilterListChange($event)\"\r\n (filterValueChange)=\"onFilterListCalculated($event)\" \r\n >\r\n </yw-list-slicer>\r\n }\r\n\r\n\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;box-sizing:border-box;background-color:var(--widget-bg, #ffffff);border:1px solid var(--widget-border-color, #040404);border-radius:var(--widget-border-radius, 8px);padding:var(--widget-padding, 10px)}:host *,:host *:before,:host *:after{box-sizing:border-box}.widget-filter-action-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%}.widget-filter-content-wrapper{width:100%;display:flex;flex-direction:column}\n"] }]
4090
+ }], ctorParameters: () => [], propDecorators: { configWidget: [{
4091
+ type: Input
4092
+ }], controlConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlConfig", required: false }] }], controlData: [{
4093
+ type: Input
4094
+ }], eventDeleteRequest: [{ type: i0.Output, args: ["eventDeleteRequest"] }], eventShowConfigFormRequest: [{ type: i0.Output, args: ["eventShowConfigFormRequest"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
4095
+
4096
+ class YwDashboardFilterComponent {
4097
+ constructor() {
4098
+ this.dashboardFilterConfig = {
4099
+ showConfigButtons: false,
4100
+ lockPositionWidgets: false,
4101
+ controlListConfig: []
4102
+ };
4103
+ this.dashboardData = [];
4104
+ this.filterSelectionChange = output();
4105
+ this.controlListConfig = [];
4088
4106
  }
4089
- onFilterSelectionChange(eventData) {
4090
- const lsize = this.widgetsActivos.size;
4091
- //Validar que ya se crearon y renderizaron los componentes graficos.
4092
- if (lsize > 0) {
4093
- const currentFilterController = this.dashboardFilterConfig.controlListConfig.find((x) => x.widgetId == eventData['widgetId']);
4094
- if (currentFilterController) {
4095
- currentFilterController.controlFilterData = eventData['eventResponse'];
4096
- this.fnUpdateDataControllerBasedOnFilter(this.dashboardFilterConfig.controlListConfig);
4107
+ ngOnInit() {
4108
+ this.controlListConfig = [];
4109
+ this.dashboardFilterConfig.controlListConfig.forEach((item) => {
4110
+ const tableName = item.controlTable;
4111
+ const prmcontrolData = this.fn_getDataForWidgetFilterComponent(tableName, this.dashboardData);
4112
+ const prmconfigWidget = { ...item };
4113
+ if (item.controlFilterData) {
4114
+ item.configComponent = this.fnSetControlFilterCurrentValues(prmconfigWidget);
4097
4115
  }
4098
- }
4116
+ const configControl = { configWidget: prmconfigWidget,
4117
+ controlData: prmcontrolData,
4118
+ controlConfig: item.configComponent
4119
+ };
4120
+ this.controlListConfig.push(configControl);
4121
+ });
4099
4122
  }
4100
- fnUpdateDataControllerBasedOnFilter(filterControlListConfig) {
4101
- let copyDashboardData = structuredClone(this.dashboardData);
4102
- filterControlListConfig.forEach((item) => {
4103
- let tableSelected = copyDashboardData.find((x) => x.tableName == item.controlTable);
4104
- if (item.typeComponent == 'filter-slicer' && tableSelected && item.controlFilterData) {
4105
- const fieldName = item.configComponent.filterField;
4106
- if (item.configComponent.dataType == 'date') {
4107
- const minDate = item.controlFilterData['startDate'];
4108
- const maxDate = item.controlFilterData['endDate'];
4109
- if (minDate && maxDate) {
4110
- const filterData = tableSelected.tableData.filter((y) => (minDate <= y[fieldName] && y[fieldName] <= maxDate));
4111
- tableSelected.tableData = filterData;
4112
- }
4113
- }
4114
- if (item.configComponent.dataType == 'number') {
4115
- const minNum = Number(item.controlFilterData['minValue']);
4116
- const maxNum = Number(item.controlFilterData['maxValue']);
4117
- if (minNum && maxNum) {
4118
- const filterData = tableSelected.tableData.filter((y) => (minNum <= y[fieldName] && y[fieldName] <= maxNum));
4119
- tableSelected.tableData = filterData;
4120
- }
4121
- }
4122
- }
4123
- if (item.typeComponent == 'filter-button' && tableSelected && item.controlFilterData) {
4124
- const fieldName = item.configComponent.filterField;
4125
- const listValues = item.controlFilterData || [];
4126
- if (listValues && listValues.length > 0) {
4127
- const filterData = tableSelected.tableData.filter((y) => (listValues.includes(y[fieldName])));
4128
- tableSelected.tableData = filterData;
4129
- }
4130
- }
4131
- if (item.typeComponent == 'filter-list' && tableSelected && item.controlFilterData) {
4132
- const fieldName = item.configComponent.filterField;
4133
- if (item.configComponent.dataType == 'text') {
4134
- const listValues = item.controlFilterData['ids'] || [];
4135
- if (listValues && listValues.length > 0) {
4136
- const listValues1D = listValues;
4137
- const filterData = tableSelected.tableData.filter((y) => (listValues1D.includes(y[fieldName])));
4138
- tableSelected.tableData = filterData;
4139
- }
4140
- }
4141
- if (item.configComponent.dataType == 'date') {
4142
- const minDate = item.controlFilterData['minDate'];
4143
- const maxDate = item.controlFilterData['maxDate'];
4144
- if (minDate && maxDate) {
4145
- const filterData = tableSelected.tableData.filter((y) => (minDate <= y[fieldName] && y[fieldName] <= maxDate));
4146
- tableSelected.tableData = filterData;
4147
- }
4148
- }
4123
+ //Filtrar Datos por Componente del Widget
4124
+ fn_getDataForWidgetFilterComponent(prmTableName, prmdashboardData) {
4125
+ let dataresponse = [];
4126
+ const ldsize = prmdashboardData.length;
4127
+ prmdashboardData.forEach((curTableRef) => {
4128
+ if (prmTableName.localeCompare(curTableRef.tableName) == 0) {
4129
+ dataresponse = curTableRef.tableData;
4149
4130
  }
4150
4131
  });
4151
- //Actualizacion de Data Componentes Graficos
4152
- this.dashboardConfig.controlListConfig.forEach((item) => {
4153
- const controlData = this.fn_getDataForWidgetComponent(item.controlTables, copyDashboardData);
4154
- this.eventUpdateWidgetControlData(item.widgetId, controlData);
4155
- });
4132
+ return dataresponse;
4156
4133
  }
4157
- /* END - DRAWER */
4158
- /* BEGIN - Eventos que provienen desde widget */
4159
- eventRemoveWidgetById(widgetId) {
4160
- // 1. Buscar el elemento HTML físico dentro de Gridstack usando su atributo interno [gs-id]
4161
- const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4162
- if (elementoHtml) {
4163
- // 2. Remover el elemento de Gridstack (esto limpia el HTML y reordena el tablero si float es false)
4164
- // El parámetro false indica que remueva el nodo del DOM pero no dispare eventos internos destructivos pesados
4165
- this.grid.removeWidget(elementoHtml, false);
4134
+ onFilterChange(eventData) {
4135
+ this.filterSelectionChange.emit({ widgetId: eventData.widgetId, eventResponse: eventData.eventResponse });
4136
+ }
4137
+ fnSetControlFilterCurrentValues(prmControlConfig) {
4138
+ if (prmControlConfig.typeComponent == 'filter-slicer') {
4139
+ let curConfigComponent = prmControlConfig.configComponent;
4140
+ if (prmControlConfig.configComponent.dataType == 'date') {
4141
+ curConfigComponent.minCurrent = prmControlConfig.controlFilterData['startDate'];
4142
+ curConfigComponent.maxCurrent = prmControlConfig.controlFilterData['endDate'];
4143
+ }
4144
+ if (prmControlConfig.configComponent.dataType == 'number') {
4145
+ curConfigComponent.minCurrent = prmControlConfig.controlFilterData['minValue'];
4146
+ curConfigComponent.maxCurrent = prmControlConfig.controlFilterData['maxValue'];
4147
+ }
4148
+ return curConfigComponent;
4166
4149
  }
4167
- // 3. Buscar y destruir la instancia de Angular en memoria RAM
4168
- const componentRef = this.widgetsActivos.get(widgetId);
4169
- if (componentRef) {
4170
- // Desengancha la vista del ciclo de renderizado global de Angular
4171
- this.appRef.detachView(componentRef.hostView);
4172
- // Destruye el componente y libera la memoria RAM
4173
- componentRef.destroy();
4174
- // Eliminamos el registro de nuestro Mapa
4175
- this.widgetsActivos.delete(widgetId);
4150
+ if (prmControlConfig.typeComponent == 'filter-button') {
4151
+ let curConfigComponent = prmControlConfig.configComponent;
4152
+ curConfigComponent.currentIds = prmControlConfig.controlFilterData || [];
4153
+ return curConfigComponent;
4176
4154
  }
4177
- //console.log(`Widget ${widgetId} eliminado con éxito de Gridstack y Angular.`);
4178
- }
4179
- eventToggleLockWidget(widgetId, shouldLock) {
4180
- const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4181
- if (elementoHtml) {
4182
- // La API de Gridstack nos permite congelar un nodo específico pasándole true/false
4183
- this.grid.movable(elementoHtml, !shouldLock);
4184
- this.grid.resizable(elementoHtml, !shouldLock);
4185
- //console.log(`Widget ${widgetId} cambiado a estado bloqueado: ${shouldLock}`);
4155
+ if (prmControlConfig.typeComponent == 'filter-list') {
4156
+ let curConfigComponent = prmControlConfig.configComponent;
4157
+ curConfigComponent.currentSelectedId = prmControlConfig.controlFilterData['currentNodeId'];
4158
+ return curConfigComponent;
4186
4159
  }
4187
4160
  }
4188
- eventToggleMaximizeWidget(widgetId, shouldMaximize) {
4189
- const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4190
- if (elementoHtml) {
4191
- if (shouldMaximize) {
4192
- // Aplicamos estilos CSS nativos para forzar al contenedor a flotar sobre todo el dashboard
4193
- elementoHtml.classList.add('widget-maximized');
4194
- // Deshabilitamos temporalmente que Gridstack intente moverlo mientras está maximizado
4195
- this.grid.movable(elementoHtml, false);
4196
- this.grid.resizable(elementoHtml, false);
4197
- }
4198
- else {
4199
- elementoHtml.classList.remove('widget-maximized');
4200
- // Restauramos los permisos normales leyendo si el componente de Angular estaba bloqueado previamente
4201
- const componentRef = this.widgetsActivos.get(widgetId);
4202
- const isCurrentlyLocked = componentRef?.instance.isLocked() || false;
4203
- this.grid.movable(elementoHtml, !isCurrentlyLocked);
4204
- this.grid.resizable(elementoHtml, !isCurrentlyLocked);
4161
+ handleClearFilter() {
4162
+ this.controlListConfig = [];
4163
+ this.dashboardFilterConfig.controlListConfig.forEach((item) => {
4164
+ const tableName = item.controlTable;
4165
+ const prmcontrolData = this.fn_getDataForWidgetFilterComponent(tableName, this.dashboardData);
4166
+ const prmconfigWidget = { ...item };
4167
+ if (item.controlFilterData) {
4168
+ item.configComponent = this.fnSetControlFilterClearValues(prmconfigWidget);
4205
4169
  }
4206
- // Forzamos un evento resize simulado para que los gráficos de Syncfusion recalculen su nuevo tamaño gigante/pequeño
4207
- setTimeout(() => {
4208
- window.dispatchEvent(new Event('resize'));
4209
- }, 50);
4210
- }
4170
+ const configControl = { configWidget: prmconfigWidget,
4171
+ controlData: prmcontrolData,
4172
+ controlConfig: item.configComponent
4173
+ };
4174
+ this.controlListConfig.push(configControl);
4175
+ });
4211
4176
  }
4212
- eventShowFormConfigWidget(widgetId) {
4213
- this.drawerCurrentWidgetObject['widgetId'] = widgetId;
4214
- this.drawerconfigvisible = true;
4177
+ fnSetControlFilterClearValues(prmControlConfig) {
4178
+ if (prmControlConfig.typeComponent == 'filter-slicer') {
4179
+ let curConfigComponent = prmControlConfig.configComponent;
4180
+ curConfigComponent.minCurrent = null;
4181
+ curConfigComponent.maxCurrent = null;
4182
+ return curConfigComponent;
4183
+ }
4184
+ if (prmControlConfig.typeComponent == 'filter-button') {
4185
+ let curConfigComponent = prmControlConfig.configComponent;
4186
+ curConfigComponent.currentIds = [];
4187
+ return curConfigComponent;
4188
+ }
4189
+ if (prmControlConfig.typeComponent == 'filter-list') {
4190
+ let curConfigComponent = prmControlConfig.configComponent;
4191
+ curConfigComponent.currentSelectedId = null;
4192
+ return curConfigComponent;
4193
+ }
4215
4194
  }
4216
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardComponent, deps: [{ token: i0.EnvironmentInjector }, { token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component }); }
4217
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardComponent, isStandalone: true, selector: "yw-dashboard", inputs: { showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: false, transformFunction: null }, showFilter: { classPropertyName: "showFilter", publicName: "showFilter", isSignal: true, isRequired: false, transformFunction: null }, dashboardStyle: { classPropertyName: "dashboardStyle", publicName: "dashboardStyle", isSignal: false, isRequired: false, transformFunction: null }, dashboardConfig: { classPropertyName: "dashboardConfig", publicName: "dashboardConfig", isSignal: false, isRequired: false, transformFunction: null }, dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: false, isRequired: false, transformFunction: null }, dashboardFilterConfig: { classPropertyName: "dashboardFilterConfig", publicName: "dashboardFilterConfig", isSignal: false, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "gridContainer", first: true, predicate: ["gridContainer"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- <div class=\"controls\" [hidden]=\"!showControls()\">\r\n <button (click)=\"saveLayoutToJSON()\">Guardar JSON en Consola</button>\r\n <button (click)=\"fn_btn_addWidget()\">add widget</button>\r\n <button (click)=\"fn_btn_lockPositionWidgets()\">Lock widgets</button>\r\n <button (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\">\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n</div> -->\r\n\r\n<div class=\"controls-container\" >\r\n @if ( showControls() ) { \r\n <!-- Botones principales con nz-button y tipos de Ant Design -->\r\n <button nz-button nzType=\"default\" (click)=\"saveLayoutToJSON()\" >\r\n <span nz-icon nz-type=\"code\"></span> Guardar JSON\r\n </button>\r\n\r\n <button nz-button nzType=\"primary\" (click)=\"fn_btn_addWidget()\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n\r\n <button nz-button [nzType]=\"isLocked ? 'primary' : 'default'\" nzDanger (click)=\"fn_btn_lockPositionWidgets()\" >\r\n <span nz-icon [nzType]=\"isLocked ? 'lock' : 'unlock'\"></span> \r\n {{ isLocked ? 'Bloqueado' : 'Bloquear' }}\r\n </button>\r\n }\r\n @if ( showFilter() ) { \r\n <!-- Bot\u00F3n de filtro con estilo ic\u00F3nico -->\r\n <button nz-button nzType=\"default\" nzShape=\"circle\" (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\" [class.active]=\"drawerfiltervisible\" >\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n }\r\n</div>\r\n<div #gridContainer class=\"grid-stack canvas-container\"\r\n [style.--canvas-bg]=\"dashboardStyle.canvasBackgroundColor\"\r\n></div>\r\n\r\n\r\n\r\n\r\n<!-- DRAWER - FILTER -->\r\n\r\n<nz-drawer\r\n[nzVisible]=\"drawerfiltervisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormFilterDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>Filtros</h6>\r\n <yw-dashboard-filter\r\n [dashboardFilterConfig]=\"dashboardFilterConfig\"\r\n [dashboardData]=\"dashboardData\"\r\n (filterSelectionChange)=\"onFilterSelectionChange($event)\"\r\n >\r\n </yw-dashboard-filter>\r\n </div>\r\n\r\n <!--\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"Secion de Filtros\">\r\n <div class=\"controls\">\r\n aqui botones de control:\r\n\r\n </div>\r\n <div>\r\n \r\n\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n-->\r\n</ng-container>\r\n</nz-drawer>\r\n\r\n\r\n\r\n<!-- DRAWER - CONFIGURACION -->\r\n<nz-drawer\r\n[nzVisible]=\"drawerconfigvisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>{{ drawerCurrentWidgetObject.widgetId }}</h6>\r\n </div>\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"{{ drawerCurrentWidgetObject.widgetId }}\">\r\n <div class=\"controls\">\r\n <button (click)=\"fn_btn_updateWidgetControlConfig(drawerCurrentWidgetObject.widgetId)\">Actualiza Configuracion</button>\r\n <button (click)=\"fn_btn_updateWidgetControlData(drawerCurrentWidgetObject.widgetId)\">Actualiza Data</button> \r\n </div>\r\n <div>\r\n bla bla bla\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n</ng-container>\r\n</nz-drawer>", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.canvas-container{background-color:var(--canvas-bg, #f5f5f5);min-height:500px;padding:10px}::vdeep .card-inner{background:#fff;border:1px solid #ccc;height:100%;display:flex;align-items:center;justify-content:center}:host ::ng-deep .grid-stack-item-content{border-radius:6px;box-shadow:0 2px 5px #0000001a;display:flex;align-items:center;justify-content:center;font-weight:700;overflow:hidden}::ng-deep .grid-stack-item.widget-maximized{position:fixed!important;top:0!important;left:0!important;width:100vw!important;height:100vh!important;z-index:9999!important;transform:none!important;margin:0!important;padding:5px}::ng-deep .grid-stack-item.widget-maximized .grid-stack-item-content{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;margin:0!important;padding:0!important;border:none!important;border-radius:0!important;box-shadow:none!important;background-color:#fff!important;overflow:hidden}::ng-deep .grid-stack>.grid-stack-item>.ui-resizable-handle{opacity:0!important;background-image:none!important}.widget-details-info{padding-top:30px;text-align:center}.widget-details-info h6{font-family:manrope,sans-serif;font-size:20px;font-weight:700;line-height:26px;color:#2d3144}.widget-details-info p{font-family:manrope,sans-serif;font-size:14px;font-weight:400;line-height:21px;color:#4b5064}.controls-container{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #f0f0f0;box-shadow:0 2px 8px #0000000a;border-radius:6px;margin-bottom:16px;width:100%;box-sizing:border-box}.controls-container button{white-space:nowrap}.controls-container .btn-filtro{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.controls-container .btn-filtro.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.controls-container .btn-filtro.active:hover{background-color:#40a9ff;border-color:#40a9ff}@media(max-width:576px){.controls-container{gap:8px;padding:8px 10px}.controls-container button[nz-button]{font-size:13px;padding:0 10px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i2.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i2.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTabsModule }, { kind: "component", type: i3.NzTabsComponent, selector: "nz-tabs,nz-tabset", inputs: ["nzSelectedIndex", "nzTabPosition", "nzTabBarExtraContent", "nzCanDeactivate", "nzAddIcon", "nzTabBarStyle", "nzType", "nzSize", "nzAnimated", "nzTabBarGutter", "nzHideAdd", "nzCentered", "nzHideAll", "nzLinkRouter", "nzLinkExact", "nzDestroyInactiveTabPane"], outputs: ["nzSelectChange", "nzSelectedIndexChange", "nzTabListScroll", "nzClose", "nzAdd"], exportAs: ["nzTabs"] }, { kind: "component", type: i3.NzTabComponent, selector: "nz-tab", inputs: ["nzTitle", "nzClosable", "nzCloseIcon", "nzDisabled", "nzForceRender"], outputs: ["nzSelect", "nzDeselect", "nzClick", "nzContextmenu"], exportAs: ["nzTab"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i5.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i6.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i7.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "component", type: YwDashboardFilterComponent, selector: "yw-dashboard-filter", inputs: ["dashboardFilterConfig", "dashboardData"], outputs: ["filterSelectionChange"] }] }); }
4195
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4196
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardFilterComponent, isStandalone: true, selector: "yw-dashboard-filter", inputs: { dashboardFilterConfig: "dashboardFilterConfig", dashboardData: "dashboardData" }, outputs: { filterSelectionChange: "filterSelectionChange" }, ngImport: i0, template: "\r\n <div class=\"dashboard-filter-content-bar\">\r\n @if ( dashboardFilterConfig.showConfigButtons ) { \r\n <button nz-button nzType=\"primary\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n }\r\n <button nz-button \r\n nzType=\"default\" \r\n nzShape=\"circle\" \r\n (click)=\"handleClearFilter()\" \r\n class=\"btn-clean\" \r\n > \r\n <!-- Icono de Borrador (Eraser) activo / relleno --> \r\n <svg \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M16.24 3.56a2.12 2.12 0 0 1 3 0l1.2 1.2a2.12 2.12 0 0 1 0 3l-8.5 8.5H6.5a1.5 1.5 0 0 1-1.5-1.5v-5.44l11.24-11.24zM19 19H5a1 1 0 0 1 0-2h14a1 1 0 0 1 0 2z\"/>\r\n </svg>\r\n \r\n </button>\r\n </div>\r\n\r\n <div class=\"dashboard-filter-content-wrapper\">\r\n @for ( colFilter of controlListConfig; track colFilter) { \r\n <div class=\"dashboard-filter-content-wrapper-item\">\r\n \r\n <yw-dashboard-filter-widget \r\n [configWidget]=\"colFilter.configWidget\"\r\n [controlConfig]=\"colFilter.controlConfig\"\r\n [controlData]=\"colFilter.controlData\"\r\n (selectionChange)=\"onFilterChange($event)\"\r\n > \r\n </yw-dashboard-filter-widget>\r\n\r\n </div>\r\n }\r\n </div>", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.dashboard-filter-content-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%;box-sizing:border-box}.dashboard-filter-content-wrapper{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;width:100%;display:flex;flex-direction:column;box-sizing:border-box}.dashboard-filter-content-wrapper-item{padding-bottom:5px}.btn-clean{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.btn-clean.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.btn-clean.active:hover{background-color:#40a9ff;border-color:#40a9ff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: YwDashboardFilterWidgetComponent, selector: "yw-dashboard-filter-widget", inputs: ["configWidget", "controlConfig", "controlData"], outputs: ["eventDeleteRequest", "eventShowConfigFormRequest", "selectionChange"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i5.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i6.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i7.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }] }); }
4218
4197
  }
4219
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardComponent, decorators: [{
4198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardFilterComponent, decorators: [{
4220
4199
  type: Component,
4221
- args: [{ selector: 'yw-dashboard', standalone: true, imports: [CommonModule,
4222
- YwDashboardWidgetComponent,
4223
- NzDrawerModule,
4224
- NzTabsModule,
4225
- YwBaseSlicerComponent,
4200
+ args: [{ selector: 'yw-dashboard-filter', standalone: true, imports: [CommonModule,
4201
+ YwDashboardFilterWidgetComponent,
4226
4202
  NzIconModule,
4227
4203
  NzButtonModule,
4228
- YwButtonSlicerComponent,
4229
- YwListSlicerComponent,
4230
- YwDashboardFilterComponent
4231
- ], template: "<!-- <div class=\"controls\" [hidden]=\"!showControls()\">\r\n <button (click)=\"saveLayoutToJSON()\">Guardar JSON en Consola</button>\r\n <button (click)=\"fn_btn_addWidget()\">add widget</button>\r\n <button (click)=\"fn_btn_lockPositionWidgets()\">Lock widgets</button>\r\n <button (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\">\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n</div> -->\r\n\r\n<div class=\"controls-container\" >\r\n @if ( showControls() ) { \r\n <!-- Botones principales con nz-button y tipos de Ant Design -->\r\n <button nz-button nzType=\"default\" (click)=\"saveLayoutToJSON()\" >\r\n <span nz-icon nz-type=\"code\"></span> Guardar JSON\r\n </button>\r\n\r\n <button nz-button nzType=\"primary\" (click)=\"fn_btn_addWidget()\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n\r\n <button nz-button [nzType]=\"isLocked ? 'primary' : 'default'\" nzDanger (click)=\"fn_btn_lockPositionWidgets()\" >\r\n <span nz-icon [nzType]=\"isLocked ? 'lock' : 'unlock'\"></span> \r\n {{ isLocked ? 'Bloqueado' : 'Bloquear' }}\r\n </button>\r\n }\r\n @if ( showFilter() ) { \r\n <!-- Bot\u00F3n de filtro con estilo ic\u00F3nico -->\r\n <button nz-button nzType=\"default\" nzShape=\"circle\" (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\" [class.active]=\"drawerfiltervisible\" >\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n }\r\n</div>\r\n<div #gridContainer class=\"grid-stack canvas-container\"\r\n [style.--canvas-bg]=\"dashboardStyle.canvasBackgroundColor\"\r\n></div>\r\n\r\n\r\n\r\n\r\n<!-- DRAWER - FILTER -->\r\n\r\n<nz-drawer\r\n[nzVisible]=\"drawerfiltervisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormFilterDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>Filtros</h6>\r\n <yw-dashboard-filter\r\n [dashboardFilterConfig]=\"dashboardFilterConfig\"\r\n [dashboardData]=\"dashboardData\"\r\n (filterSelectionChange)=\"onFilterSelectionChange($event)\"\r\n >\r\n </yw-dashboard-filter>\r\n </div>\r\n\r\n <!--\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"Secion de Filtros\">\r\n <div class=\"controls\">\r\n aqui botones de control:\r\n\r\n </div>\r\n <div>\r\n \r\n\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n-->\r\n</ng-container>\r\n</nz-drawer>\r\n\r\n\r\n\r\n<!-- DRAWER - CONFIGURACION -->\r\n<nz-drawer\r\n[nzVisible]=\"drawerconfigvisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>{{ drawerCurrentWidgetObject.widgetId }}</h6>\r\n </div>\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"{{ drawerCurrentWidgetObject.widgetId }}\">\r\n <div class=\"controls\">\r\n <button (click)=\"fn_btn_updateWidgetControlConfig(drawerCurrentWidgetObject.widgetId)\">Actualiza Configuracion</button>\r\n <button (click)=\"fn_btn_updateWidgetControlData(drawerCurrentWidgetObject.widgetId)\">Actualiza Data</button> \r\n </div>\r\n <div>\r\n bla bla bla\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n</ng-container>\r\n</nz-drawer>", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.canvas-container{background-color:var(--canvas-bg, #f5f5f5);min-height:500px;padding:10px}::vdeep .card-inner{background:#fff;border:1px solid #ccc;height:100%;display:flex;align-items:center;justify-content:center}:host ::ng-deep .grid-stack-item-content{border-radius:6px;box-shadow:0 2px 5px #0000001a;display:flex;align-items:center;justify-content:center;font-weight:700;overflow:hidden}::ng-deep .grid-stack-item.widget-maximized{position:fixed!important;top:0!important;left:0!important;width:100vw!important;height:100vh!important;z-index:9999!important;transform:none!important;margin:0!important;padding:5px}::ng-deep .grid-stack-item.widget-maximized .grid-stack-item-content{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;margin:0!important;padding:0!important;border:none!important;border-radius:0!important;box-shadow:none!important;background-color:#fff!important;overflow:hidden}::ng-deep .grid-stack>.grid-stack-item>.ui-resizable-handle{opacity:0!important;background-image:none!important}.widget-details-info{padding-top:30px;text-align:center}.widget-details-info h6{font-family:manrope,sans-serif;font-size:20px;font-weight:700;line-height:26px;color:#2d3144}.widget-details-info p{font-family:manrope,sans-serif;font-size:14px;font-weight:400;line-height:21px;color:#4b5064}.controls-container{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #f0f0f0;box-shadow:0 2px 8px #0000000a;border-radius:6px;margin-bottom:16px;width:100%;box-sizing:border-box}.controls-container button{white-space:nowrap}.controls-container .btn-filtro{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.controls-container .btn-filtro.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.controls-container .btn-filtro.active:hover{background-color:#40a9ff;border-color:#40a9ff}@media(max-width:576px){.controls-container{gap:8px;padding:8px 10px}.controls-container button[nz-button]{font-size:13px;padding:0 10px}}\n"] }]
4232
- }], ctorParameters: () => [{ type: i0.EnvironmentInjector }, { type: i0.ApplicationRef }], propDecorators: { gridContainer: [{
4233
- type: ViewChild,
4234
- args: ['gridContainer', { static: true }]
4235
- }], showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: false }] }], showFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilter", required: false }] }], dashboardStyle: [{
4236
- type: Input
4237
- }], dashboardConfig: [{
4204
+ ], template: "\r\n <div class=\"dashboard-filter-content-bar\">\r\n @if ( dashboardFilterConfig.showConfigButtons ) { \r\n <button nz-button nzType=\"primary\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n }\r\n <button nz-button \r\n nzType=\"default\" \r\n nzShape=\"circle\" \r\n (click)=\"handleClearFilter()\" \r\n class=\"btn-clean\" \r\n > \r\n <!-- Icono de Borrador (Eraser) activo / relleno --> \r\n <svg \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M16.24 3.56a2.12 2.12 0 0 1 3 0l1.2 1.2a2.12 2.12 0 0 1 0 3l-8.5 8.5H6.5a1.5 1.5 0 0 1-1.5-1.5v-5.44l11.24-11.24zM19 19H5a1 1 0 0 1 0-2h14a1 1 0 0 1 0 2z\"/>\r\n </svg>\r\n \r\n </button>\r\n </div>\r\n\r\n <div class=\"dashboard-filter-content-wrapper\">\r\n @for ( colFilter of controlListConfig; track colFilter) { \r\n <div class=\"dashboard-filter-content-wrapper-item\">\r\n \r\n <yw-dashboard-filter-widget \r\n [configWidget]=\"colFilter.configWidget\"\r\n [controlConfig]=\"colFilter.controlConfig\"\r\n [controlData]=\"colFilter.controlData\"\r\n (selectionChange)=\"onFilterChange($event)\"\r\n > \r\n </yw-dashboard-filter-widget>\r\n\r\n </div>\r\n }\r\n </div>", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.dashboard-filter-content-bar{display:flex;justify-content:flex-end;gap:4px;padding:5px 10px;flex-shrink:0;width:100%;box-sizing:border-box}.dashboard-filter-content-wrapper{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;width:100%;display:flex;flex-direction:column;box-sizing:border-box}.dashboard-filter-content-wrapper-item{padding-bottom:5px}.btn-clean{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.btn-clean.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.btn-clean.active:hover{background-color:#40a9ff;border-color:#40a9ff}\n"] }]
4205
+ }], ctorParameters: () => [], propDecorators: { dashboardFilterConfig: [{
4238
4206
  type: Input
4239
4207
  }], dashboardData: [{
4240
4208
  type: Input
4241
- }], dashboardFilterConfig: [{
4242
- type: Input
4243
- }] } });
4209
+ }], filterSelectionChange: [{ type: i0.Output, args: ["filterSelectionChange"] }] } });
4244
4210
 
4245
- const parseSyncFusionData = (allTablesData, configData_) => {
4246
- if (!allTablesData || !configData_) {
4247
- return { series: [], labelData: {} };
4211
+ /* END - FILTROS */
4212
+ class YwDashboardComponent {
4213
+ /* */
4214
+ constructor(environmentInjector, appRef) {
4215
+ //Configurar Bloqueo de Widgets
4216
+ /*
4217
+ effect(() => {
4218
+ const isLocked = this.allIsLocked();
4219
+ console.log('El estado de bloqueo cambió a:', isLocked);
4220
+ this.fn_lockPositionWidgets(isLocked);
4221
+ });
4222
+ */
4223
+ this.environmentInjector = environmentInjector;
4224
+ this.appRef = appRef;
4225
+ this.widgetsActivos = new Map();
4226
+ this.showControls = input(false, ...(ngDevMode ? [{ debugName: "showControls" }] : []));
4227
+ this.showFilter = input(false, ...(ngDevMode ? [{ debugName: "showFilter" }] : []));
4228
+ this.allIsLocked = signal(false, ...(ngDevMode ? [{ debugName: "allIsLocked" }] : []));
4229
+ this.drawerfiltervisible = false;
4230
+ this.drawerconfigvisible = false;
4231
+ this.drawerCurrentWidgetObject = {};
4232
+ this.isLocked = false;
4233
+ this.countWidget = 1;
4234
+ this.layoutConfig = {
4235
+ margin: 10,
4236
+ cellHeight: 100,
4237
+ columns: 24
4238
+ };
4239
+ /* ejemplo de Items
4240
+ items: [
4241
+ { id: 'div-1', x: 0, y: 0, w: 14, h: 2, content: 'DIV 1' , contentData : {}},
4242
+ { id: 'div-2', x: 5, y: 2, w: 19, h: 1, content: 'DIV 2' , contentData : {}},
4243
+ { id: 'div-3', x: 0, y: 3, w: 22, h: 1, content: 'DIV 3', contentData : {} }
4244
+ ]
4245
+ */
4246
+ this.dashboardStyle = {
4247
+ canvasBackgroundColor: "#f5f5f5",
4248
+ widgetBackgroundColor: "#ffffff",
4249
+ widgetBorderColor: "#007bff"
4250
+ };
4251
+ this.dashboardConfig = {
4252
+ showConfigButtons: false,
4253
+ lockPositionWidgets: false,
4254
+ layoutConfig: {
4255
+ margin: 0,
4256
+ cellHeight: 0,
4257
+ columns: 0
4258
+ },
4259
+ controlListConfig: []
4260
+ };
4261
+ this.dashboardData = [];
4262
+ this.dashboardItems = [];
4263
+ /* REF FILTROS */
4264
+ this.dashboardFilterConfig = {
4265
+ showConfigButtons: false,
4266
+ lockPositionWidgets: false,
4267
+ controlListConfig: []
4268
+ };
4248
4269
  }
4249
- console.log("bubble data:--", allTablesData, configData_);
4250
- // SI LO MANDAN COMO UN ARREGLO PLANO, LO ENVOLVEMOS AUTOMÁTICAMENTE
4251
- if (Array.isArray(allTablesData)) {
4252
- const defaultTableName = configData_?.configData?.table || 'default';
4253
- allTablesData = { [defaultTableName]: allTablesData };
4270
+ ngOnInit() {
4271
+ // console.log("DATA QUE LLEGA AL DASHBOARD:",this.dashboardConfig)
4254
4272
  }
4255
- const { ruleColorPoint, configData, xLabelText, yLabelText, title, chartoColoredLine, opacity, emptyPointSettings } = configData_;
4256
- console.log("configData_:.::", configData_);
4257
- const cfg = configData || {};
4258
- const { xAxis, yAxis, joins, configJoins, table, serie, tooltip, legends } = cfg;
4259
- let series = [];
4260
- // Función auxiliar robusta para obtener propiedades (soporta notación con puntos de los joins)
4261
- // const getNestedValue = (obj: any, path: string) => {
4262
- // if (!obj || !path) return undefined;
4263
- // if (obj[path] !== undefined) return obj[path];
4264
- // return path.split('.').reduce((acc, part) => (acc && acc[part] !== undefined ? acc[part] : undefined), obj);
4265
- // };
4266
- const sortByXAxis = (data) => {
4267
- if (!xAxis)
4268
- return data;
4269
- return [...data].sort((a, b) => {
4270
- const aValue = getNestedValue(a, xAxis);
4271
- const bValue = getNestedValue(b, xAxis);
4272
- if (aValue == null)
4273
- return 1;
4274
- if (bValue == null)
4275
- return -1;
4276
- return String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' });
4277
- });
4278
- };
4279
- if (joins === true) {
4280
- if (!configJoins) {
4281
- series = [];
4273
+ ngOnChanges(changes) {
4274
+ if (changes['dashboardConfig']) {
4275
+ console.log('Nuevo valor dashboardConfig:', this.dashboardConfig);
4276
+ //this.initCanvasGrid();
4277
+ }
4278
+ if (changes['dashboardData']) {
4279
+ console.log('Nuevo valor dashboardData:', this.dashboardData);
4280
+ //this.initCanvasGrid();
4281
+ }
4282
+ }
4283
+ ngAfterViewInit() {
4284
+ this.initCanvasGrid();
4285
+ }
4286
+ initCanvasGrid() {
4287
+ this.layoutConfig = this.dashboardConfig.layoutConfig;
4288
+ // Opciones para restringir colisiones y comportamiento
4289
+ let options = {
4290
+ column: this.layoutConfig.columns,
4291
+ cellHeight: this.layoutConfig.cellHeight,
4292
+ margin: this.layoutConfig.margin,
4293
+ float: true, // Evita que los divs floten automáticamente hacia arriba
4294
+ //noOverlap: true, // CLAVE: Bloquea el movimiento si colisiona con otro DIV
4295
+ resizable: { handles: 'e, se, s, sw, w, nw, n, ne', autoHide: true } // Permite redimensionar desde todos los bordes
4296
+ };
4297
+ if (this.layoutConfig.columnOpts) {
4298
+ options = {
4299
+ column: this.layoutConfig.columns,
4300
+ cellHeight: this.layoutConfig.cellHeight,
4301
+ margin: this.layoutConfig.margin,
4302
+ columnOpts: {
4303
+ breakpointForWindow: this.layoutConfig.columnOpts.breakpointForWindow, // Mide el ancho de la ventana gráfica
4304
+ breakpoints: this.layoutConfig.columnOpts.breakpoints,
4305
+ layout: this.layoutConfig.columnOpts.layout || 'list', // Mantiene el orden de los widgets secuencialmente al colapsar
4306
+ },
4307
+ float: true, // Evita que los divs floten automáticamente hacia arriba
4308
+ //noOverlap: true, // CLAVE: Bloquea el movimiento si colisiona con otro DIV
4309
+ resizable: { handles: 'e, se, s, sw, w, nw, n, ne', autoHide: true } // Permite redimensionar desde todos los bordes
4310
+ };
4282
4311
  }
4283
- else {
4284
- const unifiedTable = resolveJoinedTableData(allTablesData, configJoins);
4285
- console.log('unifiedTable bubble', unifiedTable);
4286
- if (unifiedTable && unifiedTable.length > 0) {
4287
- // const validRawData = unifiedTable.filter(
4288
- // (item: any) =>
4289
- // item &&
4290
- // xAxis &&
4291
- // getNestedValue(item, xAxis) !== undefined &&
4292
- // getNestedValue(item, xAxis) !== null,
4293
- // );
4294
- const validRawData = unifiedTable.filter((item) => item &&
4295
- xAxis &&
4296
- getNestedValue(item, xAxis) !== undefined &&
4297
- getNestedValue(item, xAxis) !== null);
4298
- const orderedRawData = sortByXAxis(validRawData);
4299
- if (orderedRawData.length > 0) {
4300
- if (serie) {
4301
- // 2. Agrupamos los datos por el valor de la serie (ej. sucursal o vendedor)
4302
- const groupedBySerie = orderedRawData.reduce((acc, item) => {
4303
- const serieVal = getNestedValue(item, serie);
4304
- const serieKey = serieVal !== undefined && serieVal !== null
4305
- ? String(serieVal)
4306
- : 'Desconocido';
4307
- if (!acc[serieKey]) {
4308
- acc[serieKey] = [];
4309
- }
4310
- acc[serieKey].push(item);
4311
- return acc;
4312
- }, {});
4313
- series = Object.entries(groupedBySerie).map(([serieName, groupItems]) => {
4314
- const orderedGroupItems = [...groupItems].sort((a, b) => {
4315
- const aValue = getNestedValue(a, xAxis);
4316
- const bValue = getNestedValue(b, xAxis);
4317
- return String(aValue).localeCompare(String(bValue), undefined, {
4318
- numeric: true,
4319
- sensitivity: 'base'
4320
- });
4321
- });
4322
- console.log("SERIES NAME:", orderedGroupItems);
4323
- const dataSource = orderedGroupItems.map((item) => {
4324
- const rawVal = getNestedValue(item, yAxis);
4325
- const valorFinal = rawVal !== undefined
4326
- ? typeof rawVal === 'number'
4327
- ? rawVal
4328
- : Number(rawVal) || 0
4329
- : 0;
4330
- const sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
4331
- return {
4332
- x: String(getNestedValue(item, xAxis)),
4333
- y: valorFinal,
4334
- size: sizeFinal,
4335
- name: String(getNestedValue(item, xAxis)),
4336
- // ...(chartoColoredLine
4337
- // ? { color: getRandomProfessionalHex() }
4338
- // : {})
4339
- };
4340
- });
4341
- return {
4342
- name: serieName === 'default' ? 'Serie 1' : serieName,
4343
- dataSource,
4344
- opacity: opacity,
4345
- emptyPointSettings: emptyPointSettings
4346
- // dashArray: dashArray !== undefined ? dashArray : undefined,
4347
- // width: width !== undefined ? width : undefined,
4348
- // widthLine: widthLine !== undefined ? widthLine : undefined,
4349
- };
4350
- });
4351
- }
4352
- else {
4353
- const dataSource = orderedRawData.map((item) => {
4354
- let valorFinal = 0;
4355
- let sizeFinal = 0;
4356
- // const shouldColorLine = chartoColoredLine;
4357
- const rawVal = getNestedValue(item, yAxis);
4358
- // const rawSize = getNestedValue(item, size); // <--- Extraer el valor real
4359
- if (rawVal !== undefined) {
4360
- valorFinal = typeof rawVal === 'number' ? rawVal : Number(rawVal) || 0;
4361
- }
4362
- // if (rawSize !== undefined) {
4363
- sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
4364
- // }
4365
- return {
4366
- x: String(getNestedValue(item, xAxis)),
4367
- y: valorFinal,
4368
- size: sizeFinal, // <--- Valor numérico extraído
4369
- name: String(getNestedValue(item, xAxis)),
4370
- // ...(shouldColorLine ? { color: getRandomProfessionalHex() } : {})
4371
- };
4372
- });
4373
- series = [
4374
- {
4375
- name: xAxis.split(".")[0] && xAxis !== 'default' ? xAxis.split(".")[0] : 'Serie Join',
4376
- dataSource: dataSource,
4377
- opacity: opacity,
4378
- emptyPointSettings: emptyPointSettings
4379
- // dashArray: dashArray !== undefined ? dashArray : undefined,
4380
- // width: width !== undefined ? width : undefined,
4381
- // widthLine: widthLine !== undefined ? widthLine : undefined,
4382
- }
4383
- ];
4312
+ /*EXAMPLE OF "columnOpts"
4313
+ columnOpts: {
4314
+ breakpointForWindow: true,
4315
+ breakpoints: [
4316
+ { w: 768, c: 1 },
4317
+ { w: 992, c: 6 },
4318
+ { w: 1200, c: this.layoutConfig.columns } // 👈 Usa tu variable para consistencia en Desktop
4319
+ ],
4320
+ layout: 'list'
4384
4321
  }
4385
- }
4386
- }
4322
+ */
4323
+ // Inicializar el canvas
4324
+ this.grid = GridStack.init(options, this.gridContainer.nativeElement);
4325
+ // Cargar los elementos iniciales desde el JSON
4326
+ //this.loadLayoutFromJSON(this.dashboardItems);
4327
+ this.loadLayoutFromJSON(this.dashboardConfig, this.dashboardStyle);
4328
+ //Evaluar Bloqueo de Widgets en Inicializacion
4329
+ if (this.dashboardConfig.lockPositionWidgets) {
4330
+ this.fn_lockPositionWidgets(this.dashboardConfig.lockPositionWidgets);
4387
4331
  }
4332
+ // Listener para detectar cambios y actualizar el JSON
4333
+ this.grid.on('change', (event, items) => {
4334
+ this.saveLayoutToJSON();
4335
+ });
4336
+ //Listener para detectar cuando cambia las dimenciones de un widget
4337
+ this.grid.on('resizestop', (event, el) => {
4338
+ // Disparamos el evento nativo del navegador de forma controlada
4339
+ window.dispatchEvent(new Event('resize'));
4340
+ });
4388
4341
  }
4389
- else {
4390
- let normalizedTables = [];
4391
- if (Array.isArray(table)) {
4392
- normalizedTables = table.filter((t) => typeof t === 'string' && t.trim() !== '');
4342
+ //Filtrar Datos por Componente del Widget
4343
+ fn_getDataForWidgetComponent(listTables, prmDashboardData) {
4344
+ let dataresponse = new Map();
4345
+ const ldsize = prmDashboardData.length;
4346
+ const ltsize = listTables.length;
4347
+ if (ltsize > 0) {
4348
+ listTables.forEach((curTableName) => {
4349
+ prmDashboardData.forEach((curTableRef) => {
4350
+ if (curTableName.localeCompare(curTableRef.tableName) == 0) {
4351
+ dataresponse.set(curTableRef.tableName, curTableRef.tableData);
4352
+ }
4353
+ });
4354
+ });
4393
4355
  }
4394
- else if (typeof table === 'string' && table.trim() !== '') {
4395
- normalizedTables = [table];
4356
+ else {
4357
+ prmDashboardData.forEach((curTableRef) => {
4358
+ dataresponse.set(curTableRef.tableName, curTableRef.tableData);
4359
+ });
4360
+ }
4361
+ const object_base_response = Object.fromEntries(dataresponse);
4362
+ return object_base_response;
4363
+ }
4364
+ fn_getDataForWidgetComponent_back(listTables) {
4365
+ let dataresponse = [];
4366
+ const ldsize = this.dashboardData.length;
4367
+ const ltsize = listTables.length;
4368
+ if (ltsize > 0) {
4369
+ listTables.forEach((curTableName) => {
4370
+ this.dashboardData.forEach((curTableData) => {
4371
+ if (curTableName.localeCompare(curTableData.tableName) == 0) {
4372
+ dataresponse.push(curTableData);
4373
+ }
4374
+ });
4375
+ });
4396
4376
  }
4397
4377
  else {
4398
- normalizedTables = Object.keys(allTablesData);
4378
+ return this.dashboardData;
4399
4379
  }
4400
- series = normalizedTables
4401
- .map((tableName) => {
4402
- const rawData = (allTablesData && allTablesData[tableName]) ? allTablesData[tableName] : [];
4403
- if (!rawData || rawData.length === 0)
4404
- return null;
4405
- const orderedRawData = rawData.filter((item) => item && xAxis && getNestedValue(item, xAxis) !== undefined && getNestedValue(item, xAxis) !== null);
4406
- if (orderedRawData.length === 0)
4407
- return null;
4408
- const dataSource = orderedRawData.map((item) => {
4409
- let valorFinal = 0;
4410
- let sizeFinal = 0;
4411
- const shouldColorLine = chartoColoredLine;
4412
- const rawVal = getNestedValue(item, yAxis);
4413
- // const rawSize = getNestedValue(item, size);
4414
- if (rawVal !== undefined) {
4415
- valorFinal = typeof rawVal === "number" ? rawVal : Number(rawVal) || 0;
4380
+ return dataresponse;
4381
+ }
4382
+ // Carga elementos desde la configuración JSON
4383
+ //public loadLayoutFromJSON(dashboardItems: YwWidgetLayoutInterface[], ): void {
4384
+ loadLayoutFromJSON(prmDashboardConfig, prmDashboardStyle) {
4385
+ this.grid.removeAll();
4386
+ const widgets = [];
4387
+ this.grid.load(widgets);
4388
+ const lsize = prmDashboardConfig.controlListConfig.length;
4389
+ if (lsize > 0) {
4390
+ prmDashboardConfig.controlListConfig.forEach((widgetConfig) => {
4391
+ //Agregar uno por uno, para poder cargar los parametros internos de los componentes.
4392
+ const controlData = this.fn_getDataForWidgetComponent(widgetConfig.controlTables, this.dashboardData);
4393
+ //Sobre Escribir el ID Correcto en Layaout
4394
+ widgetConfig.layoutConfig.id = widgetConfig.widgetId;
4395
+ //Evaluar Mostrar Eventos
4396
+ if (widgetConfig.showConfigButtons == null || widgetConfig.showConfigButtons == undefined) {
4397
+ widgetConfig.showConfigButtons = prmDashboardConfig.showConfigButtons;
4416
4398
  }
4417
- // if (rawSize !== undefined) {
4418
- sizeFinal = Math.abs(valorFinal) !== 0 ? Math.abs(valorFinal) * 0.05 : 0;
4419
- // }
4420
- return {
4421
- x: String(getNestedValue(item, xAxis)),
4422
- y: valorFinal,
4423
- size: sizeFinal, // <--- Valor numérico extraído
4424
- name: String(getNestedValue(item, xAxis))
4425
- // ...(shouldColorLine ? { color: getRandomProfessionalHex() } : {})
4426
- };
4399
+ //Evalua Asignacion de Estilos
4400
+ if (widgetConfig.widgetStyle == null || widgetConfig.widgetStyle == undefined) {
4401
+ widgetConfig['widgetStyle'] = {};
4402
+ widgetConfig['widgetStyle']['widgetBackgroundColor'] = prmDashboardStyle.widgetBackgroundColor;
4403
+ widgetConfig['widgetStyle']['widgetBorderColor'] = prmDashboardStyle.widgetBorderColor;
4404
+ }
4405
+ this.eventAddWidget(widgetConfig, widgetConfig.controlConfig, controlData, widgetConfig.layoutConfig);
4427
4406
  });
4428
- return {
4429
- name: tableName === 'default' ? xAxis : tableName,
4430
- dataSource: dataSource,
4431
- opacity: opacity,
4432
- emptyPointSettings: emptyPointSettings
4433
- // dashArray: dashArray !== undefined ? dashArray : undefined,
4434
- // width: width !== undefined ? width : undefined,
4435
- // widthLine: widthLine !== undefined ? widthLine : undefined,
4436
- };
4437
- })
4438
- .filter((item) => item !== null);
4407
+ }
4408
+ }
4409
+ // Guarda los elementos desde la configuración JSON
4410
+ saveLayoutToJSON() {
4411
+ const currentWidgets = this.grid.save(false);
4412
+ this.dashboardItems = currentWidgets.map(w => ({
4413
+ id: w.id,
4414
+ x: w.x || 0,
4415
+ y: w.y || 0,
4416
+ w: w.w || 1,
4417
+ h: w.h || 1,
4418
+ content: w.content,
4419
+ contentData: {}
4420
+ }));
4421
+ console.log('JSON Guardado:', JSON.stringify(this.dashboardItems));
4422
+ return this.dashboardItems;
4439
4423
  }
4440
- const labelData = {
4441
- title: title || "",
4442
- axisX: {
4443
- valueType: 'Category',
4444
- title: typeof xLabelText === 'string' ? xLabelText : 'Categoría',
4445
- // labelIntersectAction: 'Rotate90',
4446
- // labelIntersectAction: 'Rotate45',
4447
- },
4448
- axisY: {
4449
- title: typeof yLabelText === 'string' ? yLabelText : 'Valor'
4450
- },
4451
- tooltip: {
4452
- ...(tooltip?.enable !== undefined ? { enable: tooltip.enable } : {}),
4453
- ...(tooltip?.format ? { format: tooltip.format } : {}),
4454
- ...(tooltip?.header ? { header: tooltip.header } : {}),
4455
- ...(tooltip?.shared !== undefined ? { shared: tooltip.shared } : {}),
4456
- enableHighlight: true,
4457
- },
4458
- legendSettings: {
4459
- visible: legends?.visible !== undefined ? legends.visible : undefined,
4460
- position: legends?.position !== undefined ? legends.position : undefined
4461
- },
4462
- ruleColorPoint: ruleColorPoint !== undefined ? ruleColorPoint : undefined
4463
- };
4464
- return {
4465
- series,
4466
- labelData
4467
- };
4468
- };
4469
-
4470
- class BubbleChartSyncfusionComponent {
4471
- constructor(elRef, cdr) {
4472
- this.elRef = elRef;
4473
- this.cdr = cdr;
4474
- this.idComponent = '';
4475
- this.dataChartParse = [];
4476
- this.currentLabelSize = '';
4477
- this.currentWidgetWidth = 0; // Valor inicial por defecto
4424
+ /*BUTTON ADD WIDGET*/
4425
+ fn_btn_addWidget() {
4426
+ this.countWidget++;
4427
+ const newWidgetId = 'widget-' + this.countWidget;
4428
+ let newItem = {
4429
+ id: newWidgetId, autoPosition: true, w: 6, h: 3,
4430
+ content: ''
4431
+ };
4432
+ //Datos de Widget y sus Contenidos
4433
+ const widgetConfig = {
4434
+ widgetId: newWidgetId,
4435
+ title: '',
4436
+ typeComponent: 'empty-visual',
4437
+ showConfigButtons: true,
4438
+ widgetStyle: DEFAULT_WIDGET_STYLE,
4439
+ layoutConfig: {
4440
+ id: '',
4441
+ w: 0,
4442
+ h: 0,
4443
+ content: undefined
4444
+ },
4445
+ controlConfig: {},
4446
+ controlTables: []
4447
+ };
4448
+ const controlConfig = {};
4449
+ const controlData = {};
4450
+ this.eventAddWidget(widgetConfig, controlConfig, controlData, newItem);
4478
4451
  }
4479
- ngOnInit() {
4480
- this.updateParsedData();
4452
+ /*BUTTON DELETE WIDGET*/
4453
+ fn_btn_deleteWidget() {
4454
+ const newWidgetId = 'widget-' + this.countWidget;
4455
+ this.eventRemoveWidgetById(newWidgetId);
4456
+ this.countWidget--;
4481
4457
  }
4482
- ngOnChanges(changes) {
4483
- if (changes['chartData'] || changes['config']) {
4484
- this.updateParsedData();
4485
- }
4458
+ /*BUTTON BLOCK WIDGETS*/
4459
+ fn_btn_lockPositionWidgets() {
4460
+ this.isLocked = !this.isLocked;
4461
+ const shouldLock = !this.allIsLocked();
4462
+ this.allIsLocked.set(shouldLock);
4463
+ this.fn_lockPositionWidgets(shouldLock);
4464
+ console.log(`All widgets have been visually and functionally locked: ${shouldLock}`);
4486
4465
  }
4487
- ngAfterViewInit() {
4488
- this._startResizeObserver();
4466
+ fn_lockPositionWidgets(prmAllIsLocked) {
4467
+ const shouldLock = prmAllIsLocked;
4468
+ // 1. Perform the functional Gridstack task on the core grid layout
4469
+ this.grid.movable('.grid-stack-item', !shouldLock);
4470
+ this.grid.resizable('.grid-stack-item', !shouldLock);
4471
+ // 2. Broadcast the state change down to every active dynamic child component
4472
+ this.widgetsActivos.forEach((componentRef) => {
4473
+ componentRef.setInput('isLocked', shouldLock);
4474
+ });
4475
+ console.log(`All widgets have been visually and functionally locked - por TS Config: ${shouldLock}`);
4489
4476
  }
4490
- ngOnDestroy() {
4491
- this._resizeObserver?.disconnect();
4477
+ /*BUTTON UPDATE WIDGET - CONTROL CONFIG */
4478
+ fn_btn_updateWidgetControlConfig(idWidget) {
4479
+ let newControlConfig = {};
4480
+ /*MODIFICAR METODO PARA CARGAR INFO DEL FORMULARIO*/
4481
+ newControlConfig['provider'] = 'syncfusion';
4482
+ this.eventUpdateWidgetControlConfig(idWidget, newControlConfig);
4492
4483
  }
4493
- updateParsedData() {
4494
- if (this.chartData && this.config) {
4495
- const rawParsed = parseSyncFusionData(this.chartData, this.config);
4496
- this.dataChartParse = rawParsed.series;
4497
- this.labelData = rawParsed.labelData;
4498
- console.log("DATA CREADA PARA AEL BUBBLE:", this.dataChartParse, this.labelData);
4499
- if (this.dataLabel && this.labelData) {
4500
- this.labelData.dataLabel = this.dataLabel;
4501
- }
4502
- this.cdr.markForCheck();
4503
- if (this.chartInstance) {
4504
- setTimeout(() => {
4505
- this.chartInstance?.refresh();
4506
- });
4507
- }
4484
+ /*BUTTON UPDATE WIDGET - CONTROL CONFIG */
4485
+ fn_btn_updateWidgetControlData(idWidget) {
4486
+ let newControlData = [];
4487
+ /*MODIFICAR METODO PARA CARGAR INFO DEL FORMULARIO*/
4488
+ newControlData = [
4489
+ { month: 'Ene', sales: 35, expenses: 28 },
4490
+ { month: 'Feb', sales: 28, expenses: 22 },
4491
+ { month: 'Mar', sales: 34, expenses: 25 },
4492
+ { month: 'Abr', sales: 32, expenses: 27 },
4493
+ { month: 'May', sales: 40, expenses: 30 },
4494
+ { month: 'Jun', sales: 32, expenses: 26 },
4495
+ { month: 'Jul', sales: 45, expenses: 32 },
4496
+ { month: 'Ago', sales: 38, expenses: 29 },
4497
+ { month: 'Sep', sales: 42, expenses: 31 },
4498
+ { month: 'Oct', sales: 48, expenses: 35 },
4499
+ { month: 'Nov', sales: 52, expenses: 38 },
4500
+ { month: 'Dic', sales: 58, expenses: 42 },
4501
+ ];
4502
+ this.eventUpdateWidgetControlData(idWidget, newControlData);
4503
+ }
4504
+ /****************************************************** */
4505
+ /*AGREGAR WIDGET*/
4506
+ eventAddWidget(widgetConfig, controlConfig, controlData, item) {
4507
+ // 1. Agregar el contenedor del widget a Gridstack
4508
+ const el = this.grid.addWidget(item);
4509
+ // 2. Obtener el contenedor interno generado por Gridstack
4510
+ const contentElement = el.querySelector('.grid-stack-item-content');
4511
+ if (contentElement) {
4512
+ // 3. Crear dinámicamente la instancia del componente Angular
4513
+ const componentRef = createComponent(YwDashboardWidgetComponent, {
4514
+ environmentInjector: this.environmentInjector, // Requerido para resolver dependencias
4515
+ hostElement: contentElement // Renderiza directamente aquí dentro
4516
+ });
4517
+ // 4. Pasar las propiedades/Inputs al componente creado
4518
+ //Evaluar Estilos
4519
+ componentRef.setInput('styleWidget', widgetConfig.widgetStyle);
4520
+ //componentRef.instance.configWidget = widgetConfig;
4521
+ componentRef.setInput('configWidget', widgetConfig);
4522
+ componentRef.setInput('controlConfig', controlConfig);
4523
+ componentRef.setInput('controlData', controlData);
4524
+ /* BEGIN - Eventos que provienen desde widget */
4525
+ componentRef.instance.eventDeleteRequest.subscribe((idWidget) => {
4526
+ // Ejecutamos la función de borrado que ya programamos en el paso anterior
4527
+ this.eventRemoveWidgetById(idWidget);
4528
+ });
4529
+ componentRef.instance.eventLockToggleRequest.subscribe((event) => {
4530
+ this.eventToggleLockWidget(event.widgetId, event.shouldLock);
4531
+ });
4532
+ componentRef.instance.eventMaximizeToggleRequest.subscribe((event) => {
4533
+ this.eventToggleMaximizeWidget(event.widgetId, event.shouldMaximize);
4534
+ });
4535
+ //Mostrar
4536
+ componentRef.instance.eventShowConfigFormRequest.subscribe((idWidget) => {
4537
+ this.eventShowFormConfigWidget(idWidget);
4538
+ });
4539
+ /* END - Eventos que provienen desde widget */
4540
+ // 5. Mover los nodos del DOM generados por Angular dentro del DIV del Widget
4541
+ this.appRef.attachView(componentRef.hostView);
4542
+ // Guardar la referencia de Componentes para hacer operaciones con estas.
4543
+ this.widgetsActivos.set(item.id, componentRef);
4544
+ //El componente interno no aparece bien dimensionado, con esto disparamos el evento para que se ajuste a las dimenciones correctas
4545
+ setTimeout(() => {
4546
+ window.dispatchEvent(new Event('resize'));
4547
+ }, 50);
4508
4548
  }
4509
4549
  }
4510
- // public pointRender(args: IPointRenderEventArgs): void {
4511
- // const yValue = Number(args.point.y);
4512
- // const configPoint: PointRenderConfig = this.config.ruleColorPoint || null;
4513
- // if (!configPoint) return;
4514
- // let passesRule = false;
4515
- // switch (configPoint.rule) {
4516
- // case 'threshold':
4517
- // passesRule = yValue >= (configPoint.thresholdValue || 0);
4518
- // break;
4519
- // case 'pair':
4520
- // passesRule = yValue % 2 === 0;
4521
- // break;
4522
- // case 'range':
4523
- // const min = configPoint.minRange || 0;
4524
- // const max = configPoint.maxRange || 100;
4525
- // passesRule = yValue >= min && yValue <= max;
4526
- // break;
4527
- // default:
4528
- // passesRule = true;
4529
- // }
4530
- // args.fill = passesRule ? (configPoint.trueColor || '#10B981') : (configPoint.falseColor || '#EF4444');
4531
- // }
4532
- pointRender(args) {
4533
- const yValue = Number(args.point.y);
4534
- // =====================================================
4535
- // EMPTY POINT / VALOR 0
4536
- // Tiene prioridad sobre ruleColorPoint
4537
- // =====================================================
4538
- if (yValue === 0) {
4539
- const emptyPoint = this.config.emptyPointSettings;
4540
- if (emptyPoint && emptyPoint !== '') {
4541
- args.fill = emptyPoint;
4542
- }
4550
+ /*UPDATE CONTROLCONFIG WIDGET*/
4551
+ eventUpdateWidgetControlConfig(idWidget, newControlConfig) {
4552
+ //Obtener la referencia del componente almacenada en el Map
4553
+ const componentRef = this.widgetsActivos.get(idWidget);
4554
+ if (!componentRef) {
4555
+ console.warn(`No se encontró un widget activo con el ID: ${idWidget}`);
4543
4556
  return;
4544
4557
  }
4545
- // =====================================================
4546
- // RULE COLOR POINT
4547
- // =====================================================
4548
- const configPoint = this.config.ruleColorPoint || null;
4549
- if (!configPoint) {
4558
+ //Actualizar el Input usando la API oficial setInput
4559
+ componentRef.setInput('controlConfig', newControlConfig);
4560
+ // NOTA: setInput dispara automáticamente la detección de cambios (ChangeDetectionStrategy.OnPush).
4561
+ // Si deseas asegurarte manualmente, puedes forzar un render:
4562
+ // componentRef.changeDetectorRef.detectChanges();
4563
+ }
4564
+ /*UPDATE CONTROL DATA WIDGET*/
4565
+ eventUpdateWidgetControlData(idWidget, newControlData) {
4566
+ //Obtener la referencia del componente almacenada en el Map
4567
+ const componentRef = this.widgetsActivos.get(idWidget);
4568
+ if (!componentRef) {
4569
+ console.warn(`No se encontró un widget activo con el ID: ${idWidget}`);
4550
4570
  return;
4551
4571
  }
4552
- let passesRule = false;
4553
- switch (configPoint.rule) {
4554
- case 'threshold':
4555
- passesRule =
4556
- yValue >= (configPoint.thresholdValue || 0);
4557
- break;
4558
- case 'pair':
4559
- passesRule = yValue % 2 === 0;
4560
- break;
4561
- case 'range':
4562
- const min = configPoint.minRange || 0;
4563
- const max = configPoint.maxRange || 100;
4564
- passesRule =
4565
- yValue >= min &&
4566
- yValue <= max;
4567
- break;
4568
- default:
4569
- passesRule = true;
4572
+ //Actualizar el Input usando la API oficial setInput
4573
+ componentRef.setInput('controlData', newControlData);
4574
+ // NOTA: setInput dispara automáticamente la detección de cambios (ChangeDetectionStrategy.OnPush).
4575
+ // Si deseas asegurarte manualmente, puedes forzar un render:
4576
+ componentRef.changeDetectorRef.detectChanges();
4577
+ }
4578
+ /****************************************************** */
4579
+ /* BEGIN - DRAWER */
4580
+ handleShowFormFilterDrawer() {
4581
+ this.drawerfiltervisible = true;
4582
+ }
4583
+ handleCloseFormFilterDrawer() {
4584
+ this.drawerfiltervisible = false;
4585
+ }
4586
+ handleCloseFormDrawer() {
4587
+ this.drawerconfigvisible = false;
4588
+ }
4589
+ fnGetDrawerWidth(prm_percent) {
4590
+ const curWidth = window.innerWidth;
4591
+ let newWidth = curWidth;
4592
+ if (prm_percent) {
4593
+ newWidth = Math.floor(curWidth * prm_percent / 100);
4570
4594
  }
4571
- args.fill = passesRule
4572
- ? (configPoint.trueColor || '#10B981')
4573
- : (configPoint.falseColor || '#EF4444');
4595
+ if (newWidth < 400) {
4596
+ newWidth = curWidth;
4597
+ }
4598
+ return newWidth;
4574
4599
  }
4575
- _startResizeObserver() {
4576
- if (typeof ResizeObserver === 'undefined')
4577
- return;
4578
- const hostEl = this.elRef.nativeElement;
4579
- this._resizeObserver = new ResizeObserver((entries) => {
4580
- window.requestAnimationFrame(() => {
4581
- for (const entry of entries) {
4582
- this.currentWidgetWidth = entry.contentRect.width;
4583
- if (this.currentWidgetWidth > 0) {
4584
- this._updateAdaptiveLabelSize(this.currentWidgetWidth);
4585
- if (this.chartInstance) {
4586
- // SI ACTIVAMSO EL REFRESH DA UN REBOTE AL REDIMENCIONAR
4587
- this.chartInstance.refresh();
4588
- }
4600
+ onFilterSelectionChange(eventData) {
4601
+ const lsize = this.widgetsActivos.size;
4602
+ //Validar que ya se crearon y renderizaron los componentes graficos.
4603
+ if (lsize > 0) {
4604
+ const currentFilterController = this.dashboardFilterConfig.controlListConfig.find((x) => x.widgetId == eventData['widgetId']);
4605
+ if (currentFilterController) {
4606
+ currentFilterController.controlFilterData = eventData['eventResponse'];
4607
+ this.fnUpdateDataControllerBasedOnFilter(this.dashboardFilterConfig.controlListConfig);
4608
+ }
4609
+ }
4610
+ }
4611
+ fnUpdateDataControllerBasedOnFilter(filterControlListConfig) {
4612
+ let copyDashboardData = structuredClone(this.dashboardData);
4613
+ filterControlListConfig.forEach((item) => {
4614
+ let tableSelected = copyDashboardData.find((x) => x.tableName == item.controlTable);
4615
+ if (item.typeComponent == 'filter-slicer' && tableSelected && item.controlFilterData) {
4616
+ const fieldName = item.configComponent.filterField;
4617
+ if (item.configComponent.dataType == 'date') {
4618
+ const minDate = item.controlFilterData['startDate'];
4619
+ const maxDate = item.controlFilterData['endDate'];
4620
+ if (minDate && maxDate) {
4621
+ const filterData = tableSelected.tableData.filter((y) => (minDate <= y[fieldName] && y[fieldName] <= maxDate));
4622
+ tableSelected.tableData = filterData;
4589
4623
  }
4590
4624
  }
4591
- });
4592
- });
4593
- this._resizeObserver.observe(hostEl);
4594
- }
4595
- _updateAdaptiveLabelSize(width) {
4596
- if (this.config?.labelSize) {
4597
- const parsedSize = typeof this.config.labelSize === 'number'
4598
- ? this.config.labelSize
4599
- : parseFloat(this.config.labelSize);
4600
- if (!isNaN(parsedSize)) {
4601
- if (width < 260) {
4602
- const scale = Math.max(0.65, width / 260);
4603
- this.currentLabelSize = `${Math.round(parsedSize * scale)}px`;
4625
+ if (item.configComponent.dataType == 'number') {
4626
+ const minNum = Number(item.controlFilterData['minValue']);
4627
+ const maxNum = Number(item.controlFilterData['maxValue']);
4628
+ if (minNum && maxNum) {
4629
+ const filterData = tableSelected.tableData.filter((y) => (minNum <= y[fieldName] && y[fieldName] <= maxNum));
4630
+ tableSelected.tableData = filterData;
4631
+ }
4604
4632
  }
4605
- else {
4606
- this.currentLabelSize = `${parsedSize}px`;
4633
+ }
4634
+ if (item.typeComponent == 'filter-button' && tableSelected && item.controlFilterData) {
4635
+ const fieldName = item.configComponent.filterField;
4636
+ const listValues = item.controlFilterData || [];
4637
+ if (listValues && listValues.length > 0) {
4638
+ const filterData = tableSelected.tableData.filter((y) => (listValues.includes(y[fieldName])));
4639
+ tableSelected.tableData = filterData;
4607
4640
  }
4608
- this.cdr.markForCheck();
4609
- return;
4610
4641
  }
4611
- }
4612
- // Proporción estándar ideal (~7.5% del ancho del contenedor, acotado entre 13px y 26px)
4613
- const base = Math.max(13, Math.min(26, Math.round(width * 0.075)));
4614
- this.currentLabelSize = `${base}px`;
4615
- this.cdr.markForCheck();
4642
+ if (item.typeComponent == 'filter-list' && tableSelected && item.controlFilterData) {
4643
+ const fieldName = item.configComponent.filterField;
4644
+ if (item.configComponent.dataType == 'text') {
4645
+ const listValues = item.controlFilterData['ids'] || [];
4646
+ if (listValues && listValues.length > 0) {
4647
+ const listValues1D = listValues;
4648
+ const filterData = tableSelected.tableData.filter((y) => (listValues1D.includes(y[fieldName])));
4649
+ tableSelected.tableData = filterData;
4650
+ }
4651
+ }
4652
+ if (item.configComponent.dataType == 'date') {
4653
+ const minDate = item.controlFilterData['minDate'];
4654
+ const maxDate = item.controlFilterData['maxDate'];
4655
+ if (minDate && maxDate) {
4656
+ const filterData = tableSelected.tableData.filter((y) => (minDate <= y[fieldName] && y[fieldName] <= maxDate));
4657
+ tableSelected.tableData = filterData;
4658
+ }
4659
+ }
4660
+ }
4661
+ });
4662
+ //Actualizacion de Data Componentes Graficos
4663
+ this.dashboardConfig.controlListConfig.forEach((item) => {
4664
+ const controlData = this.fn_getDataForWidgetComponent(item.controlTables, copyDashboardData);
4665
+ this.eventUpdateWidgetControlData(item.widgetId, controlData);
4666
+ });
4616
4667
  }
4617
- refresh() {
4618
- this.updateParsedData();
4668
+ /* END - DRAWER */
4669
+ /* BEGIN - Eventos que provienen desde widget */
4670
+ eventRemoveWidgetById(widgetId) {
4671
+ // 1. Buscar el elemento HTML físico dentro de Gridstack usando su atributo interno [gs-id]
4672
+ const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4673
+ if (elementoHtml) {
4674
+ // 2. Remover el elemento de Gridstack (esto limpia el HTML y reordena el tablero si float es false)
4675
+ // El parámetro false indica que remueva el nodo del DOM pero no dispare eventos internos destructivos pesados
4676
+ this.grid.removeWidget(elementoHtml, false);
4677
+ }
4678
+ // 3. Buscar y destruir la instancia de Angular en memoria RAM
4679
+ const componentRef = this.widgetsActivos.get(widgetId);
4680
+ if (componentRef) {
4681
+ // Desengancha la vista del ciclo de renderizado global de Angular
4682
+ this.appRef.detachView(componentRef.hostView);
4683
+ // Destruye el componente y libera la memoria RAM
4684
+ componentRef.destroy();
4685
+ // Eliminamos el registro de nuestro Mapa
4686
+ this.widgetsActivos.delete(widgetId);
4687
+ }
4688
+ //console.log(`Widget ${widgetId} eliminado con éxito de Gridstack y Angular.`);
4619
4689
  }
4620
- // pointRender(args: any) {
4621
- // if (args.point?.y === 0) {
4622
- // args.fill = this.emptyPointSettings.fill;
4623
- // args.border = {
4624
- // width: this.emptyPointSettings.border?.width ?? 0,
4625
- // color: this.emptyPointSettings.border?.color ?? ''
4626
- // };
4627
- // }
4628
- // }
4629
- axisLabelRender(args) {
4630
- const umbralWidget = 700;
4631
- if (this.currentWidgetWidth > umbralWidget) {
4632
- return;
4690
+ eventToggleLockWidget(widgetId, shouldLock) {
4691
+ const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4692
+ if (elementoHtml) {
4693
+ // La API de Gridstack nos permite congelar un nodo específico pasándole true/false
4694
+ this.grid.movable(elementoHtml, !shouldLock);
4695
+ this.grid.resizable(elementoHtml, !shouldLock);
4696
+ //console.log(`Widget ${widgetId} cambiado a estado bloqueado: ${shouldLock}`);
4633
4697
  }
4634
- // Si la tarjeta es estrecha, aplicamos el recorte de etiquetas
4635
- if (args.text && typeof args.text === 'string') {
4636
- const palabras = args.text.split(' ');
4637
- if (palabras.length > 1) {
4638
- const primeraPalabra = palabras[0];
4639
- const inicialSegunda = palabras[1].charAt(0).toUpperCase();
4640
- args.text = `${primeraPalabra} ${inicialSegunda}.`;
4698
+ }
4699
+ eventToggleMaximizeWidget(widgetId, shouldMaximize) {
4700
+ const elementoHtml = this.gridContainer.nativeElement.querySelector(`[gs-id="${widgetId}"]`);
4701
+ if (elementoHtml) {
4702
+ if (shouldMaximize) {
4703
+ // Aplicamos estilos CSS nativos para forzar al contenedor a flotar sobre todo el dashboard
4704
+ elementoHtml.classList.add('widget-maximized');
4705
+ // Deshabilitamos temporalmente que Gridstack intente moverlo mientras está maximizado
4706
+ this.grid.movable(elementoHtml, false);
4707
+ this.grid.resizable(elementoHtml, false);
4641
4708
  }
4642
4709
  else {
4643
- if (args.text.length > 10) {
4644
- args.text = args.text.substring(0, 9) + '.';
4645
- }
4710
+ elementoHtml.classList.remove('widget-maximized');
4711
+ // Restauramos los permisos normales leyendo si el componente de Angular estaba bloqueado previamente
4712
+ const componentRef = this.widgetsActivos.get(widgetId);
4713
+ const isCurrentlyLocked = componentRef?.instance.isLocked() || false;
4714
+ this.grid.movable(elementoHtml, !isCurrentlyLocked);
4715
+ this.grid.resizable(elementoHtml, !isCurrentlyLocked);
4646
4716
  }
4717
+ // Forzamos un evento resize simulado para que los gráficos de Syncfusion recalculen su nuevo tamaño gigante/pequeño
4718
+ setTimeout(() => {
4719
+ window.dispatchEvent(new Event('resize'));
4720
+ }, 50);
4647
4721
  }
4648
4722
  }
4649
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartSyncfusionComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4650
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: BubbleChartSyncfusionComponent, isStandalone: true, selector: "yw-bubble-chart-syncfusion", inputs: { chartData: "chartData", config: "config", idComponent: "idComponent" }, providers: [BubbleSeriesService, CategoryService, CategoryService,
4651
- TooltipService,
4652
- LegendService,
4653
- DateTimeService], viewQueries: [{ propertyName: "chartInstance", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"control-section\">\r\n\r\n <ejs-chart \r\n #chart \r\n [primaryXAxis]=\"labelData.axisX\" \r\n [primaryYAxis]=\"labelData.axisY\" \r\n [title]=\"labelData.title\" \r\n (pointRender)=\"pointRender($event)\" \r\n height=\"100%\"\r\n width=\"100%\"\r\n [legendSettings]=\"labelData.legendSettings\"\r\n (axisLabelRender)=\"axisLabelRender($event)\"\r\n\r\n [tooltip]=\"labelData.tooltip\">\r\n <e-series-collection>\r\n @for(series of dataChartParse; track $index){\r\n <e-series \r\n [opacity]=\"series.opacity\"\r\n [dataSource]='series.dataSource' \r\n type='Bubble' \r\n xName='x' \r\n yName='y' \r\n size='size' \r\n [name]='series.name'>\r\n </e-series>\r\n\r\n }\r\n </e-series-collection>\r\n</ejs-chart>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden}.control-section{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden;background:#fff;border-radius:8px}:host ::ng-deep ejs-circulargauge{display:block;width:100%!important;height:100%!important;flex-grow:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartModule }, { kind: "component", type: i1.ChartComponent, selector: "ejs-chart", inputs: ["accessibility", "allowExport", "allowMultiSelection", "annotations", "axes", "background", "backgroundImage", "border", "chartArea", "columns", "crosshair", "currencyCode", "dataSource", "description", "enableAnimation", "enableAutoIntervalOnBothAxis", "enableCanvas", "enableExport", "enableHtmlSanitizer", "enablePersistence", "enableRtl", "enableSideBySidePlacement", "focusBorderColor", "focusBorderMargin", "focusBorderWidth", "height", "highlightColor", "highlightMode", "highlightPattern", "indicators", "isMultiSelect", "isTransposed", "legendSettings", "locale", "margin", "palettes", "primaryXAxis", "primaryYAxis", "rangeColorSettings", "rows", "selectedDataIndexes", "selectionMode", "selectionPattern", "series", "subTitle", "subTitleStyle", "tabIndex", "theme", "title", "titleStyle", "tooltip", "useGroupingSeparator", "width", "zoomSettings"], outputs: ["afterExport", "animationComplete", "annotationRender", "axisLabelClick", "axisLabelRender", "axisMultiLabelRender", "axisRangeCalculated", "beforeExport", "beforePrint", "beforeResize", "chartDoubleClick", "chartMouseClick", "chartMouseDown", "chartMouseLeave", "chartMouseMove", "chartMouseUp", "drag", "dragComplete", "dragEnd", "dragStart", "legendClick", "legendRender", "load", "loaded", "multiLevelLabelClick", "onZooming", "pointClick", "pointDoubleClick", "pointMove", "pointRender", "resized", "scrollChanged", "scrollEnd", "scrollStart", "selectionComplete", "seriesRender", "sharedTooltipRender", "textRender", "tooltipRender", "zoomComplete", "dataSourceChange"] }, { kind: "directive", type: i1.SeriesDirective, selector: "e-series-collection>e-series", inputs: ["accessibility", "animation", "bearFillColor", "binInterval", "border", "boxPlotMode", "bullFillColor", "cardinalSplineTension", "close", "colorName", "columnFacet", "columnSpacing", "columnWidth", "columnWidthInPixel", "connector", "cornerRadius", "dashArray", "dataSource", "dragSettings", "drawType", "emptyPointSettings", "enableComplexProperty", "enableSolidCandles", "enableTooltip", "errorBar", "fill", "groupName", "high", "intermediateSumIndexes", "isClosed", "legendImageUrl", "legendShape", "low", "marker", "maxRadius", "minRadius", "name", "negativeFillColor", "noRisers", "nonHighlightStyle", "opacity", "open", "paretoOptions", "pointColorMapping", "query", "segmentAxis", "segments", "selectionStyle", "showMean", "showNormalDistribution", "size", "splineType", "stackingGroup", "step", "sumIndexes", "summaryFillColor", "tooltipFormat", "tooltipMappingName", "trendlines", "type", "unSelectedStyle", "visible", "volume", "width", "xAxisName", "xName", "yAxisName", "yName", "zOrder"] }, { kind: "directive", type: i1.SeriesCollectionDirective, selector: "ej-chart>e-series-collection" }] }); }
4654
- }
4655
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartSyncfusionComponent, decorators: [{
4656
- type: Component,
4657
- args: [{ selector: 'yw-bubble-chart-syncfusion', standalone: true, imports: [CommonModule, ChartModule], providers: [BubbleSeriesService, CategoryService, CategoryService,
4658
- TooltipService,
4659
- LegendService,
4660
- DateTimeService], template: "<div class=\"control-section\">\r\n\r\n <ejs-chart \r\n #chart \r\n [primaryXAxis]=\"labelData.axisX\" \r\n [primaryYAxis]=\"labelData.axisY\" \r\n [title]=\"labelData.title\" \r\n (pointRender)=\"pointRender($event)\" \r\n height=\"100%\"\r\n width=\"100%\"\r\n [legendSettings]=\"labelData.legendSettings\"\r\n (axisLabelRender)=\"axisLabelRender($event)\"\r\n\r\n [tooltip]=\"labelData.tooltip\">\r\n <e-series-collection>\r\n @for(series of dataChartParse; track $index){\r\n <e-series \r\n [opacity]=\"series.opacity\"\r\n [dataSource]='series.dataSource' \r\n type='Bubble' \r\n xName='x' \r\n yName='y' \r\n size='size' \r\n [name]='series.name'>\r\n </e-series>\r\n\r\n }\r\n </e-series-collection>\r\n</ejs-chart>\r\n</div>", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden}.control-section{display:flex;flex-direction:column;width:100%;height:100%;min-height:260px;box-sizing:border-box;overflow:hidden;background:#fff;border-radius:8px}:host ::ng-deep ejs-circulargauge{display:block;width:100%!important;height:100%!important;flex-grow:1}\n"] }]
4661
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { chartInstance: [{
4662
- type: ViewChild,
4663
- args: ['chart']
4664
- }], chartData: [{
4665
- type: Input,
4666
- args: ['chartData']
4667
- }], config: [{
4668
- type: Input,
4669
- args: ['config']
4670
- }], idComponent: [{
4671
- type: Input,
4672
- args: ['idComponent']
4673
- }] } });
4674
-
4675
- // import { LineChartSyncfusionComponent } from '../../../../../adapters/charts/line-chart/syncfusion/visual/yw-line-chart-syncfusion.component';
4676
- // import { YwLineMappingConfig } from '../../../../../models/config/chart/yw-line-chart-config.interface';
4677
- class BubbleChartComponent {
4678
- constructor() {
4679
- this.idComponent = '';
4680
- }
4681
- ngOnChanges(changes) {
4682
- if (changes['chartData']) {
4683
- console.log('change chartData:', changes['chartData'].currentValue);
4684
- }
4685
- if (changes['config']) {
4686
- console.log('change config:', changes['config'].currentValue);
4687
- }
4723
+ eventShowFormConfigWidget(widgetId) {
4724
+ this.drawerCurrentWidgetObject['widgetId'] = widgetId;
4725
+ this.drawerconfigvisible = true;
4688
4726
  }
4689
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4690
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: BubbleChartComponent, isStandalone: true, selector: "yw-bubble-chart", inputs: { chartData: "chartData", config: "config", idComponent: "idComponent" }, usesOnChanges: true, ngImport: i0, template: "llegamos\r\n@if(config.provider==='syncfusion'){\r\n <div style=\"position: relative; width: 100%; height: 100%;\">\r\n <yw-bubble-chart-syncfusion \r\n [idComponent]=\"idComponent\"\r\n [chartData]=\"chartData\" \r\n [config]=\"config\" style=\"display: block; width: 100%; height: 100%;\">\r\n </yw-bubble-chart-syncfusion>\r\n</div>\r\n}", styles: [":host{display:block;width:100%;height:100%;min-height:260px;min-width:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BubbleChartSyncfusionComponent, selector: "yw-bubble-chart-syncfusion", inputs: ["chartData", "config", "idComponent"] }] }); }
4727
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardComponent, deps: [{ token: i0.EnvironmentInjector }, { token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component }); }
4728
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: YwDashboardComponent, isStandalone: true, selector: "yw-dashboard", inputs: { showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: false, transformFunction: null }, showFilter: { classPropertyName: "showFilter", publicName: "showFilter", isSignal: true, isRequired: false, transformFunction: null }, dashboardStyle: { classPropertyName: "dashboardStyle", publicName: "dashboardStyle", isSignal: false, isRequired: false, transformFunction: null }, dashboardConfig: { classPropertyName: "dashboardConfig", publicName: "dashboardConfig", isSignal: false, isRequired: false, transformFunction: null }, dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: false, isRequired: false, transformFunction: null }, dashboardFilterConfig: { classPropertyName: "dashboardFilterConfig", publicName: "dashboardFilterConfig", isSignal: false, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "gridContainer", first: true, predicate: ["gridContainer"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- <div class=\"controls\" [hidden]=\"!showControls()\">\r\n <button (click)=\"saveLayoutToJSON()\">Guardar JSON en Consola</button>\r\n <button (click)=\"fn_btn_addWidget()\">add widget</button>\r\n <button (click)=\"fn_btn_lockPositionWidgets()\">Lock widgets</button>\r\n <button (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\">\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n</div> -->\r\n\r\n<div class=\"controls-container\" >\r\n @if ( showControls() ) { \r\n <!-- Botones principales con nz-button y tipos de Ant Design -->\r\n <button nz-button nzType=\"default\" (click)=\"saveLayoutToJSON()\" >\r\n <span nz-icon nz-type=\"code\"></span> Guardar JSON\r\n </button>\r\n\r\n <button nz-button nzType=\"primary\" (click)=\"fn_btn_addWidget()\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n\r\n <button nz-button [nzType]=\"isLocked ? 'primary' : 'default'\" nzDanger (click)=\"fn_btn_lockPositionWidgets()\" >\r\n <span nz-icon [nzType]=\"isLocked ? 'lock' : 'unlock'\"></span> \r\n {{ isLocked ? 'Bloqueado' : 'Bloquear' }}\r\n </button>\r\n }\r\n @if ( showFilter() ) { \r\n <!-- Bot\u00F3n de filtro con estilo ic\u00F3nico -->\r\n <button nz-button nzType=\"default\" nzShape=\"circle\" (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\" [class.active]=\"drawerfiltervisible\" >\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n }\r\n</div>\r\n<div #gridContainer class=\"grid-stack canvas-container\"\r\n [style.--canvas-bg]=\"dashboardStyle.canvasBackgroundColor\"\r\n></div>\r\n\r\n\r\n\r\n\r\n<!-- DRAWER - FILTER -->\r\n\r\n<nz-drawer\r\n[nzVisible]=\"drawerfiltervisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormFilterDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>Filtros</h6>\r\n <yw-dashboard-filter\r\n [dashboardFilterConfig]=\"dashboardFilterConfig\"\r\n [dashboardData]=\"dashboardData\"\r\n (filterSelectionChange)=\"onFilterSelectionChange($event)\"\r\n >\r\n </yw-dashboard-filter>\r\n </div>\r\n\r\n <!--\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"Secion de Filtros\">\r\n <div class=\"controls\">\r\n aqui botones de control:\r\n\r\n </div>\r\n <div>\r\n \r\n\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n-->\r\n</ng-container>\r\n</nz-drawer>\r\n\r\n\r\n\r\n<!-- DRAWER - CONFIGURACION -->\r\n<nz-drawer\r\n[nzVisible]=\"drawerconfigvisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>{{ drawerCurrentWidgetObject.widgetId }}</h6>\r\n </div>\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"{{ drawerCurrentWidgetObject.widgetId }}\">\r\n <div class=\"controls\">\r\n <button (click)=\"fn_btn_updateWidgetControlConfig(drawerCurrentWidgetObject.widgetId)\">Actualiza Configuracion</button>\r\n <button (click)=\"fn_btn_updateWidgetControlData(drawerCurrentWidgetObject.widgetId)\">Actualiza Data</button> \r\n </div>\r\n <div>\r\n bla bla bla\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n</ng-container>\r\n</nz-drawer>", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.canvas-container{background-color:var(--canvas-bg, #f5f5f5);min-height:500px;padding:10px}::vdeep .card-inner{background:#fff;border:1px solid #ccc;height:100%;display:flex;align-items:center;justify-content:center}:host ::ng-deep .grid-stack-item-content{border-radius:6px;box-shadow:0 2px 5px #0000001a;display:flex;align-items:center;justify-content:center;font-weight:700;overflow:hidden}::ng-deep .grid-stack-item.widget-maximized{position:fixed!important;top:0!important;left:0!important;width:100vw!important;height:100vh!important;z-index:9999!important;transform:none!important;margin:0!important;padding:5px}::ng-deep .grid-stack-item.widget-maximized .grid-stack-item-content{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;margin:0!important;padding:0!important;border:none!important;border-radius:0!important;box-shadow:none!important;background-color:#fff!important;overflow:hidden}::ng-deep .grid-stack>.grid-stack-item>.ui-resizable-handle{opacity:0!important;background-image:none!important}.widget-details-info{padding-top:30px;text-align:center}.widget-details-info h6{font-family:manrope,sans-serif;font-size:20px;font-weight:700;line-height:26px;color:#2d3144}.widget-details-info p{font-family:manrope,sans-serif;font-size:14px;font-weight:400;line-height:21px;color:#4b5064}.controls-container{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #f0f0f0;box-shadow:0 2px 8px #0000000a;border-radius:6px;margin-bottom:16px;width:100%;box-sizing:border-box;position:sticky;top:0}.controls-container button{white-space:nowrap}.controls-container .btn-filtro{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.controls-container .btn-filtro.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.controls-container .btn-filtro.active:hover{background-color:#40a9ff;border-color:#40a9ff}@media(max-width:576px){.controls-container{gap:8px;padding:8px 10px}.controls-container button[nz-button]{font-size:13px;padding:0 10px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i2.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i2.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTabsModule }, { kind: "component", type: i3.NzTabsComponent, selector: "nz-tabs,nz-tabset", inputs: ["nzSelectedIndex", "nzTabPosition", "nzTabBarExtraContent", "nzCanDeactivate", "nzAddIcon", "nzTabBarStyle", "nzType", "nzSize", "nzAnimated", "nzTabBarGutter", "nzHideAdd", "nzCentered", "nzHideAll", "nzLinkRouter", "nzLinkExact", "nzDestroyInactiveTabPane"], outputs: ["nzSelectChange", "nzSelectedIndexChange", "nzTabListScroll", "nzClose", "nzAdd"], exportAs: ["nzTabs"] }, { kind: "component", type: i3.NzTabComponent, selector: "nz-tab", inputs: ["nzTitle", "nzClosable", "nzCloseIcon", "nzDisabled", "nzForceRender"], outputs: ["nzSelect", "nzDeselect", "nzClick", "nzContextmenu"], exportAs: ["nzTab"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i5.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i6.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i7.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "component", type: YwDashboardFilterComponent, selector: "yw-dashboard-filter", inputs: ["dashboardFilterConfig", "dashboardData"], outputs: ["filterSelectionChange"] }] }); }
4691
4729
  }
4692
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: BubbleChartComponent, decorators: [{
4730
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: YwDashboardComponent, decorators: [{
4693
4731
  type: Component,
4694
- args: [{ selector: 'yw-bubble-chart', standalone: true, imports: [CommonModule, BubbleChartSyncfusionComponent], template: "llegamos\r\n@if(config.provider==='syncfusion'){\r\n <div style=\"position: relative; width: 100%; height: 100%;\">\r\n <yw-bubble-chart-syncfusion \r\n [idComponent]=\"idComponent\"\r\n [chartData]=\"chartData\" \r\n [config]=\"config\" style=\"display: block; width: 100%; height: 100%;\">\r\n </yw-bubble-chart-syncfusion>\r\n</div>\r\n}", styles: [":host{display:block;width:100%;height:100%;min-height:260px;min-width:0;overflow:hidden}\n"] }]
4695
- }], propDecorators: { chartData: [{
4696
- type: Input,
4697
- args: ['chartData']
4698
- }], config: [{
4699
- type: Input,
4700
- args: ['config']
4701
- }], idComponent: [{
4702
- type: Input,
4703
- args: ['idComponent']
4732
+ args: [{ selector: 'yw-dashboard', standalone: true, imports: [CommonModule,
4733
+ YwDashboardWidgetComponent,
4734
+ NzDrawerModule,
4735
+ NzTabsModule,
4736
+ YwBaseSlicerComponent,
4737
+ NzIconModule,
4738
+ NzButtonModule,
4739
+ YwButtonSlicerComponent,
4740
+ YwListSlicerComponent,
4741
+ YwDashboardFilterComponent
4742
+ ], template: "<!-- <div class=\"controls\" [hidden]=\"!showControls()\">\r\n <button (click)=\"saveLayoutToJSON()\">Guardar JSON en Consola</button>\r\n <button (click)=\"fn_btn_addWidget()\">add widget</button>\r\n <button (click)=\"fn_btn_lockPositionWidgets()\">Lock widgets</button>\r\n <button (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\">\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"20\" height=\"20\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n</div> -->\r\n\r\n<div class=\"controls-container\" >\r\n @if ( showControls() ) { \r\n <!-- Botones principales con nz-button y tipos de Ant Design -->\r\n <button nz-button nzType=\"default\" (click)=\"saveLayoutToJSON()\" >\r\n <span nz-icon nz-type=\"code\"></span> Guardar JSON\r\n </button>\r\n\r\n <button nz-button nzType=\"primary\" (click)=\"fn_btn_addWidget()\" >\r\n <span nz-icon nz-type=\"plus\"></span> A\u00F1adir widget\r\n </button>\r\n\r\n <button nz-button [nzType]=\"isLocked ? 'primary' : 'default'\" nzDanger (click)=\"fn_btn_lockPositionWidgets()\" >\r\n <span nz-icon [nzType]=\"isLocked ? 'lock' : 'unlock'\"></span> \r\n {{ isLocked ? 'Bloqueado' : 'Bloquear' }}\r\n </button>\r\n }\r\n @if ( showFilter() ) { \r\n <!-- Bot\u00F3n de filtro con estilo ic\u00F3nico -->\r\n <button nz-button nzType=\"default\" nzShape=\"circle\" (click)=\"handleShowFormFilterDrawer()\" class=\"btn-filtro\" [class.active]=\"drawerfiltervisible\" >\r\n <svg *ngIf=\"drawerfiltervisible; else filtroInactivo\" \r\n xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"currentColor\">\r\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/>\r\n </svg>\r\n <ng-template #filtroInactivo>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" \r\n width=\"16\" height=\"16\" \r\n viewBox=\"0 0 24 24\" \r\n fill=\"none\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\">\r\n <polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"/>\r\n </svg>\r\n </ng-template>\r\n </button>\r\n }\r\n</div>\r\n<div #gridContainer class=\"grid-stack canvas-container\"\r\n [style.--canvas-bg]=\"dashboardStyle.canvasBackgroundColor\"\r\n></div>\r\n\r\n\r\n\r\n\r\n<!-- DRAWER - FILTER -->\r\n\r\n<nz-drawer\r\n[nzVisible]=\"drawerfiltervisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormFilterDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>Filtros</h6>\r\n <yw-dashboard-filter\r\n [dashboardFilterConfig]=\"dashboardFilterConfig\"\r\n [dashboardData]=\"dashboardData\"\r\n (filterSelectionChange)=\"onFilterSelectionChange($event)\"\r\n >\r\n </yw-dashboard-filter>\r\n </div>\r\n\r\n <!--\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"Secion de Filtros\">\r\n <div class=\"controls\">\r\n aqui botones de control:\r\n\r\n </div>\r\n <div>\r\n \r\n\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n-->\r\n</ng-container>\r\n</nz-drawer>\r\n\r\n\r\n\r\n<!-- DRAWER - CONFIGURACION -->\r\n<nz-drawer\r\n[nzVisible]=\"drawerconfigvisible\"\r\n[nzMaskClosable]=\"false\"\r\nnzPlacement=\"right\"\r\n[nzWidth]=\"fnGetDrawerWidth(50)\"\r\n(nzOnClose)=\"handleCloseFormDrawer()\"\r\n>\r\n<ng-container *nzDrawerContent>\r\n <div class=\"widget-details-info\">\r\n <h6 nz-typography>{{ drawerCurrentWidgetObject.widgetId }}</h6>\r\n </div>\r\n <nz-tabset nzCentered>\r\n <nz-tab nzTitle=\"{{ drawerCurrentWidgetObject.widgetId }}\">\r\n <div class=\"controls\">\r\n <button (click)=\"fn_btn_updateWidgetControlConfig(drawerCurrentWidgetObject.widgetId)\">Actualiza Configuracion</button>\r\n <button (click)=\"fn_btn_updateWidgetControlData(drawerCurrentWidgetObject.widgetId)\">Actualiza Data</button> \r\n </div>\r\n <div>\r\n bla bla bla\r\n </div>\r\n\r\n </nz-tab>\r\n \r\n </nz-tabset>\r\n</ng-container>\r\n</nz-drawer>", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.canvas-container{background-color:var(--canvas-bg, #f5f5f5);min-height:500px;padding:10px}::vdeep .card-inner{background:#fff;border:1px solid #ccc;height:100%;display:flex;align-items:center;justify-content:center}:host ::ng-deep .grid-stack-item-content{border-radius:6px;box-shadow:0 2px 5px #0000001a;display:flex;align-items:center;justify-content:center;font-weight:700;overflow:hidden}::ng-deep .grid-stack-item.widget-maximized{position:fixed!important;top:0!important;left:0!important;width:100vw!important;height:100vh!important;z-index:9999!important;transform:none!important;margin:0!important;padding:5px}::ng-deep .grid-stack-item.widget-maximized .grid-stack-item-content{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;margin:0!important;padding:0!important;border:none!important;border-radius:0!important;box-shadow:none!important;background-color:#fff!important;overflow:hidden}::ng-deep .grid-stack>.grid-stack-item>.ui-resizable-handle{opacity:0!important;background-image:none!important}.widget-details-info{padding-top:30px;text-align:center}.widget-details-info h6{font-family:manrope,sans-serif;font-size:20px;font-weight:700;line-height:26px;color:#2d3144}.widget-details-info p{font-family:manrope,sans-serif;font-size:14px;font-weight:400;line-height:21px;color:#4b5064}.controls-container{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #f0f0f0;box-shadow:0 2px 8px #0000000a;border-radius:6px;margin-bottom:16px;width:100%;box-sizing:border-box;position:sticky;top:0}.controls-container button{white-space:nowrap}.controls-container .btn-filtro{display:inline-flex;align-items:center;justify-content:center;padding:0;width:32px;height:32px;border-radius:50%;transition:all .3s ease}.controls-container .btn-filtro.active{color:#fff;background-color:#1890ff;border-color:#1890ff}.controls-container .btn-filtro.active:hover{background-color:#40a9ff;border-color:#40a9ff}@media(max-width:576px){.controls-container{gap:8px;padding:8px 10px}.controls-container button[nz-button]{font-size:13px;padding:0 10px}}\n"] }]
4743
+ }], ctorParameters: () => [{ type: i0.EnvironmentInjector }, { type: i0.ApplicationRef }], propDecorators: { gridContainer: [{
4744
+ type: ViewChild,
4745
+ args: ['gridContainer', { static: true }]
4746
+ }], showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: false }] }], showFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilter", required: false }] }], dashboardStyle: [{
4747
+ type: Input
4748
+ }], dashboardConfig: [{
4749
+ type: Input
4750
+ }], dashboardData: [{
4751
+ type: Input
4752
+ }], dashboardFilterConfig: [{
4753
+ type: Input
4704
4754
  }] } });
4705
4755
 
4706
4756
  // Configuraciones especificas de pie chart -> acumulation chart en syncfusion