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.
@@ -21099,9 +21099,14 @@
21099
21099
  overlay = null;
21100
21100
  modal = null;
21101
21101
  i18n;
21102
+ chartDisplayMode = "water_level";
21103
+ // RFC-0107: Default to water_level (m.c.a)
21102
21104
  constructor(config) {
21103
21105
  this.config = config;
21104
21106
  this.i18n = this.getI18n();
21107
+ if (config.params.displayKey) {
21108
+ this.chartDisplayMode = config.params.displayKey;
21109
+ }
21105
21110
  }
21106
21111
  /**
21107
21112
  * Get i18n strings with defaults
@@ -21413,14 +21418,14 @@
21413
21418
  `;
21414
21419
  }
21415
21420
  /**
21416
- * Render chart section - shows water_level (m.c.a) over time
21421
+ * RFC-0107: Render chart section with display mode selector
21422
+ * Shows water_level (m.c.a) or water_percentage (%) based on user selection
21417
21423
  */
21418
21424
  renderChart() {
21419
21425
  const { data } = this.config;
21420
- const waterLevelPoints = data.telemetry.filter(
21421
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21422
- );
21423
- if (waterLevelPoints.length === 0) {
21426
+ const chartPoints = this.getChartDataPoints();
21427
+ if (chartPoints.length === 0) {
21428
+ const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21424
21429
  return `
21425
21430
  <div style="
21426
21431
  background: #f8f9fa;
@@ -21432,13 +21437,14 @@
21432
21437
  <div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
21433
21438
  <div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
21434
21439
  <div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
21435
- No water_level (m.c.a) data available for this period
21440
+ No ${this.chartDisplayMode} (${displayLabel}) data available for this period
21436
21441
  </div>
21437
21442
  </div>
21438
21443
  `;
21439
21444
  }
21440
- const firstTs = waterLevelPoints[0]?.ts;
21441
- const lastTs = waterLevelPoints[waterLevelPoints.length - 1]?.ts;
21445
+ const firstTs = chartPoints[0]?.ts;
21446
+ const lastTs = chartPoints[chartPoints.length - 1]?.ts;
21447
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21442
21448
  return `
21443
21449
  <div style="
21444
21450
  background: white;
@@ -21446,12 +21452,38 @@
21446
21452
  border-radius: 8px;
21447
21453
  padding: 20px;
21448
21454
  ">
21449
- <h3 style="
21450
- margin: 0 0 16px 0;
21451
- font-size: 16px;
21452
- font-weight: 600;
21453
- color: #2c3e50;
21454
- ">${this.i18n.levelChart}</h3>
21455
+ <div style="
21456
+ display: flex;
21457
+ align-items: center;
21458
+ justify-content: space-between;
21459
+ margin-bottom: 16px;
21460
+ ">
21461
+ <h3 style="
21462
+ margin: 0;
21463
+ font-size: 16px;
21464
+ font-weight: 600;
21465
+ color: #2c3e50;
21466
+ ">${chartTitle}</h3>
21467
+ <div style="
21468
+ display: flex;
21469
+ align-items: center;
21470
+ gap: 8px;
21471
+ ">
21472
+ <span style="font-size: 13px; color: #7f8c8d;">Display:</span>
21473
+ <select id="myio-water-tank-display-mode" style="
21474
+ padding: 6px 12px;
21475
+ border: 1px solid #ddd;
21476
+ border-radius: 6px;
21477
+ font-size: 13px;
21478
+ color: #2c3e50;
21479
+ background: white;
21480
+ cursor: pointer;
21481
+ ">
21482
+ <option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>Level (m.c.a)</option>
21483
+ <option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentage (%)</option>
21484
+ </select>
21485
+ </div>
21486
+ </div>
21455
21487
  <canvas id="myio-water-tank-chart" style="width: 100%; height: 280px;"></canvas>
21456
21488
  ${firstTs && lastTs ? `
21457
21489
  <div style="
@@ -21461,12 +21493,29 @@
21461
21493
  text-align: center;
21462
21494
  ">
21463
21495
  ${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
21464
- (${waterLevelPoints.length} readings)
21496
+ (${chartPoints.length} readings)
21465
21497
  </div>
21466
21498
  ` : ""}
21467
21499
  </div>
21468
21500
  `;
21469
21501
  }
21502
+ /**
21503
+ * RFC-0107: Get chart data points based on current display mode
21504
+ */
21505
+ getChartDataPoints() {
21506
+ const { data } = this.config;
21507
+ if (this.chartDisplayMode === "water_percentage") {
21508
+ const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
21509
+ return percentagePoints.map((p) => ({
21510
+ ...p,
21511
+ value: p.value <= 1.5 ? p.value * 100 : p.value
21512
+ }));
21513
+ } else {
21514
+ return data.telemetry.filter(
21515
+ (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21516
+ );
21517
+ }
21518
+ }
21470
21519
  /**
21471
21520
  * Render footer with actions
21472
21521
  */
@@ -21516,6 +21565,13 @@
21516
21565
  if (applyDatesBtn) {
21517
21566
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
21518
21567
  }
21568
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
21569
+ if (displayModeSelect) {
21570
+ displayModeSelect.addEventListener("change", () => {
21571
+ this.chartDisplayMode = displayModeSelect.value;
21572
+ this.refreshChart();
21573
+ });
21574
+ }
21519
21575
  this.overlay.addEventListener("click", (e) => {
21520
21576
  if (e.target === this.overlay) {
21521
21577
  this.config.onClose();
@@ -21560,15 +21616,25 @@
21560
21616
  }
21561
21617
  }
21562
21618
  /**
21563
- * Render chart using Canvas API - shows water_level (m.c.a) over time
21619
+ * RFC-0107: Refresh chart when display mode changes
21620
+ */
21621
+ refreshChart() {
21622
+ if (!this.modal) return;
21623
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21624
+ const titleEl = this.modal.querySelector(".myio-water-tank-modal-body h3:last-of-type");
21625
+ if (titleEl) {
21626
+ titleEl.textContent = chartTitle;
21627
+ }
21628
+ this.renderCanvasChart();
21629
+ }
21630
+ /**
21631
+ * RFC-0107: Render chart using Canvas API
21632
+ * Shows water_level (m.c.a) or water_percentage (%) based on display mode
21564
21633
  */
21565
21634
  renderCanvasChart() {
21566
21635
  const canvas = document.getElementById("myio-water-tank-chart");
21567
21636
  if (!canvas) return;
21568
- const { data } = this.config;
21569
- const points = data.telemetry.filter(
21570
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21571
- );
21637
+ const points = this.getChartDataPoints();
21572
21638
  if (points.length < 2) return;
21573
21639
  const ctx = canvas.getContext("2d");
21574
21640
  if (!ctx) return;
@@ -21605,13 +21671,14 @@
21605
21671
  ctx.stroke();
21606
21672
  ctx.fillText(`${value.toFixed(2)}`, padding.left - 8, y + 4);
21607
21673
  }
21674
+ const yAxisLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21608
21675
  ctx.save();
21609
21676
  ctx.translate(15, height / 2);
21610
21677
  ctx.rotate(-Math.PI / 2);
21611
21678
  ctx.textAlign = "center";
21612
21679
  ctx.fillStyle = "#666";
21613
21680
  ctx.font = "12px Arial";
21614
- ctx.fillText("m.c.a", 0, 0);
21681
+ ctx.fillText(yAxisLabel, 0, 0);
21615
21682
  ctx.restore();
21616
21683
  ctx.strokeStyle = "#ccc";
21617
21684
  ctx.lineWidth = 1;
@@ -21697,6 +21764,13 @@
21697
21764
  if (applyDatesBtn) {
21698
21765
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
21699
21766
  }
21767
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
21768
+ if (displayModeSelect) {
21769
+ displayModeSelect.addEventListener("change", () => {
21770
+ this.chartDisplayMode = displayModeSelect.value;
21771
+ this.refreshChart();
21772
+ });
21773
+ }
21700
21774
  requestAnimationFrame(() => {
21701
21775
  this.renderCanvasChart();
21702
21776
  });
@@ -21869,13 +21943,12 @@
21869
21943
  }
21870
21944
  /**
21871
21945
  * Transform raw ThingsBoard response to our data points
21872
- * RFC-0107: Support displayKey option to choose between water_level or water_percentage
21946
+ * RFC-0107: Keep ALL data points with their original keys (no deduplication)
21947
+ * This allows the chart to switch between water_level and water_percentage dynamically
21873
21948
  */
21874
21949
  transformTelemetryData(rawData, keys) {
21875
21950
  const allPoints = [];
21876
- const displayKey = this.options.displayKey || "water_percentage";
21877
- const prioritizedKeys = rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
21878
- for (const key of prioritizedKeys) {
21951
+ for (const key of keys) {
21879
21952
  if (rawData[key] && Array.isArray(rawData[key])) {
21880
21953
  const keyPoints = rawData[key].map((point) => {
21881
21954
  let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
@@ -21892,16 +21965,12 @@
21892
21965
  }
21893
21966
  }
21894
21967
  allPoints.sort((a, b) => a.ts - b.ts);
21895
- const uniquePoints = [];
21896
- const seenTimestamps = /* @__PURE__ */ new Set();
21897
- for (const point of allPoints) {
21898
- if (!seenTimestamps.has(point.ts)) {
21899
- seenTimestamps.add(point.ts);
21900
- uniquePoints.push(point);
21901
- }
21968
+ const keyCounts = {};
21969
+ for (const p of allPoints) {
21970
+ keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
21902
21971
  }
21903
- console.log(`[WaterTankModal] Transformed ${uniquePoints.length} points, displayKey: ${displayKey}`);
21904
- return uniquePoints;
21972
+ console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
21973
+ return allPoints;
21905
21974
  }
21906
21975
  /**
21907
21976
  * Calculate summary statistics from telemetry data