myio-js-library 0.1.26 → 0.1.28
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 +97 -57
- package/dist/index.d.cts +13 -1
- package/dist/index.js +97 -57
- package/dist/myio-js-library.umd.js +96 -56
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7889,10 +7889,16 @@ function formatDateTime(date, locale) {
|
|
|
7889
7889
|
minute: "2-digit"
|
|
7890
7890
|
});
|
|
7891
7891
|
}
|
|
7892
|
-
async function fetchTelemetryData(token, deviceId, startDate, endDate) {
|
|
7892
|
+
async function fetchTelemetryData(token, deviceId, startDate, endDate, queryParams) {
|
|
7893
7893
|
const startTs = new Date(startDate).getTime();
|
|
7894
7894
|
const endTs = new Date(endDate).getTime();
|
|
7895
|
-
const
|
|
7895
|
+
const keys = queryParams?.keys || "consumption";
|
|
7896
|
+
const limit = queryParams?.limit || 5e4;
|
|
7897
|
+
const intervalType = queryParams?.intervalType || "MILLISECONDS";
|
|
7898
|
+
const interval = queryParams?.interval || 54e6;
|
|
7899
|
+
const agg = queryParams?.agg || "SUM";
|
|
7900
|
+
const orderBy = queryParams?.orderBy || "ASC";
|
|
7901
|
+
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=${keys}&startTs=${startTs}&endTs=${endTs}&limit=${limit}&intervalType=${intervalType}&interval=${interval}&agg=${agg}&orderBy=${orderBy}`;
|
|
7896
7902
|
const response = await fetch(url, {
|
|
7897
7903
|
headers: {
|
|
7898
7904
|
"X-Authorization": `Bearer ${token}`,
|
|
@@ -7903,50 +7909,72 @@ async function fetchTelemetryData(token, deviceId, startDate, endDate) {
|
|
|
7903
7909
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
7904
7910
|
}
|
|
7905
7911
|
const data = await response.json();
|
|
7906
|
-
return data
|
|
7907
|
-
}
|
|
7908
|
-
function
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
const
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7912
|
+
return data;
|
|
7913
|
+
}
|
|
7914
|
+
function processMultiSeriesChartData(rawData, keys, correctionFactor, locale) {
|
|
7915
|
+
const seriesKeys = keys.split(",").map((k) => k.trim());
|
|
7916
|
+
const seriesData = [];
|
|
7917
|
+
let globalPeak = null;
|
|
7918
|
+
let isEmpty = true;
|
|
7919
|
+
const colors = ["#4A148C", "#2196F3", "#4CAF50", "#FF9800", "#F44336", "#9C27B0", "#795548", "#607D8B"];
|
|
7920
|
+
seriesKeys.forEach((key, index) => {
|
|
7921
|
+
const rawSeries = rawData[key] || [];
|
|
7922
|
+
if (rawSeries.length === 0) {
|
|
7923
|
+
seriesData.push({ key, label: key, points: [], peak: null, color: colors[index % colors.length] });
|
|
7924
|
+
return;
|
|
7925
|
+
}
|
|
7926
|
+
isEmpty = false;
|
|
7927
|
+
const sortedData = rawSeries.sort((a, b) => a.ts - b.ts);
|
|
7928
|
+
const points = [];
|
|
7929
|
+
let previousValue = 0;
|
|
7930
|
+
let previousTs = 0;
|
|
7931
|
+
for (let i = 0; i < sortedData.length; i++) {
|
|
7932
|
+
const current = sortedData[i];
|
|
7933
|
+
const currentValue = parseFloat(current.value);
|
|
7934
|
+
const currentTs = current.ts;
|
|
7935
|
+
if (i > 0) {
|
|
7936
|
+
const deltaWh = currentValue - previousValue;
|
|
7937
|
+
const deltaHours = (currentTs - previousTs) / (1e3 * 60 * 60);
|
|
7938
|
+
if (deltaWh > 0 && deltaHours > 0) {
|
|
7939
|
+
const demandKw = deltaWh / 1e3 / deltaHours * correctionFactor;
|
|
7940
|
+
points.push({
|
|
7941
|
+
x: currentTs,
|
|
7942
|
+
y: demandKw
|
|
7943
|
+
});
|
|
7944
|
+
}
|
|
7929
7945
|
}
|
|
7946
|
+
previousValue = currentValue;
|
|
7947
|
+
previousTs = currentTs;
|
|
7930
7948
|
}
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7949
|
+
let seriesPeak = null;
|
|
7950
|
+
if (points.length > 0) {
|
|
7951
|
+
const maxPoint = points.reduce(
|
|
7952
|
+
(max, point) => point.y > max.y ? point : max
|
|
7953
|
+
);
|
|
7954
|
+
seriesPeak = {
|
|
7955
|
+
value: maxPoint.y,
|
|
7956
|
+
timestamp: maxPoint.x,
|
|
7957
|
+
formattedValue: maxPoint.y.toFixed(2),
|
|
7958
|
+
formattedTime: formatDateTime(new Date(maxPoint.x), locale),
|
|
7959
|
+
key
|
|
7960
|
+
};
|
|
7961
|
+
if (!globalPeak || seriesPeak.value > globalPeak.value) {
|
|
7962
|
+
globalPeak = seriesPeak;
|
|
7963
|
+
}
|
|
7964
|
+
}
|
|
7965
|
+
seriesData.push({
|
|
7966
|
+
key,
|
|
7967
|
+
label: key,
|
|
7968
|
+
// Use key as label for now, can be customized later
|
|
7969
|
+
points,
|
|
7970
|
+
peak: seriesPeak,
|
|
7971
|
+
color: colors[index % colors.length]
|
|
7972
|
+
});
|
|
7973
|
+
});
|
|
7946
7974
|
return {
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
isEmpty
|
|
7975
|
+
series: seriesData,
|
|
7976
|
+
globalPeak,
|
|
7977
|
+
isEmpty
|
|
7950
7978
|
};
|
|
7951
7979
|
}
|
|
7952
7980
|
function createFocusTrap(container) {
|
|
@@ -8135,15 +8163,21 @@ async function openDemandModal(params) {
|
|
|
8135
8163
|
errorText.textContent = "O Limite de busca \xE9 de 30 dias de intervalo.";
|
|
8136
8164
|
return;
|
|
8137
8165
|
}
|
|
8138
|
-
const rawData = params.fetcher ? await params.fetcher({ token: params.token, deviceId: params.deviceId, startDate: params.startDate, endDate: params.endDate }) : await fetchTelemetryData(params.token, params.deviceId, params.startDate, params.endDate);
|
|
8139
|
-
chartData =
|
|
8166
|
+
const rawData = params.fetcher ? await params.fetcher({ token: params.token, deviceId: params.deviceId, startDate: params.startDate, endDate: params.endDate, telemetryQuery: params.telemetryQuery }) : await fetchTelemetryData(params.token, params.deviceId, params.startDate, params.endDate, params.telemetryQuery);
|
|
8167
|
+
chartData = processMultiSeriesChartData(
|
|
8168
|
+
rawData,
|
|
8169
|
+
params.telemetryQuery?.keys || "consumption",
|
|
8170
|
+
params.correctionFactor || 1,
|
|
8171
|
+
locale
|
|
8172
|
+
);
|
|
8140
8173
|
if (chartData.isEmpty) {
|
|
8141
8174
|
errorEl.style.display = "flex";
|
|
8142
8175
|
errorText.textContent = strings.noData;
|
|
8143
8176
|
return;
|
|
8144
8177
|
}
|
|
8145
|
-
if (chartData.
|
|
8146
|
-
const
|
|
8178
|
+
if (chartData.globalPeak) {
|
|
8179
|
+
const peak = chartData.globalPeak;
|
|
8180
|
+
const date = new Date(peak.timestamp);
|
|
8147
8181
|
const dateStr = date.toLocaleDateString(locale, {
|
|
8148
8182
|
day: "2-digit",
|
|
8149
8183
|
month: "2-digit",
|
|
@@ -8153,7 +8187,7 @@ async function openDemandModal(params) {
|
|
|
8153
8187
|
hour: "2-digit",
|
|
8154
8188
|
minute: "2-digit"
|
|
8155
8189
|
});
|
|
8156
|
-
peakEl.textContent = `${strings.maximum}: ${
|
|
8190
|
+
peakEl.textContent = `${strings.maximum}: ${peak.formattedValue} kW ${peak.key ? `(${peak.key}) ` : ""}${strings.at} ${dateStr} ${strings.atTime} ${timeStr}${strings.timeUnit}`;
|
|
8157
8191
|
peakEl.style.display = "block";
|
|
8158
8192
|
}
|
|
8159
8193
|
const Chart = window.Chart;
|
|
@@ -8161,22 +8195,27 @@ async function openDemandModal(params) {
|
|
|
8161
8195
|
chart = new Chart(chartCanvas, {
|
|
8162
8196
|
type: "line",
|
|
8163
8197
|
data: {
|
|
8164
|
-
datasets:
|
|
8165
|
-
label:
|
|
8166
|
-
data:
|
|
8167
|
-
borderColor:
|
|
8168
|
-
backgroundColor:
|
|
8169
|
-
fill:
|
|
8198
|
+
datasets: chartData.series.map((series) => ({
|
|
8199
|
+
label: series.label,
|
|
8200
|
+
data: series.points,
|
|
8201
|
+
borderColor: series.color,
|
|
8202
|
+
backgroundColor: series.color + "20",
|
|
8203
|
+
fill: false,
|
|
8204
|
+
// No fill for multi-series
|
|
8170
8205
|
tension: 0.4,
|
|
8171
8206
|
pointRadius: 2,
|
|
8172
8207
|
pointHoverRadius: 6
|
|
8173
|
-
}
|
|
8208
|
+
}))
|
|
8174
8209
|
},
|
|
8175
8210
|
options: {
|
|
8176
8211
|
responsive: true,
|
|
8177
8212
|
maintainAspectRatio: false,
|
|
8178
8213
|
plugins: {
|
|
8179
|
-
legend: {
|
|
8214
|
+
legend: {
|
|
8215
|
+
display: chartData.series.length > 1,
|
|
8216
|
+
// Show legend only if multiple series
|
|
8217
|
+
position: "top"
|
|
8218
|
+
},
|
|
8180
8219
|
zoom: {
|
|
8181
8220
|
zoom: {
|
|
8182
8221
|
wheel: { enabled: true },
|
|
@@ -8214,7 +8253,8 @@ async function openDemandModal(params) {
|
|
|
8214
8253
|
y: {
|
|
8215
8254
|
title: {
|
|
8216
8255
|
display: true,
|
|
8217
|
-
text: strings.demand
|
|
8256
|
+
text: params.yAxisLabel || strings.demand
|
|
8257
|
+
// Use configurable Y-axis label
|
|
8218
8258
|
},
|
|
8219
8259
|
beginAtZero: true
|
|
8220
8260
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -862,13 +862,25 @@ interface DemandModalParams {
|
|
|
862
862
|
pdf?: DemandModalPdfConfig;
|
|
863
863
|
styles?: Partial<DemandModalStyles>;
|
|
864
864
|
fetcher?: TelemetryFetcher;
|
|
865
|
+
telemetryQuery?: TelemetryQueryParams;
|
|
866
|
+
yAxisLabel?: string;
|
|
867
|
+
correctionFactor?: number;
|
|
868
|
+
}
|
|
869
|
+
interface TelemetryQueryParams {
|
|
870
|
+
keys?: string;
|
|
871
|
+
limit?: number;
|
|
872
|
+
intervalType?: string;
|
|
873
|
+
interval?: number;
|
|
874
|
+
agg?: string;
|
|
875
|
+
orderBy?: string;
|
|
865
876
|
}
|
|
866
877
|
type TelemetryFetcher = (params: {
|
|
867
878
|
token: string;
|
|
868
879
|
deviceId: string;
|
|
869
880
|
startDate: string;
|
|
870
881
|
endDate: string;
|
|
871
|
-
|
|
882
|
+
telemetryQuery?: TelemetryQueryParams;
|
|
883
|
+
}) => Promise<any>;
|
|
872
884
|
interface DemandModalPdfConfig {
|
|
873
885
|
enabled?: boolean;
|
|
874
886
|
fileName?: string;
|
package/dist/index.js
CHANGED
|
@@ -7823,10 +7823,16 @@ function formatDateTime(date, locale) {
|
|
|
7823
7823
|
minute: "2-digit"
|
|
7824
7824
|
});
|
|
7825
7825
|
}
|
|
7826
|
-
async function fetchTelemetryData(token, deviceId, startDate, endDate) {
|
|
7826
|
+
async function fetchTelemetryData(token, deviceId, startDate, endDate, queryParams) {
|
|
7827
7827
|
const startTs = new Date(startDate).getTime();
|
|
7828
7828
|
const endTs = new Date(endDate).getTime();
|
|
7829
|
-
const
|
|
7829
|
+
const keys = queryParams?.keys || "consumption";
|
|
7830
|
+
const limit = queryParams?.limit || 5e4;
|
|
7831
|
+
const intervalType = queryParams?.intervalType || "MILLISECONDS";
|
|
7832
|
+
const interval = queryParams?.interval || 54e6;
|
|
7833
|
+
const agg = queryParams?.agg || "SUM";
|
|
7834
|
+
const orderBy = queryParams?.orderBy || "ASC";
|
|
7835
|
+
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=${keys}&startTs=${startTs}&endTs=${endTs}&limit=${limit}&intervalType=${intervalType}&interval=${interval}&agg=${agg}&orderBy=${orderBy}`;
|
|
7830
7836
|
const response = await fetch(url, {
|
|
7831
7837
|
headers: {
|
|
7832
7838
|
"X-Authorization": `Bearer ${token}`,
|
|
@@ -7837,50 +7843,72 @@ async function fetchTelemetryData(token, deviceId, startDate, endDate) {
|
|
|
7837
7843
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
7838
7844
|
}
|
|
7839
7845
|
const data = await response.json();
|
|
7840
|
-
return data
|
|
7841
|
-
}
|
|
7842
|
-
function
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
const
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7846
|
+
return data;
|
|
7847
|
+
}
|
|
7848
|
+
function processMultiSeriesChartData(rawData, keys, correctionFactor, locale) {
|
|
7849
|
+
const seriesKeys = keys.split(",").map((k) => k.trim());
|
|
7850
|
+
const seriesData = [];
|
|
7851
|
+
let globalPeak = null;
|
|
7852
|
+
let isEmpty = true;
|
|
7853
|
+
const colors = ["#4A148C", "#2196F3", "#4CAF50", "#FF9800", "#F44336", "#9C27B0", "#795548", "#607D8B"];
|
|
7854
|
+
seriesKeys.forEach((key, index) => {
|
|
7855
|
+
const rawSeries = rawData[key] || [];
|
|
7856
|
+
if (rawSeries.length === 0) {
|
|
7857
|
+
seriesData.push({ key, label: key, points: [], peak: null, color: colors[index % colors.length] });
|
|
7858
|
+
return;
|
|
7859
|
+
}
|
|
7860
|
+
isEmpty = false;
|
|
7861
|
+
const sortedData = rawSeries.sort((a, b) => a.ts - b.ts);
|
|
7862
|
+
const points = [];
|
|
7863
|
+
let previousValue = 0;
|
|
7864
|
+
let previousTs = 0;
|
|
7865
|
+
for (let i = 0; i < sortedData.length; i++) {
|
|
7866
|
+
const current = sortedData[i];
|
|
7867
|
+
const currentValue = parseFloat(current.value);
|
|
7868
|
+
const currentTs = current.ts;
|
|
7869
|
+
if (i > 0) {
|
|
7870
|
+
const deltaWh = currentValue - previousValue;
|
|
7871
|
+
const deltaHours = (currentTs - previousTs) / (1e3 * 60 * 60);
|
|
7872
|
+
if (deltaWh > 0 && deltaHours > 0) {
|
|
7873
|
+
const demandKw = deltaWh / 1e3 / deltaHours * correctionFactor;
|
|
7874
|
+
points.push({
|
|
7875
|
+
x: currentTs,
|
|
7876
|
+
y: demandKw
|
|
7877
|
+
});
|
|
7878
|
+
}
|
|
7863
7879
|
}
|
|
7880
|
+
previousValue = currentValue;
|
|
7881
|
+
previousTs = currentTs;
|
|
7864
7882
|
}
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7883
|
+
let seriesPeak = null;
|
|
7884
|
+
if (points.length > 0) {
|
|
7885
|
+
const maxPoint = points.reduce(
|
|
7886
|
+
(max, point) => point.y > max.y ? point : max
|
|
7887
|
+
);
|
|
7888
|
+
seriesPeak = {
|
|
7889
|
+
value: maxPoint.y,
|
|
7890
|
+
timestamp: maxPoint.x,
|
|
7891
|
+
formattedValue: maxPoint.y.toFixed(2),
|
|
7892
|
+
formattedTime: formatDateTime(new Date(maxPoint.x), locale),
|
|
7893
|
+
key
|
|
7894
|
+
};
|
|
7895
|
+
if (!globalPeak || seriesPeak.value > globalPeak.value) {
|
|
7896
|
+
globalPeak = seriesPeak;
|
|
7897
|
+
}
|
|
7898
|
+
}
|
|
7899
|
+
seriesData.push({
|
|
7900
|
+
key,
|
|
7901
|
+
label: key,
|
|
7902
|
+
// Use key as label for now, can be customized later
|
|
7903
|
+
points,
|
|
7904
|
+
peak: seriesPeak,
|
|
7905
|
+
color: colors[index % colors.length]
|
|
7906
|
+
});
|
|
7907
|
+
});
|
|
7880
7908
|
return {
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
isEmpty
|
|
7909
|
+
series: seriesData,
|
|
7910
|
+
globalPeak,
|
|
7911
|
+
isEmpty
|
|
7884
7912
|
};
|
|
7885
7913
|
}
|
|
7886
7914
|
function createFocusTrap(container) {
|
|
@@ -8069,15 +8097,21 @@ async function openDemandModal(params) {
|
|
|
8069
8097
|
errorText.textContent = "O Limite de busca \xE9 de 30 dias de intervalo.";
|
|
8070
8098
|
return;
|
|
8071
8099
|
}
|
|
8072
|
-
const rawData = params.fetcher ? await params.fetcher({ token: params.token, deviceId: params.deviceId, startDate: params.startDate, endDate: params.endDate }) : await fetchTelemetryData(params.token, params.deviceId, params.startDate, params.endDate);
|
|
8073
|
-
chartData =
|
|
8100
|
+
const rawData = params.fetcher ? await params.fetcher({ token: params.token, deviceId: params.deviceId, startDate: params.startDate, endDate: params.endDate, telemetryQuery: params.telemetryQuery }) : await fetchTelemetryData(params.token, params.deviceId, params.startDate, params.endDate, params.telemetryQuery);
|
|
8101
|
+
chartData = processMultiSeriesChartData(
|
|
8102
|
+
rawData,
|
|
8103
|
+
params.telemetryQuery?.keys || "consumption",
|
|
8104
|
+
params.correctionFactor || 1,
|
|
8105
|
+
locale
|
|
8106
|
+
);
|
|
8074
8107
|
if (chartData.isEmpty) {
|
|
8075
8108
|
errorEl.style.display = "flex";
|
|
8076
8109
|
errorText.textContent = strings.noData;
|
|
8077
8110
|
return;
|
|
8078
8111
|
}
|
|
8079
|
-
if (chartData.
|
|
8080
|
-
const
|
|
8112
|
+
if (chartData.globalPeak) {
|
|
8113
|
+
const peak = chartData.globalPeak;
|
|
8114
|
+
const date = new Date(peak.timestamp);
|
|
8081
8115
|
const dateStr = date.toLocaleDateString(locale, {
|
|
8082
8116
|
day: "2-digit",
|
|
8083
8117
|
month: "2-digit",
|
|
@@ -8087,7 +8121,7 @@ async function openDemandModal(params) {
|
|
|
8087
8121
|
hour: "2-digit",
|
|
8088
8122
|
minute: "2-digit"
|
|
8089
8123
|
});
|
|
8090
|
-
peakEl.textContent = `${strings.maximum}: ${
|
|
8124
|
+
peakEl.textContent = `${strings.maximum}: ${peak.formattedValue} kW ${peak.key ? `(${peak.key}) ` : ""}${strings.at} ${dateStr} ${strings.atTime} ${timeStr}${strings.timeUnit}`;
|
|
8091
8125
|
peakEl.style.display = "block";
|
|
8092
8126
|
}
|
|
8093
8127
|
const Chart = window.Chart;
|
|
@@ -8095,22 +8129,27 @@ async function openDemandModal(params) {
|
|
|
8095
8129
|
chart = new Chart(chartCanvas, {
|
|
8096
8130
|
type: "line",
|
|
8097
8131
|
data: {
|
|
8098
|
-
datasets:
|
|
8099
|
-
label:
|
|
8100
|
-
data:
|
|
8101
|
-
borderColor:
|
|
8102
|
-
backgroundColor:
|
|
8103
|
-
fill:
|
|
8132
|
+
datasets: chartData.series.map((series) => ({
|
|
8133
|
+
label: series.label,
|
|
8134
|
+
data: series.points,
|
|
8135
|
+
borderColor: series.color,
|
|
8136
|
+
backgroundColor: series.color + "20",
|
|
8137
|
+
fill: false,
|
|
8138
|
+
// No fill for multi-series
|
|
8104
8139
|
tension: 0.4,
|
|
8105
8140
|
pointRadius: 2,
|
|
8106
8141
|
pointHoverRadius: 6
|
|
8107
|
-
}
|
|
8142
|
+
}))
|
|
8108
8143
|
},
|
|
8109
8144
|
options: {
|
|
8110
8145
|
responsive: true,
|
|
8111
8146
|
maintainAspectRatio: false,
|
|
8112
8147
|
plugins: {
|
|
8113
|
-
legend: {
|
|
8148
|
+
legend: {
|
|
8149
|
+
display: chartData.series.length > 1,
|
|
8150
|
+
// Show legend only if multiple series
|
|
8151
|
+
position: "top"
|
|
8152
|
+
},
|
|
8114
8153
|
zoom: {
|
|
8115
8154
|
zoom: {
|
|
8116
8155
|
wheel: { enabled: true },
|
|
@@ -8148,7 +8187,8 @@ async function openDemandModal(params) {
|
|
|
8148
8187
|
y: {
|
|
8149
8188
|
title: {
|
|
8150
8189
|
display: true,
|
|
8151
|
-
text: strings.demand
|
|
8190
|
+
text: params.yAxisLabel || strings.demand
|
|
8191
|
+
// Use configurable Y-axis label
|
|
8152
8192
|
},
|
|
8153
8193
|
beginAtZero: true
|
|
8154
8194
|
}
|