myio-js-library 0.1.211 → 0.1.213
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 +103 -34
- package/dist/index.js +103 -34
- package/dist/myio-js-library.umd.js +103 -34
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21457,9 +21457,14 @@ var WaterTankModalView = class {
|
|
|
21457
21457
|
overlay = null;
|
|
21458
21458
|
modal = null;
|
|
21459
21459
|
i18n;
|
|
21460
|
+
chartDisplayMode = "water_level";
|
|
21461
|
+
// RFC-0107: Default to water_level (m.c.a)
|
|
21460
21462
|
constructor(config) {
|
|
21461
21463
|
this.config = config;
|
|
21462
21464
|
this.i18n = this.getI18n();
|
|
21465
|
+
if (config.params.displayKey) {
|
|
21466
|
+
this.chartDisplayMode = config.params.displayKey;
|
|
21467
|
+
}
|
|
21463
21468
|
}
|
|
21464
21469
|
/**
|
|
21465
21470
|
* Get i18n strings with defaults
|
|
@@ -21771,14 +21776,14 @@ var WaterTankModalView = class {
|
|
|
21771
21776
|
`;
|
|
21772
21777
|
}
|
|
21773
21778
|
/**
|
|
21774
|
-
* Render chart section
|
|
21779
|
+
* RFC-0107: Render chart section with display mode selector
|
|
21780
|
+
* Shows water_level (m.c.a) or water_percentage (%) based on user selection
|
|
21775
21781
|
*/
|
|
21776
21782
|
renderChart() {
|
|
21777
21783
|
const { data } = this.config;
|
|
21778
|
-
const
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
if (waterLevelPoints.length === 0) {
|
|
21784
|
+
const chartPoints = this.getChartDataPoints();
|
|
21785
|
+
if (chartPoints.length === 0) {
|
|
21786
|
+
const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21782
21787
|
return `
|
|
21783
21788
|
<div style="
|
|
21784
21789
|
background: #f8f9fa;
|
|
@@ -21790,13 +21795,14 @@ var WaterTankModalView = class {
|
|
|
21790
21795
|
<div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
|
|
21791
21796
|
<div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
|
|
21792
21797
|
<div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
|
|
21793
|
-
No
|
|
21798
|
+
No ${this.chartDisplayMode} (${displayLabel}) data available for this period
|
|
21794
21799
|
</div>
|
|
21795
21800
|
</div>
|
|
21796
21801
|
`;
|
|
21797
21802
|
}
|
|
21798
|
-
const firstTs =
|
|
21799
|
-
const lastTs =
|
|
21803
|
+
const firstTs = chartPoints[0]?.ts;
|
|
21804
|
+
const lastTs = chartPoints[chartPoints.length - 1]?.ts;
|
|
21805
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
|
|
21800
21806
|
return `
|
|
21801
21807
|
<div style="
|
|
21802
21808
|
background: white;
|
|
@@ -21804,12 +21810,38 @@ var WaterTankModalView = class {
|
|
|
21804
21810
|
border-radius: 8px;
|
|
21805
21811
|
padding: 20px;
|
|
21806
21812
|
">
|
|
21807
|
-
<
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
"
|
|
21813
|
+
<div style="
|
|
21814
|
+
display: flex;
|
|
21815
|
+
align-items: center;
|
|
21816
|
+
justify-content: space-between;
|
|
21817
|
+
margin-bottom: 16px;
|
|
21818
|
+
">
|
|
21819
|
+
<h3 style="
|
|
21820
|
+
margin: 0;
|
|
21821
|
+
font-size: 16px;
|
|
21822
|
+
font-weight: 600;
|
|
21823
|
+
color: #2c3e50;
|
|
21824
|
+
">${chartTitle}</h3>
|
|
21825
|
+
<div style="
|
|
21826
|
+
display: flex;
|
|
21827
|
+
align-items: center;
|
|
21828
|
+
gap: 8px;
|
|
21829
|
+
">
|
|
21830
|
+
<span style="font-size: 13px; color: #7f8c8d;">Display:</span>
|
|
21831
|
+
<select id="myio-water-tank-display-mode" style="
|
|
21832
|
+
padding: 6px 12px;
|
|
21833
|
+
border: 1px solid #ddd;
|
|
21834
|
+
border-radius: 6px;
|
|
21835
|
+
font-size: 13px;
|
|
21836
|
+
color: #2c3e50;
|
|
21837
|
+
background: white;
|
|
21838
|
+
cursor: pointer;
|
|
21839
|
+
">
|
|
21840
|
+
<option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>Level (m.c.a)</option>
|
|
21841
|
+
<option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentage (%)</option>
|
|
21842
|
+
</select>
|
|
21843
|
+
</div>
|
|
21844
|
+
</div>
|
|
21813
21845
|
<canvas id="myio-water-tank-chart" style="width: 100%; height: 280px;"></canvas>
|
|
21814
21846
|
${firstTs && lastTs ? `
|
|
21815
21847
|
<div style="
|
|
@@ -21819,12 +21851,29 @@ var WaterTankModalView = class {
|
|
|
21819
21851
|
text-align: center;
|
|
21820
21852
|
">
|
|
21821
21853
|
${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
|
|
21822
|
-
(${
|
|
21854
|
+
(${chartPoints.length} readings)
|
|
21823
21855
|
</div>
|
|
21824
21856
|
` : ""}
|
|
21825
21857
|
</div>
|
|
21826
21858
|
`;
|
|
21827
21859
|
}
|
|
21860
|
+
/**
|
|
21861
|
+
* RFC-0107: Get chart data points based on current display mode
|
|
21862
|
+
*/
|
|
21863
|
+
getChartDataPoints() {
|
|
21864
|
+
const { data } = this.config;
|
|
21865
|
+
if (this.chartDisplayMode === "water_percentage") {
|
|
21866
|
+
const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
|
|
21867
|
+
return percentagePoints.map((p) => ({
|
|
21868
|
+
...p,
|
|
21869
|
+
value: p.value <= 1.5 ? p.value * 100 : p.value
|
|
21870
|
+
}));
|
|
21871
|
+
} else {
|
|
21872
|
+
return data.telemetry.filter(
|
|
21873
|
+
(p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
|
|
21874
|
+
);
|
|
21875
|
+
}
|
|
21876
|
+
}
|
|
21828
21877
|
/**
|
|
21829
21878
|
* Render footer with actions
|
|
21830
21879
|
*/
|
|
@@ -21874,6 +21923,13 @@ var WaterTankModalView = class {
|
|
|
21874
21923
|
if (applyDatesBtn) {
|
|
21875
21924
|
applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
|
|
21876
21925
|
}
|
|
21926
|
+
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21927
|
+
if (displayModeSelect) {
|
|
21928
|
+
displayModeSelect.addEventListener("change", () => {
|
|
21929
|
+
this.chartDisplayMode = displayModeSelect.value;
|
|
21930
|
+
this.refreshChart();
|
|
21931
|
+
});
|
|
21932
|
+
}
|
|
21877
21933
|
this.overlay.addEventListener("click", (e) => {
|
|
21878
21934
|
if (e.target === this.overlay) {
|
|
21879
21935
|
this.config.onClose();
|
|
@@ -21918,15 +21974,25 @@ var WaterTankModalView = class {
|
|
|
21918
21974
|
}
|
|
21919
21975
|
}
|
|
21920
21976
|
/**
|
|
21921
|
-
*
|
|
21977
|
+
* RFC-0107: Refresh chart when display mode changes
|
|
21978
|
+
*/
|
|
21979
|
+
refreshChart() {
|
|
21980
|
+
if (!this.modal) return;
|
|
21981
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
|
|
21982
|
+
const titleEl = this.modal.querySelector(".myio-water-tank-modal-body h3:last-of-type");
|
|
21983
|
+
if (titleEl) {
|
|
21984
|
+
titleEl.textContent = chartTitle;
|
|
21985
|
+
}
|
|
21986
|
+
this.renderCanvasChart();
|
|
21987
|
+
}
|
|
21988
|
+
/**
|
|
21989
|
+
* RFC-0107: Render chart using Canvas API
|
|
21990
|
+
* Shows water_level (m.c.a) or water_percentage (%) based on display mode
|
|
21922
21991
|
*/
|
|
21923
21992
|
renderCanvasChart() {
|
|
21924
21993
|
const canvas = document.getElementById("myio-water-tank-chart");
|
|
21925
21994
|
if (!canvas) return;
|
|
21926
|
-
const
|
|
21927
|
-
const points = data.telemetry.filter(
|
|
21928
|
-
(p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
|
|
21929
|
-
);
|
|
21995
|
+
const points = this.getChartDataPoints();
|
|
21930
21996
|
if (points.length < 2) return;
|
|
21931
21997
|
const ctx = canvas.getContext("2d");
|
|
21932
21998
|
if (!ctx) return;
|
|
@@ -21963,13 +22029,14 @@ var WaterTankModalView = class {
|
|
|
21963
22029
|
ctx.stroke();
|
|
21964
22030
|
ctx.fillText(`${value.toFixed(2)}`, padding.left - 8, y + 4);
|
|
21965
22031
|
}
|
|
22032
|
+
const yAxisLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21966
22033
|
ctx.save();
|
|
21967
22034
|
ctx.translate(15, height / 2);
|
|
21968
22035
|
ctx.rotate(-Math.PI / 2);
|
|
21969
22036
|
ctx.textAlign = "center";
|
|
21970
22037
|
ctx.fillStyle = "#666";
|
|
21971
22038
|
ctx.font = "12px Arial";
|
|
21972
|
-
ctx.fillText(
|
|
22039
|
+
ctx.fillText(yAxisLabel, 0, 0);
|
|
21973
22040
|
ctx.restore();
|
|
21974
22041
|
ctx.strokeStyle = "#ccc";
|
|
21975
22042
|
ctx.lineWidth = 1;
|
|
@@ -22055,6 +22122,13 @@ var WaterTankModalView = class {
|
|
|
22055
22122
|
if (applyDatesBtn) {
|
|
22056
22123
|
applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
|
|
22057
22124
|
}
|
|
22125
|
+
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
22126
|
+
if (displayModeSelect) {
|
|
22127
|
+
displayModeSelect.addEventListener("change", () => {
|
|
22128
|
+
this.chartDisplayMode = displayModeSelect.value;
|
|
22129
|
+
this.refreshChart();
|
|
22130
|
+
});
|
|
22131
|
+
}
|
|
22058
22132
|
requestAnimationFrame(() => {
|
|
22059
22133
|
this.renderCanvasChart();
|
|
22060
22134
|
});
|
|
@@ -22227,13 +22301,12 @@ var WaterTankModal = class {
|
|
|
22227
22301
|
}
|
|
22228
22302
|
/**
|
|
22229
22303
|
* Transform raw ThingsBoard response to our data points
|
|
22230
|
-
* RFC-0107:
|
|
22304
|
+
* RFC-0107: Keep ALL data points with their original keys (no deduplication)
|
|
22305
|
+
* This allows the chart to switch between water_level and water_percentage dynamically
|
|
22231
22306
|
*/
|
|
22232
22307
|
transformTelemetryData(rawData, keys) {
|
|
22233
22308
|
const allPoints = [];
|
|
22234
|
-
const
|
|
22235
|
-
const prioritizedKeys = displayKey && rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
|
|
22236
|
-
for (const key of prioritizedKeys) {
|
|
22309
|
+
for (const key of keys) {
|
|
22237
22310
|
if (rawData[key] && Array.isArray(rawData[key])) {
|
|
22238
22311
|
const keyPoints = rawData[key].map((point) => {
|
|
22239
22312
|
let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
|
|
@@ -22250,16 +22323,12 @@ var WaterTankModal = class {
|
|
|
22250
22323
|
}
|
|
22251
22324
|
}
|
|
22252
22325
|
allPoints.sort((a, b) => a.ts - b.ts);
|
|
22253
|
-
const
|
|
22254
|
-
const
|
|
22255
|
-
|
|
22256
|
-
if (!seenTimestamps.has(point.ts)) {
|
|
22257
|
-
seenTimestamps.add(point.ts);
|
|
22258
|
-
uniquePoints.push(point);
|
|
22259
|
-
}
|
|
22326
|
+
const keyCounts = {};
|
|
22327
|
+
for (const p of allPoints) {
|
|
22328
|
+
keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
|
|
22260
22329
|
}
|
|
22261
|
-
console.log(`[WaterTankModal] Transformed ${
|
|
22262
|
-
return
|
|
22330
|
+
console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
|
|
22331
|
+
return allPoints;
|
|
22263
22332
|
}
|
|
22264
22333
|
/**
|
|
22265
22334
|
* Calculate summary statistics from telemetry data
|
package/dist/index.js
CHANGED
|
@@ -21285,9 +21285,14 @@ var WaterTankModalView = class {
|
|
|
21285
21285
|
overlay = null;
|
|
21286
21286
|
modal = null;
|
|
21287
21287
|
i18n;
|
|
21288
|
+
chartDisplayMode = "water_level";
|
|
21289
|
+
// RFC-0107: Default to water_level (m.c.a)
|
|
21288
21290
|
constructor(config) {
|
|
21289
21291
|
this.config = config;
|
|
21290
21292
|
this.i18n = this.getI18n();
|
|
21293
|
+
if (config.params.displayKey) {
|
|
21294
|
+
this.chartDisplayMode = config.params.displayKey;
|
|
21295
|
+
}
|
|
21291
21296
|
}
|
|
21292
21297
|
/**
|
|
21293
21298
|
* Get i18n strings with defaults
|
|
@@ -21599,14 +21604,14 @@ var WaterTankModalView = class {
|
|
|
21599
21604
|
`;
|
|
21600
21605
|
}
|
|
21601
21606
|
/**
|
|
21602
|
-
* Render chart section
|
|
21607
|
+
* RFC-0107: Render chart section with display mode selector
|
|
21608
|
+
* Shows water_level (m.c.a) or water_percentage (%) based on user selection
|
|
21603
21609
|
*/
|
|
21604
21610
|
renderChart() {
|
|
21605
21611
|
const { data } = this.config;
|
|
21606
|
-
const
|
|
21607
|
-
|
|
21608
|
-
|
|
21609
|
-
if (waterLevelPoints.length === 0) {
|
|
21612
|
+
const chartPoints = this.getChartDataPoints();
|
|
21613
|
+
if (chartPoints.length === 0) {
|
|
21614
|
+
const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21610
21615
|
return `
|
|
21611
21616
|
<div style="
|
|
21612
21617
|
background: #f8f9fa;
|
|
@@ -21618,13 +21623,14 @@ var WaterTankModalView = class {
|
|
|
21618
21623
|
<div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
|
|
21619
21624
|
<div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
|
|
21620
21625
|
<div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
|
|
21621
|
-
No
|
|
21626
|
+
No ${this.chartDisplayMode} (${displayLabel}) data available for this period
|
|
21622
21627
|
</div>
|
|
21623
21628
|
</div>
|
|
21624
21629
|
`;
|
|
21625
21630
|
}
|
|
21626
|
-
const firstTs =
|
|
21627
|
-
const lastTs =
|
|
21631
|
+
const firstTs = chartPoints[0]?.ts;
|
|
21632
|
+
const lastTs = chartPoints[chartPoints.length - 1]?.ts;
|
|
21633
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
|
|
21628
21634
|
return `
|
|
21629
21635
|
<div style="
|
|
21630
21636
|
background: white;
|
|
@@ -21632,12 +21638,38 @@ var WaterTankModalView = class {
|
|
|
21632
21638
|
border-radius: 8px;
|
|
21633
21639
|
padding: 20px;
|
|
21634
21640
|
">
|
|
21635
|
-
<
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
"
|
|
21641
|
+
<div style="
|
|
21642
|
+
display: flex;
|
|
21643
|
+
align-items: center;
|
|
21644
|
+
justify-content: space-between;
|
|
21645
|
+
margin-bottom: 16px;
|
|
21646
|
+
">
|
|
21647
|
+
<h3 style="
|
|
21648
|
+
margin: 0;
|
|
21649
|
+
font-size: 16px;
|
|
21650
|
+
font-weight: 600;
|
|
21651
|
+
color: #2c3e50;
|
|
21652
|
+
">${chartTitle}</h3>
|
|
21653
|
+
<div style="
|
|
21654
|
+
display: flex;
|
|
21655
|
+
align-items: center;
|
|
21656
|
+
gap: 8px;
|
|
21657
|
+
">
|
|
21658
|
+
<span style="font-size: 13px; color: #7f8c8d;">Display:</span>
|
|
21659
|
+
<select id="myio-water-tank-display-mode" style="
|
|
21660
|
+
padding: 6px 12px;
|
|
21661
|
+
border: 1px solid #ddd;
|
|
21662
|
+
border-radius: 6px;
|
|
21663
|
+
font-size: 13px;
|
|
21664
|
+
color: #2c3e50;
|
|
21665
|
+
background: white;
|
|
21666
|
+
cursor: pointer;
|
|
21667
|
+
">
|
|
21668
|
+
<option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>Level (m.c.a)</option>
|
|
21669
|
+
<option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentage (%)</option>
|
|
21670
|
+
</select>
|
|
21671
|
+
</div>
|
|
21672
|
+
</div>
|
|
21641
21673
|
<canvas id="myio-water-tank-chart" style="width: 100%; height: 280px;"></canvas>
|
|
21642
21674
|
${firstTs && lastTs ? `
|
|
21643
21675
|
<div style="
|
|
@@ -21647,12 +21679,29 @@ var WaterTankModalView = class {
|
|
|
21647
21679
|
text-align: center;
|
|
21648
21680
|
">
|
|
21649
21681
|
${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
|
|
21650
|
-
(${
|
|
21682
|
+
(${chartPoints.length} readings)
|
|
21651
21683
|
</div>
|
|
21652
21684
|
` : ""}
|
|
21653
21685
|
</div>
|
|
21654
21686
|
`;
|
|
21655
21687
|
}
|
|
21688
|
+
/**
|
|
21689
|
+
* RFC-0107: Get chart data points based on current display mode
|
|
21690
|
+
*/
|
|
21691
|
+
getChartDataPoints() {
|
|
21692
|
+
const { data } = this.config;
|
|
21693
|
+
if (this.chartDisplayMode === "water_percentage") {
|
|
21694
|
+
const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
|
|
21695
|
+
return percentagePoints.map((p) => ({
|
|
21696
|
+
...p,
|
|
21697
|
+
value: p.value <= 1.5 ? p.value * 100 : p.value
|
|
21698
|
+
}));
|
|
21699
|
+
} else {
|
|
21700
|
+
return data.telemetry.filter(
|
|
21701
|
+
(p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
|
|
21702
|
+
);
|
|
21703
|
+
}
|
|
21704
|
+
}
|
|
21656
21705
|
/**
|
|
21657
21706
|
* Render footer with actions
|
|
21658
21707
|
*/
|
|
@@ -21702,6 +21751,13 @@ var WaterTankModalView = class {
|
|
|
21702
21751
|
if (applyDatesBtn) {
|
|
21703
21752
|
applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
|
|
21704
21753
|
}
|
|
21754
|
+
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21755
|
+
if (displayModeSelect) {
|
|
21756
|
+
displayModeSelect.addEventListener("change", () => {
|
|
21757
|
+
this.chartDisplayMode = displayModeSelect.value;
|
|
21758
|
+
this.refreshChart();
|
|
21759
|
+
});
|
|
21760
|
+
}
|
|
21705
21761
|
this.overlay.addEventListener("click", (e) => {
|
|
21706
21762
|
if (e.target === this.overlay) {
|
|
21707
21763
|
this.config.onClose();
|
|
@@ -21746,15 +21802,25 @@ var WaterTankModalView = class {
|
|
|
21746
21802
|
}
|
|
21747
21803
|
}
|
|
21748
21804
|
/**
|
|
21749
|
-
*
|
|
21805
|
+
* RFC-0107: Refresh chart when display mode changes
|
|
21806
|
+
*/
|
|
21807
|
+
refreshChart() {
|
|
21808
|
+
if (!this.modal) return;
|
|
21809
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
|
|
21810
|
+
const titleEl = this.modal.querySelector(".myio-water-tank-modal-body h3:last-of-type");
|
|
21811
|
+
if (titleEl) {
|
|
21812
|
+
titleEl.textContent = chartTitle;
|
|
21813
|
+
}
|
|
21814
|
+
this.renderCanvasChart();
|
|
21815
|
+
}
|
|
21816
|
+
/**
|
|
21817
|
+
* RFC-0107: Render chart using Canvas API
|
|
21818
|
+
* Shows water_level (m.c.a) or water_percentage (%) based on display mode
|
|
21750
21819
|
*/
|
|
21751
21820
|
renderCanvasChart() {
|
|
21752
21821
|
const canvas = document.getElementById("myio-water-tank-chart");
|
|
21753
21822
|
if (!canvas) return;
|
|
21754
|
-
const
|
|
21755
|
-
const points = data.telemetry.filter(
|
|
21756
|
-
(p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
|
|
21757
|
-
);
|
|
21823
|
+
const points = this.getChartDataPoints();
|
|
21758
21824
|
if (points.length < 2) return;
|
|
21759
21825
|
const ctx = canvas.getContext("2d");
|
|
21760
21826
|
if (!ctx) return;
|
|
@@ -21791,13 +21857,14 @@ var WaterTankModalView = class {
|
|
|
21791
21857
|
ctx.stroke();
|
|
21792
21858
|
ctx.fillText(`${value.toFixed(2)}`, padding.left - 8, y + 4);
|
|
21793
21859
|
}
|
|
21860
|
+
const yAxisLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21794
21861
|
ctx.save();
|
|
21795
21862
|
ctx.translate(15, height / 2);
|
|
21796
21863
|
ctx.rotate(-Math.PI / 2);
|
|
21797
21864
|
ctx.textAlign = "center";
|
|
21798
21865
|
ctx.fillStyle = "#666";
|
|
21799
21866
|
ctx.font = "12px Arial";
|
|
21800
|
-
ctx.fillText(
|
|
21867
|
+
ctx.fillText(yAxisLabel, 0, 0);
|
|
21801
21868
|
ctx.restore();
|
|
21802
21869
|
ctx.strokeStyle = "#ccc";
|
|
21803
21870
|
ctx.lineWidth = 1;
|
|
@@ -21883,6 +21950,13 @@ var WaterTankModalView = class {
|
|
|
21883
21950
|
if (applyDatesBtn) {
|
|
21884
21951
|
applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
|
|
21885
21952
|
}
|
|
21953
|
+
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21954
|
+
if (displayModeSelect) {
|
|
21955
|
+
displayModeSelect.addEventListener("change", () => {
|
|
21956
|
+
this.chartDisplayMode = displayModeSelect.value;
|
|
21957
|
+
this.refreshChart();
|
|
21958
|
+
});
|
|
21959
|
+
}
|
|
21886
21960
|
requestAnimationFrame(() => {
|
|
21887
21961
|
this.renderCanvasChart();
|
|
21888
21962
|
});
|
|
@@ -22055,13 +22129,12 @@ var WaterTankModal = class {
|
|
|
22055
22129
|
}
|
|
22056
22130
|
/**
|
|
22057
22131
|
* Transform raw ThingsBoard response to our data points
|
|
22058
|
-
* RFC-0107:
|
|
22132
|
+
* RFC-0107: Keep ALL data points with their original keys (no deduplication)
|
|
22133
|
+
* This allows the chart to switch between water_level and water_percentage dynamically
|
|
22059
22134
|
*/
|
|
22060
22135
|
transformTelemetryData(rawData, keys) {
|
|
22061
22136
|
const allPoints = [];
|
|
22062
|
-
const
|
|
22063
|
-
const prioritizedKeys = displayKey && rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
|
|
22064
|
-
for (const key of prioritizedKeys) {
|
|
22137
|
+
for (const key of keys) {
|
|
22065
22138
|
if (rawData[key] && Array.isArray(rawData[key])) {
|
|
22066
22139
|
const keyPoints = rawData[key].map((point) => {
|
|
22067
22140
|
let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
|
|
@@ -22078,16 +22151,12 @@ var WaterTankModal = class {
|
|
|
22078
22151
|
}
|
|
22079
22152
|
}
|
|
22080
22153
|
allPoints.sort((a, b) => a.ts - b.ts);
|
|
22081
|
-
const
|
|
22082
|
-
const
|
|
22083
|
-
|
|
22084
|
-
if (!seenTimestamps.has(point.ts)) {
|
|
22085
|
-
seenTimestamps.add(point.ts);
|
|
22086
|
-
uniquePoints.push(point);
|
|
22087
|
-
}
|
|
22154
|
+
const keyCounts = {};
|
|
22155
|
+
for (const p of allPoints) {
|
|
22156
|
+
keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
|
|
22088
22157
|
}
|
|
22089
|
-
console.log(`[WaterTankModal] Transformed ${
|
|
22090
|
-
return
|
|
22158
|
+
console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
|
|
22159
|
+
return allPoints;
|
|
22091
22160
|
}
|
|
22092
22161
|
/**
|
|
22093
22162
|
* Calculate summary statistics from telemetry data
|