myio-js-library 0.1.165 → 0.1.167

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -574,6 +574,10 @@ __export(index_exports, {
574
574
  CONSUMPTION_THEME_COLORS: () => THEME_COLORS,
575
575
  ConnectionStatusType: () => ConnectionStatusType,
576
576
  DEFAULT_CLAMP_RANGE: () => DEFAULT_CLAMP_RANGE,
577
+ DEFAULT_ENERGY_GROUP_COLORS: () => DEFAULT_ENERGY_GROUP_COLORS,
578
+ DEFAULT_GAS_GROUP_COLORS: () => DEFAULT_GAS_GROUP_COLORS,
579
+ DEFAULT_SHOPPING_COLORS: () => DEFAULT_SHOPPING_COLORS,
580
+ DEFAULT_WATER_GROUP_COLORS: () => DEFAULT_WATER_GROUP_COLORS,
577
581
  DeviceStatusType: () => DeviceStatusType,
578
582
  EXPORT_DEFAULT_COLORS: () => EXPORT_DEFAULT_COLORS,
579
583
  EXPORT_DOMAIN_ICONS: () => EXPORT_DOMAIN_ICONS,
@@ -587,6 +591,7 @@ __export(index_exports, {
587
591
  addDetectionContext: () => addDetectionContext,
588
592
  addNamespace: () => addNamespace,
589
593
  aggregateByDay: () => aggregateByDay,
594
+ assignShoppingColors: () => assignShoppingColors,
590
595
  averageByDay: () => averageByDay,
591
596
  buildListItemsThingsboardByUniqueDatasource: () => buildListItemsThingsboardByUniqueDatasource,
592
597
  buildMyioIngestionAuth: () => buildMyioIngestionAuth,
@@ -608,6 +613,7 @@ __export(index_exports, {
608
613
  createConsumptionChartWidget: () => createConsumptionChartWidget,
609
614
  createConsumptionModal: () => createConsumptionModal,
610
615
  createDateRangePicker: () => createDateRangePicker2,
616
+ createDistributionChartWidget: () => createDistributionChartWidget,
611
617
  createInputDateRangePickerInsideDIV: () => createInputDateRangePickerInsideDIV,
612
618
  createModalHeader: () => createModalHeader,
613
619
  decodePayload: () => decodePayload,
@@ -646,11 +652,16 @@ __export(index_exports, {
646
652
  getAvailableContexts: () => getAvailableContexts,
647
653
  getConnectionStatusIcon: () => getConnectionStatusIcon,
648
654
  getDateRangeArray: () => getDateRangeArray,
655
+ getDefaultGroupColors: () => getDefaultGroupColors,
649
656
  getDeviceStatusIcon: () => getDeviceStatusIcon,
650
657
  getDeviceStatusInfo: () => getDeviceStatusInfo,
658
+ getDistributionThemeColors: () => getThemeColors2,
659
+ getGroupColor: () => getGroupColor,
660
+ getHashColor: () => getHashColor,
651
661
  getModalHeaderStyles: () => getModalHeaderStyles,
652
662
  getSaoPauloISOString: () => getSaoPauloISOString,
653
663
  getSaoPauloISOStringFixed: () => getSaoPauloISOStringFixed,
664
+ getShoppingColor: () => getShoppingColor,
654
665
  getValueByDatakey: () => getValueByDatakey,
655
666
  getValueByDatakeyLegacy: () => getValueByDatakeyLegacy,
656
667
  getWaterCategories: () => getWaterCategories,
@@ -23723,11 +23734,16 @@ function createConsumptionModal(config) {
23723
23734
  let isMaximized = false;
23724
23735
  const domainCfg = DOMAIN_CONFIG3[config.domain] || { name: config.domain, icon: "\u{1F4CA}" };
23725
23736
  const title = config.title || `${domainCfg.name} - Hist\xF3rico de Consumo`;
23726
- function getThemeColors2() {
23737
+ function getThemeColors3() {
23727
23738
  return THEME_COLORS[currentTheme];
23728
23739
  }
23740
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
23741
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
23742
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;pointer-events:none"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
23743
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
23744
+ const showSettingsButton = config.showSettingsButton ?? true;
23729
23745
  function renderModal4() {
23730
- const colors = getThemeColors2();
23746
+ const colors = getThemeColors3();
23731
23747
  const exportFormats = config.exportFormats || ["csv"];
23732
23748
  headerInstance = createModalHeader({
23733
23749
  id: modalId,
@@ -23760,7 +23776,55 @@ function createConsumptionModal(config) {
23760
23776
  instance.close();
23761
23777
  }
23762
23778
  });
23779
+ const btnBaseStyle = `
23780
+ display: flex;
23781
+ align-items: center;
23782
+ justify-content: center;
23783
+ gap: 6px;
23784
+ padding: 6px 12px;
23785
+ border: none;
23786
+ border-radius: 6px;
23787
+ font-size: 12px;
23788
+ font-weight: 500;
23789
+ cursor: pointer;
23790
+ transition: all 0.2s;
23791
+ white-space: nowrap;
23792
+ `.replace(/\s+/g, " ").trim();
23793
+ const tabBgColor = currentTheme === "dark" ? "#4b5563" : "#e5e7eb";
23794
+ const activeColor = "#3e1a7d";
23795
+ const inactiveTextColor = colors.text;
23763
23796
  return `
23797
+ <style>
23798
+ .myio-modal-tab-btn {
23799
+ ${btnBaseStyle}
23800
+ }
23801
+ .myio-modal-tab-btn:hover {
23802
+ opacity: 0.85;
23803
+ }
23804
+ .myio-modal-tab-btn.active {
23805
+ background: ${activeColor} !important;
23806
+ color: white !important;
23807
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
23808
+ }
23809
+ .myio-modal-tab-btn svg {
23810
+ pointer-events: none;
23811
+ }
23812
+ .myio-modal-settings-btn {
23813
+ background: transparent;
23814
+ border: 1px solid ${colors.border};
23815
+ font-size: 16px;
23816
+ cursor: pointer;
23817
+ padding: 6px 10px;
23818
+ border-radius: 6px;
23819
+ transition: all 0.2s;
23820
+ color: ${colors.text};
23821
+ }
23822
+ .myio-modal-settings-btn:hover {
23823
+ background: ${activeColor};
23824
+ border-color: ${activeColor};
23825
+ color: white;
23826
+ }
23827
+ </style>
23764
23828
  <div class="myio-consumption-modal-overlay" style="
23765
23829
  position: fixed;
23766
23830
  top: 0;
@@ -23791,59 +23855,44 @@ function createConsumptionModal(config) {
23791
23855
  <!-- Controls Bar -->
23792
23856
  <div class="myio-consumption-modal-controls" style="
23793
23857
  display: flex;
23794
- gap: 16px;
23858
+ gap: 12px;
23795
23859
  padding: 12px 16px;
23796
23860
  background: ${currentTheme === "dark" ? "#374151" : "#f7f7f7"};
23797
23861
  border-bottom: 1px solid ${colors.border};
23798
23862
  align-items: center;
23799
23863
  flex-wrap: wrap;
23800
23864
  ">
23865
+ <!-- Settings Button -->
23866
+ ${showSettingsButton ? `
23867
+ <button id="${modalId}-settings-btn" class="myio-modal-settings-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
23868
+ ` : ""}
23869
+
23801
23870
  <!-- Viz Mode Tabs -->
23802
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23803
- <button id="${modalId}-viz-total" style="
23804
- padding: 6px 12px;
23805
- border: none;
23806
- border-radius: 6px;
23807
- font-size: 13px;
23808
- cursor: pointer;
23809
- transition: all 0.2s;
23810
- background: ${currentVizMode === "total" ? "#3e1a7d" : "transparent"};
23811
- color: ${currentVizMode === "total" ? "white" : colors.text};
23812
- ">Consolidado</button>
23813
- <button id="${modalId}-viz-separate" style="
23814
- padding: 6px 12px;
23815
- border: none;
23816
- border-radius: 6px;
23817
- font-size: 13px;
23818
- cursor: pointer;
23819
- transition: all 0.2s;
23820
- background: ${currentVizMode === "separate" ? "#3e1a7d" : "transparent"};
23821
- color: ${currentVizMode === "separate" ? "white" : colors.text};
23822
- ">Por Shopping</button>
23871
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23872
+ <button id="${modalId}-viz-total" class="myio-modal-tab-btn ${currentVizMode === "total" ? "active" : ""}"
23873
+ data-viz="total" title="Consolidado"
23874
+ style="background: ${currentVizMode === "total" ? activeColor : "transparent"}; color: ${currentVizMode === "total" ? "white" : inactiveTextColor};">
23875
+ ${consolidadoIcon}
23876
+ </button>
23877
+ <button id="${modalId}-viz-separate" class="myio-modal-tab-btn ${currentVizMode === "separate" ? "active" : ""}"
23878
+ data-viz="separate" title="Por Shopping"
23879
+ style="background: ${currentVizMode === "separate" ? activeColor : "transparent"}; color: ${currentVizMode === "separate" ? "white" : inactiveTextColor};">
23880
+ ${porShoppingIcon}
23881
+ </button>
23823
23882
  </div>
23824
23883
 
23825
23884
  <!-- Chart Type Tabs -->
23826
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23827
- <button id="${modalId}-type-line" style="
23828
- padding: 6px 12px;
23829
- border: none;
23830
- border-radius: 6px;
23831
- font-size: 13px;
23832
- cursor: pointer;
23833
- transition: all 0.2s;
23834
- background: ${currentChartType === "line" ? "#3e1a7d" : "transparent"};
23835
- color: ${currentChartType === "line" ? "white" : colors.text};
23836
- ">Linhas</button>
23837
- <button id="${modalId}-type-bar" style="
23838
- padding: 6px 12px;
23839
- border: none;
23840
- border-radius: 6px;
23841
- font-size: 13px;
23842
- cursor: pointer;
23843
- transition: all 0.2s;
23844
- background: ${currentChartType === "bar" ? "#3e1a7d" : "transparent"};
23845
- color: ${currentChartType === "bar" ? "white" : colors.text};
23846
- ">Barras</button>
23885
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23886
+ <button id="${modalId}-type-line" class="myio-modal-tab-btn ${currentChartType === "line" ? "active" : ""}"
23887
+ data-type="line" title="Gr\xE1fico de Linhas"
23888
+ style="background: ${currentChartType === "line" ? activeColor : "transparent"}; color: ${currentChartType === "line" ? "white" : inactiveTextColor};">
23889
+ ${lineChartIcon}
23890
+ </button>
23891
+ <button id="${modalId}-type-bar" class="myio-modal-tab-btn ${currentChartType === "bar" ? "active" : ""}"
23892
+ data-type="bar" title="Gr\xE1fico de Barras"
23893
+ style="background: ${currentChartType === "bar" ? activeColor : "transparent"}; color: ${currentChartType === "bar" ? "white" : inactiveTextColor};">
23894
+ ${barChartIcon}
23895
+ </button>
23847
23896
  </div>
23848
23897
  </div>
23849
23898
 
@@ -23864,6 +23913,11 @@ function createConsumptionModal(config) {
23864
23913
  function setupListeners() {
23865
23914
  if (!modalElement) return;
23866
23915
  headerInstance?.attachListeners();
23916
+ if (showSettingsButton) {
23917
+ document.getElementById(`${modalId}-settings-btn`)?.addEventListener("click", () => {
23918
+ config.onSettingsClick?.();
23919
+ });
23920
+ }
23867
23921
  document.getElementById(`${modalId}-viz-total`)?.addEventListener("click", () => {
23868
23922
  currentVizMode = "total";
23869
23923
  chartInstance?.setVizMode("total");
@@ -23898,25 +23952,30 @@ function createConsumptionModal(config) {
23898
23952
  modalElement.__handleKeydown = handleKeydown;
23899
23953
  }
23900
23954
  function updateControlStyles() {
23901
- const colors = getThemeColors2();
23955
+ const colors = getThemeColors3();
23956
+ const activeColor = "#3e1a7d";
23902
23957
  const vizTotalBtn = document.getElementById(`${modalId}-viz-total`);
23903
23958
  const vizSeparateBtn = document.getElementById(`${modalId}-viz-separate`);
23904
23959
  if (vizTotalBtn) {
23905
- vizTotalBtn.style.background = currentVizMode === "total" ? "#3e1a7d" : "transparent";
23960
+ vizTotalBtn.classList.toggle("active", currentVizMode === "total");
23961
+ vizTotalBtn.style.background = currentVizMode === "total" ? activeColor : "transparent";
23906
23962
  vizTotalBtn.style.color = currentVizMode === "total" ? "white" : colors.text;
23907
23963
  }
23908
23964
  if (vizSeparateBtn) {
23909
- vizSeparateBtn.style.background = currentVizMode === "separate" ? "#3e1a7d" : "transparent";
23965
+ vizSeparateBtn.classList.toggle("active", currentVizMode === "separate");
23966
+ vizSeparateBtn.style.background = currentVizMode === "separate" ? activeColor : "transparent";
23910
23967
  vizSeparateBtn.style.color = currentVizMode === "separate" ? "white" : colors.text;
23911
23968
  }
23912
23969
  const typeLineBtn = document.getElementById(`${modalId}-type-line`);
23913
23970
  const typeBarBtn = document.getElementById(`${modalId}-type-bar`);
23914
23971
  if (typeLineBtn) {
23915
- typeLineBtn.style.background = currentChartType === "line" ? "#3e1a7d" : "transparent";
23972
+ typeLineBtn.classList.toggle("active", currentChartType === "line");
23973
+ typeLineBtn.style.background = currentChartType === "line" ? activeColor : "transparent";
23916
23974
  typeLineBtn.style.color = currentChartType === "line" ? "white" : colors.text;
23917
23975
  }
23918
23976
  if (typeBarBtn) {
23919
- typeBarBtn.style.background = currentChartType === "bar" ? "#3e1a7d" : "transparent";
23977
+ typeBarBtn.classList.toggle("active", currentChartType === "bar");
23978
+ typeBarBtn.style.background = currentChartType === "bar" ? activeColor : "transparent";
23920
23979
  typeBarBtn.style.color = currentChartType === "bar" ? "white" : colors.text;
23921
23980
  }
23922
23981
  }
@@ -23953,7 +24012,11 @@ function createConsumptionModal(config) {
23953
24012
  defaultChartType: currentChartType,
23954
24013
  defaultVizMode: currentVizMode
23955
24014
  });
23956
- await chartInstance.render();
24015
+ if (config.initialData) {
24016
+ chartInstance.update(config.initialData);
24017
+ } else {
24018
+ await chartInstance.render();
24019
+ }
23957
24020
  },
23958
24021
  close() {
23959
24022
  if (modalElement) {
@@ -25816,6 +25879,581 @@ var EXPORT_DEFAULT_COLORS = DEFAULT_COLORS4;
25816
25879
  var EXPORT_DOMAIN_ICONS = DOMAIN_ICONS;
25817
25880
  var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS;
25818
25881
  var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25882
+
25883
+ // src/components/DistributionChart/colorManager.ts
25884
+ var DEFAULT_SHOPPING_COLORS = [
25885
+ "#3b82f6",
25886
+ // Blue
25887
+ "#8b5cf6",
25888
+ // Purple
25889
+ "#f59e0b",
25890
+ // Amber
25891
+ "#ef4444",
25892
+ // Red
25893
+ "#10b981",
25894
+ // Emerald
25895
+ "#06b6d4",
25896
+ // Cyan
25897
+ "#ec4899",
25898
+ // Pink
25899
+ "#14b8a6",
25900
+ // Teal
25901
+ "#f97316",
25902
+ // Orange
25903
+ "#a855f7"
25904
+ // Violet
25905
+ ];
25906
+ var DEFAULT_ENERGY_GROUP_COLORS = {
25907
+ "Elevadores": "#3b82f6",
25908
+ "Escadas Rolantes": "#8b5cf6",
25909
+ "Climatiza\xE7\xE3o": "#f59e0b",
25910
+ "Climatizacao": "#f59e0b",
25911
+ // Without accent
25912
+ "Outros Equipamentos": "#ef4444",
25913
+ "Lojas": "#10b981"
25914
+ };
25915
+ var DEFAULT_WATER_GROUP_COLORS = {
25916
+ "Lojas": "#10b981",
25917
+ "\xC1rea Comum": "#0288d1",
25918
+ "Area Comum": "#0288d1"
25919
+ // Without accent
25920
+ };
25921
+ var DEFAULT_GAS_GROUP_COLORS = {
25922
+ "Cozinha": "#f59e0b",
25923
+ "Aquecimento": "#ef4444",
25924
+ "Outros": "#94a3b8"
25925
+ };
25926
+ function getDefaultGroupColors(domain) {
25927
+ switch (domain.toLowerCase()) {
25928
+ case "energy":
25929
+ return DEFAULT_ENERGY_GROUP_COLORS;
25930
+ case "water":
25931
+ return DEFAULT_WATER_GROUP_COLORS;
25932
+ case "gas":
25933
+ return DEFAULT_GAS_GROUP_COLORS;
25934
+ default:
25935
+ return DEFAULT_ENERGY_GROUP_COLORS;
25936
+ }
25937
+ }
25938
+ function assignShoppingColors(shoppingIds) {
25939
+ const colors = {};
25940
+ shoppingIds.forEach((id, index) => {
25941
+ colors[id] = DEFAULT_SHOPPING_COLORS[index % DEFAULT_SHOPPING_COLORS.length];
25942
+ });
25943
+ return colors;
25944
+ }
25945
+ function getShoppingColor(shoppingId, shoppingColors, fallbackIndex = 0) {
25946
+ if (shoppingColors && shoppingColors[shoppingId]) {
25947
+ return shoppingColors[shoppingId];
25948
+ }
25949
+ if (shoppingColors) {
25950
+ const normalizedId = shoppingId.toLowerCase();
25951
+ for (const [key, color] of Object.entries(shoppingColors)) {
25952
+ if (key.toLowerCase() === normalizedId || key.toLowerCase().includes(normalizedId)) {
25953
+ return color;
25954
+ }
25955
+ }
25956
+ }
25957
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25958
+ }
25959
+ function getGroupColor(groupName, groupColors, domain = "energy", fallbackIndex = 0) {
25960
+ if (groupColors && groupColors[groupName]) {
25961
+ return groupColors[groupName];
25962
+ }
25963
+ const defaultColors = getDefaultGroupColors(domain);
25964
+ if (defaultColors[groupName]) {
25965
+ return defaultColors[groupName];
25966
+ }
25967
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25968
+ }
25969
+ function getThemeColors2(theme) {
25970
+ if (theme === "dark") {
25971
+ return {
25972
+ text: "#f3f4f6",
25973
+ secondaryText: "#9ca3af",
25974
+ background: "#111827",
25975
+ cardBackground: "#1f2937",
25976
+ border: "#374151",
25977
+ grid: "#374151"
25978
+ };
25979
+ }
25980
+ return {
25981
+ text: "#1f2937",
25982
+ secondaryText: "#6b7280",
25983
+ background: "#f5f5f5",
25984
+ cardBackground: "#ffffff",
25985
+ border: "#e5e7eb",
25986
+ grid: "#e5e7eb"
25987
+ };
25988
+ }
25989
+ function getHashColor(str) {
25990
+ let hash = 0;
25991
+ for (let i = 0; i < str.length; i++) {
25992
+ const char = str.charCodeAt(i);
25993
+ hash = (hash << 5) - hash + char;
25994
+ hash = hash & hash;
25995
+ }
25996
+ return DEFAULT_SHOPPING_COLORS[Math.abs(hash) % DEFAULT_SHOPPING_COLORS.length];
25997
+ }
25998
+
25999
+ // src/components/DistributionChart/createDistributionChartWidget.ts
26000
+ var settingsIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><circle cx="12" cy="12" r="3"/><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"/></svg>`;
26001
+ var maximizeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>`;
26002
+ function createDistributionChartWidget(config) {
26003
+ const widgetId = `distribution-${config.domain}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
26004
+ let chartInstance = null;
26005
+ let currentMode = config.defaultMode || "groups";
26006
+ let currentTheme = config.theme || "light";
26007
+ let currentData = null;
26008
+ let containerElement = null;
26009
+ let isLoading = false;
26010
+ const title = config.title || getDomainTitle(config.domain);
26011
+ const chartHeight = config.chartHeight || 300;
26012
+ const showHeader = config.showHeader !== false;
26013
+ const showModeSelector = config.showModeSelector !== false;
26014
+ const showSettingsButton = config.showSettingsButton ?? false;
26015
+ const showMaximizeButton = config.showMaximizeButton ?? false;
26016
+ const decimalPlaces = config.decimalPlaces ?? 2;
26017
+ const modes = config.modes || getDefaultModes(config.domain);
26018
+ const groupColors = config.groupColors || getDefaultGroupColors(config.domain);
26019
+ function getDomainTitle(domain) {
26020
+ const titles = {
26021
+ energy: "Distribui\xE7\xE3o de Energia",
26022
+ water: "Distribui\xE7\xE3o de \xC1gua",
26023
+ gas: "Distribui\xE7\xE3o de G\xE1s",
26024
+ temperature: "Distribui\xE7\xE3o de Temperatura"
26025
+ };
26026
+ return titles[domain.toLowerCase()] || `Distribui\xE7\xE3o de ${domain}`;
26027
+ }
26028
+ function getDefaultModes(domain) {
26029
+ if (domain === "water") {
26030
+ return [
26031
+ { value: "groups", label: "Lojas vs \xC1rea Comum" },
26032
+ { value: "stores", label: "Lojas por Shopping" },
26033
+ { value: "common", label: "\xC1rea Comum por Shopping" }
26034
+ ];
26035
+ }
26036
+ return [
26037
+ { value: "groups", label: "Por Grupos de Equipamentos" },
26038
+ { value: "elevators", label: "Elevadores por Shopping" },
26039
+ { value: "escalators", label: "Escadas Rolantes por Shopping" },
26040
+ { value: "hvac", label: "Climatiza\xE7\xE3o por Shopping" },
26041
+ { value: "others", label: "Outros Equipamentos por Shopping" },
26042
+ { value: "stores", label: "Lojas por Shopping" }
26043
+ ];
26044
+ }
26045
+ function $id(id) {
26046
+ if (config.$container) {
26047
+ return config.$container[0].querySelector(`#${id}`);
26048
+ }
26049
+ return document.getElementById(id);
26050
+ }
26051
+ function formatValue(value) {
26052
+ if (config.unitLarge && config.thresholdForLargeUnit && value >= config.thresholdForLargeUnit) {
26053
+ return `${(value / config.thresholdForLargeUnit).toFixed(decimalPlaces)} ${config.unitLarge}`;
26054
+ }
26055
+ return `${value.toFixed(decimalPlaces)} ${config.unit}`;
26056
+ }
26057
+ function getColor(key, index, isGroupMode2) {
26058
+ if (isGroupMode2) {
26059
+ return getGroupColor(key, groupColors, config.domain, index);
26060
+ }
26061
+ const shoppingColors = config.getShoppingColors?.();
26062
+ return getShoppingColor(key, shoppingColors, index);
26063
+ }
26064
+ function getColors2() {
26065
+ return getThemeColors2(currentTheme);
26066
+ }
26067
+ function isGroupMode() {
26068
+ return currentMode === "groups";
26069
+ }
26070
+ function renderHTML() {
26071
+ const colors = getColors2();
26072
+ const modeOptions = modes.map(
26073
+ (m) => `<option value="${m.value}" ${m.value === currentMode ? "selected" : ""}>${m.label}</option>`
26074
+ ).join("");
26075
+ const headerButtons = [];
26076
+ if (showSettingsButton) {
26077
+ headerButtons.push(`
26078
+ <button id="${widgetId}-settings-btn" class="myio-dist-btn" title="Configura\xE7\xF5es">
26079
+ ${settingsIcon}
26080
+ </button>
26081
+ `);
26082
+ }
26083
+ if (showMaximizeButton) {
26084
+ headerButtons.push(`
26085
+ <button id="${widgetId}-maximize-btn" class="myio-dist-btn" title="Expandir">
26086
+ ${maximizeIcon}
26087
+ </button>
26088
+ `);
26089
+ }
26090
+ return `
26091
+ <style>
26092
+ #${widgetId} {
26093
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
26094
+ }
26095
+ #${widgetId} .myio-dist-header {
26096
+ display: flex;
26097
+ justify-content: space-between;
26098
+ align-items: center;
26099
+ margin-bottom: 16px;
26100
+ flex-wrap: wrap;
26101
+ gap: 12px;
26102
+ }
26103
+ #${widgetId} .myio-dist-title {
26104
+ margin: 0;
26105
+ font-size: 16px;
26106
+ font-weight: 600;
26107
+ color: ${colors.text};
26108
+ }
26109
+ #${widgetId} .myio-dist-controls {
26110
+ display: flex;
26111
+ align-items: center;
26112
+ gap: 8px;
26113
+ }
26114
+ #${widgetId} .myio-dist-label {
26115
+ font-size: 12px;
26116
+ color: ${colors.secondaryText};
26117
+ }
26118
+ #${widgetId} .myio-dist-select {
26119
+ padding: 6px 10px;
26120
+ border-radius: 6px;
26121
+ border: 1px solid ${colors.border};
26122
+ background: ${colors.cardBackground};
26123
+ color: ${colors.text};
26124
+ font-size: 12px;
26125
+ cursor: pointer;
26126
+ min-width: 180px;
26127
+ }
26128
+ #${widgetId} .myio-dist-select:focus {
26129
+ outline: none;
26130
+ border-color: #3e1a7d;
26131
+ }
26132
+ #${widgetId} .myio-dist-btn {
26133
+ display: flex;
26134
+ align-items: center;
26135
+ justify-content: center;
26136
+ padding: 6px 8px;
26137
+ border: 1px solid ${colors.border};
26138
+ border-radius: 6px;
26139
+ background: transparent;
26140
+ color: ${colors.text};
26141
+ cursor: pointer;
26142
+ transition: all 0.2s;
26143
+ }
26144
+ #${widgetId} .myio-dist-btn:hover {
26145
+ background: #3e1a7d;
26146
+ border-color: #3e1a7d;
26147
+ color: white;
26148
+ }
26149
+ #${widgetId} .myio-dist-chart-container {
26150
+ position: relative;
26151
+ height: ${chartHeight}px;
26152
+ }
26153
+ #${widgetId} .myio-dist-loading {
26154
+ position: absolute;
26155
+ top: 0;
26156
+ left: 0;
26157
+ right: 0;
26158
+ bottom: 0;
26159
+ display: flex;
26160
+ align-items: center;
26161
+ justify-content: center;
26162
+ background: ${colors.cardBackground}ee;
26163
+ z-index: 10;
26164
+ }
26165
+ #${widgetId} .myio-dist-spinner {
26166
+ width: 32px;
26167
+ height: 32px;
26168
+ border: 3px solid ${colors.border};
26169
+ border-top-color: #3e1a7d;
26170
+ border-radius: 50%;
26171
+ animation: myio-dist-spin 0.8s linear infinite;
26172
+ }
26173
+ @keyframes myio-dist-spin {
26174
+ to { transform: rotate(360deg); }
26175
+ }
26176
+ #${widgetId} .myio-dist-empty {
26177
+ display: flex;
26178
+ flex-direction: column;
26179
+ align-items: center;
26180
+ justify-content: center;
26181
+ height: 100%;
26182
+ color: ${colors.secondaryText};
26183
+ font-size: 14px;
26184
+ }
26185
+ #${widgetId} .myio-dist-empty-icon {
26186
+ font-size: 48px;
26187
+ margin-bottom: 12px;
26188
+ opacity: 0.5;
26189
+ }
26190
+ </style>
26191
+
26192
+ <div id="${widgetId}" class="myio-distribution-widget" style="
26193
+ background: ${colors.cardBackground};
26194
+ border-radius: 12px;
26195
+ padding: 16px;
26196
+ height: 100%;
26197
+ display: flex;
26198
+ flex-direction: column;
26199
+ ">
26200
+ ${showHeader ? `
26201
+ <div class="myio-dist-header">
26202
+ <h4 class="myio-dist-title">${title}</h4>
26203
+ <div class="myio-dist-controls">
26204
+ ${showModeSelector && modes.length > 1 ? `
26205
+ <label for="${widgetId}-mode" class="myio-dist-label">Visualizar:</label>
26206
+ <select id="${widgetId}-mode" class="myio-dist-select">
26207
+ ${modeOptions}
26208
+ </select>
26209
+ ` : ""}
26210
+ ${headerButtons.join("")}
26211
+ </div>
26212
+ </div>
26213
+ ` : ""}
26214
+
26215
+ <div class="myio-dist-chart-container">
26216
+ <canvas id="${widgetId}-canvas"></canvas>
26217
+ <div id="${widgetId}-loading" class="myio-dist-loading" style="display: none;">
26218
+ <div class="myio-dist-spinner"></div>
26219
+ </div>
26220
+ </div>
26221
+ </div>
26222
+ `;
26223
+ }
26224
+ function setLoading(loading) {
26225
+ isLoading = loading;
26226
+ const loadingEl = $id(`${widgetId}-loading`);
26227
+ if (loadingEl) {
26228
+ loadingEl.style.display = loading ? "flex" : "none";
26229
+ }
26230
+ }
26231
+ function buildChartData(distribution) {
26232
+ const labels = [];
26233
+ const data = [];
26234
+ const backgroundColors = [];
26235
+ const total = Object.values(distribution).reduce((sum, val) => sum + val, 0);
26236
+ const isGroup = isGroupMode();
26237
+ const entries = Object.entries(distribution).filter(([_, value]) => value > 0).sort((a, b) => b[1] - a[1]);
26238
+ entries.forEach(([key, value], index) => {
26239
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26240
+ labels.push(`${key} (${formatValue(value)} - ${percentage}%)`);
26241
+ data.push(value);
26242
+ backgroundColors.push(getColor(key, index, isGroup));
26243
+ });
26244
+ return { labels, data, backgroundColors, total };
26245
+ }
26246
+ function renderEmptyState() {
26247
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26248
+ if (container) {
26249
+ const emptyEl = document.createElement("div");
26250
+ emptyEl.className = "myio-dist-empty";
26251
+ emptyEl.innerHTML = `
26252
+ <div class="myio-dist-empty-icon">\u{1F4CA}</div>
26253
+ <div>Sem dados dispon\xEDveis</div>
26254
+ `;
26255
+ const canvas = $id(`${widgetId}-canvas`);
26256
+ if (canvas) canvas.style.display = "none";
26257
+ const existingEmpty = container.querySelector(".myio-dist-empty");
26258
+ if (!existingEmpty) {
26259
+ container.appendChild(emptyEl);
26260
+ }
26261
+ }
26262
+ }
26263
+ function removeEmptyState() {
26264
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26265
+ if (container) {
26266
+ const emptyEl = container.querySelector(".myio-dist-empty");
26267
+ if (emptyEl) emptyEl.remove();
26268
+ const canvas = $id(`${widgetId}-canvas`);
26269
+ if (canvas) canvas.style.display = "block";
26270
+ }
26271
+ }
26272
+ async function updateChart() {
26273
+ const canvas = $id(`${widgetId}-canvas`);
26274
+ if (!canvas) {
26275
+ console.error(`[${config.domain.toUpperCase()}] Distribution canvas not found`);
26276
+ return;
26277
+ }
26278
+ setLoading(true);
26279
+ try {
26280
+ const distribution = await config.fetchDistribution(currentMode);
26281
+ if (!distribution || Object.keys(distribution).length === 0) {
26282
+ console.warn(`[${config.domain.toUpperCase()}] No distribution data for mode: ${currentMode}`);
26283
+ currentData = null;
26284
+ setLoading(false);
26285
+ renderEmptyState();
26286
+ return;
26287
+ }
26288
+ removeEmptyState();
26289
+ currentData = distribution;
26290
+ const { labels, data, backgroundColors, total } = buildChartData(distribution);
26291
+ const colors = getColors2();
26292
+ const Chart2 = window.Chart;
26293
+ if (!Chart2) {
26294
+ throw new Error("Chart.js not loaded");
26295
+ }
26296
+ if (chartInstance) {
26297
+ chartInstance.destroy();
26298
+ chartInstance = null;
26299
+ }
26300
+ const ctx = canvas.getContext("2d");
26301
+ if (!ctx) {
26302
+ throw new Error("Could not get canvas context");
26303
+ }
26304
+ chartInstance = new Chart2(ctx, {
26305
+ type: "bar",
26306
+ data: {
26307
+ labels,
26308
+ datasets: [
26309
+ {
26310
+ label: `Consumo (${config.unit})`,
26311
+ data,
26312
+ backgroundColor: backgroundColors
26313
+ }
26314
+ ]
26315
+ },
26316
+ options: {
26317
+ responsive: true,
26318
+ maintainAspectRatio: false,
26319
+ indexAxis: "y",
26320
+ // Horizontal bar chart
26321
+ animation: false,
26322
+ plugins: {
26323
+ legend: { display: false },
26324
+ tooltip: {
26325
+ callbacks: {
26326
+ label: (context) => {
26327
+ const value = context.parsed.x || 0;
26328
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26329
+ return `${formatValue(value)} (${percentage}%)`;
26330
+ }
26331
+ }
26332
+ }
26333
+ },
26334
+ scales: {
26335
+ x: {
26336
+ beginAtZero: true,
26337
+ ticks: {
26338
+ callback: (value) => formatValue(Number(value)),
26339
+ color: colors.secondaryText,
26340
+ font: { size: 11 }
26341
+ },
26342
+ grid: { color: colors.grid }
26343
+ },
26344
+ y: {
26345
+ ticks: {
26346
+ font: { size: 11 },
26347
+ color: colors.text
26348
+ },
26349
+ grid: { display: false }
26350
+ }
26351
+ }
26352
+ }
26353
+ });
26354
+ config.onDataLoaded?.(distribution);
26355
+ console.log(`[${config.domain.toUpperCase()}] Distribution chart updated for mode: ${currentMode}`);
26356
+ } catch (error) {
26357
+ console.error(`[${config.domain.toUpperCase()}] Error updating distribution chart:`, error);
26358
+ config.onError?.(error);
26359
+ renderEmptyState();
26360
+ } finally {
26361
+ setLoading(false);
26362
+ }
26363
+ }
26364
+ function setupListeners() {
26365
+ const modeSelect = $id(`${widgetId}-mode`);
26366
+ if (modeSelect) {
26367
+ modeSelect.addEventListener("change", async (e) => {
26368
+ currentMode = e.target.value;
26369
+ config.onModeChange?.(currentMode);
26370
+ await updateChart();
26371
+ });
26372
+ }
26373
+ if (showSettingsButton) {
26374
+ const settingsBtn = $id(`${widgetId}-settings-btn`);
26375
+ if (settingsBtn) {
26376
+ settingsBtn.addEventListener("click", () => {
26377
+ config.onSettingsClick?.();
26378
+ });
26379
+ }
26380
+ }
26381
+ if (showMaximizeButton) {
26382
+ const maximizeBtn = $id(`${widgetId}-maximize-btn`);
26383
+ if (maximizeBtn) {
26384
+ maximizeBtn.addEventListener("click", () => {
26385
+ config.onMaximizeClick?.();
26386
+ });
26387
+ }
26388
+ }
26389
+ }
26390
+ function updateThemeStyles() {
26391
+ const colors = getColors2();
26392
+ const widget = $id(widgetId);
26393
+ if (widget) {
26394
+ widget.style.background = colors.cardBackground;
26395
+ const title2 = widget.querySelector(".myio-dist-title");
26396
+ if (title2) title2.style.color = colors.text;
26397
+ const labels = widget.querySelectorAll(".myio-dist-label");
26398
+ labels.forEach((l) => l.style.color = colors.secondaryText);
26399
+ const select = widget.querySelector(".myio-dist-select");
26400
+ if (select) {
26401
+ select.style.background = colors.cardBackground;
26402
+ select.style.color = colors.text;
26403
+ select.style.borderColor = colors.border;
26404
+ }
26405
+ const buttons = widget.querySelectorAll(".myio-dist-btn");
26406
+ buttons.forEach((b) => {
26407
+ b.style.color = colors.text;
26408
+ b.style.borderColor = colors.border;
26409
+ });
26410
+ }
26411
+ }
26412
+ const instance = {
26413
+ async render() {
26414
+ containerElement = $id(config.containerId);
26415
+ if (!containerElement) {
26416
+ throw new Error(`Container #${config.containerId} not found`);
26417
+ }
26418
+ containerElement.innerHTML = renderHTML();
26419
+ setupListeners();
26420
+ await updateChart();
26421
+ },
26422
+ async setMode(mode) {
26423
+ currentMode = mode;
26424
+ const modeSelect = $id(`${widgetId}-mode`);
26425
+ if (modeSelect) {
26426
+ modeSelect.value = mode;
26427
+ }
26428
+ config.onModeChange?.(mode);
26429
+ await updateChart();
26430
+ },
26431
+ async refresh() {
26432
+ await updateChart();
26433
+ },
26434
+ setTheme(theme) {
26435
+ currentTheme = theme;
26436
+ updateThemeStyles();
26437
+ if (currentData) {
26438
+ updateChart();
26439
+ }
26440
+ },
26441
+ destroy() {
26442
+ if (chartInstance) {
26443
+ chartInstance.destroy();
26444
+ chartInstance = null;
26445
+ }
26446
+ if (containerElement) {
26447
+ containerElement.innerHTML = "";
26448
+ }
26449
+ currentData = null;
26450
+ },
26451
+ getChartInstance: () => chartInstance,
26452
+ getCurrentMode: () => currentMode,
26453
+ getCurrentData: () => currentData
26454
+ };
26455
+ return instance;
26456
+ }
25819
26457
  // Annotate the CommonJS export names for ESM import in node:
25820
26458
  0 && (module.exports = {
25821
26459
  CHART_COLORS,
@@ -25824,6 +26462,10 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25824
26462
  CONSUMPTION_THEME_COLORS,
25825
26463
  ConnectionStatusType,
25826
26464
  DEFAULT_CLAMP_RANGE,
26465
+ DEFAULT_ENERGY_GROUP_COLORS,
26466
+ DEFAULT_GAS_GROUP_COLORS,
26467
+ DEFAULT_SHOPPING_COLORS,
26468
+ DEFAULT_WATER_GROUP_COLORS,
25827
26469
  DeviceStatusType,
25828
26470
  EXPORT_DEFAULT_COLORS,
25829
26471
  EXPORT_DOMAIN_ICONS,
@@ -25837,6 +26479,7 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25837
26479
  addDetectionContext,
25838
26480
  addNamespace,
25839
26481
  aggregateByDay,
26482
+ assignShoppingColors,
25840
26483
  averageByDay,
25841
26484
  buildListItemsThingsboardByUniqueDatasource,
25842
26485
  buildMyioIngestionAuth,
@@ -25858,6 +26501,7 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25858
26501
  createConsumptionChartWidget,
25859
26502
  createConsumptionModal,
25860
26503
  createDateRangePicker,
26504
+ createDistributionChartWidget,
25861
26505
  createInputDateRangePickerInsideDIV,
25862
26506
  createModalHeader,
25863
26507
  decodePayload,
@@ -25896,11 +26540,16 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25896
26540
  getAvailableContexts,
25897
26541
  getConnectionStatusIcon,
25898
26542
  getDateRangeArray,
26543
+ getDefaultGroupColors,
25899
26544
  getDeviceStatusIcon,
25900
26545
  getDeviceStatusInfo,
26546
+ getDistributionThemeColors,
26547
+ getGroupColor,
26548
+ getHashColor,
25901
26549
  getModalHeaderStyles,
25902
26550
  getSaoPauloISOString,
25903
26551
  getSaoPauloISOStringFixed,
26552
+ getShoppingColor,
25904
26553
  getValueByDatakey,
25905
26554
  getValueByDatakeyLegacy,
25906
26555
  getWaterCategories,