|
68 | 68 | } |
69 | 69 | } |
70 | 70 | #estimateTime { |
71 | | - margin-left: 130px; |
72 | 71 | } |
73 | 72 |
|
74 | 73 | #sections { |
|
103 | 102 | } |
104 | 103 |
|
105 | 104 | #cellsSection { |
106 | | - margin-top: 10px; |
| 105 | + margin-top: 6px; |
107 | 106 | background-color: rgba(255, 255, 255, 0.1); |
108 | 107 | border-radius: 8px; |
109 | 108 |
|
110 | 109 | display: flex; |
111 | 110 | flex-direction: column; |
112 | 111 |
|
113 | | - .cells-title { |
114 | | - margin-left: 20px; |
| 112 | + .cellDetail { |
| 113 | + display: flex; |
| 114 | + flex-direction: column; |
| 115 | + gap: 6px; |
| 116 | + padding: 10px; |
| 117 | + text-align: center; |
115 | 118 | flex: 1; |
| 119 | + .cells-title { |
| 120 | + font-weight: bold; |
| 121 | + } |
| 122 | + .value { |
| 123 | + opacity: 0.7; |
| 124 | + } |
116 | 125 | } |
117 | 126 |
|
118 | 127 | .cells-diff-avg { |
|
133 | 142 |
|
134 | 143 | .cells-title-description { |
135 | 144 | display: flex; |
136 | | - height: 50px; |
| 145 | + flex-wrap: wrap; |
137 | 146 | align-items: center; |
138 | 147 | gap: 10px; |
| 148 | + border-bottom: solid 1px black; |
139 | 149 | } |
140 | | - .cell-item { |
141 | | - height: 50px; |
142 | | - border-top: solid 1px black; |
143 | | - padding-left: 20px; |
144 | | - padding-right: 10px; |
| 150 | + .cells { |
145 | 151 | display: flex; |
146 | | - align-items: center; |
| 152 | + flex-wrap: wrap; |
147 | 153 | } |
148 | | - .cell-title { |
| 154 | + .cell-item { |
149 | 155 | flex: 1; |
| 156 | + display: flex; |
| 157 | + flex-direction: column; |
| 158 | + align-items: center; |
| 159 | + padding: 10px; |
| 160 | + gap: 6px; |
| 161 | + justify-content: center; |
| 162 | + .cell-title { |
| 163 | + font-weight: bold; |
| 164 | + } |
150 | 165 | } |
| 166 | + |
151 | 167 | .cells-volt-bal { |
152 | 168 | font-variant-numeric: tabular-nums; |
153 | | - text-align: end; |
| 169 | + opacity: 0.7; |
154 | 170 | } |
155 | 171 | } |
156 | 172 |
|
|
192 | 208 | <div id="battery-fill"></div> |
193 | 209 | <div class="battery-positive"></div> |
194 | 210 | </div> |
195 | | - <div id="batteryPercent">0%</div> |
| 211 | + <div> |
| 212 | + <div id="batteryPercent">0%</div> |
| 213 | + <div id="estimateTime"></div> |
| 214 | + </div> |
196 | 215 | </div> |
197 | | - <div id="estimateTime"></div> |
198 | 216 | </div> |
199 | 217 |
|
200 | 218 | <div id="sections"></div> |
|
507 | 525 | const averageVoltage = |
508 | 526 | cellVolts.reduce((a, b) => a + b, 0) / cellVolts.length; |
509 | 527 |
|
| 528 | + const els = [ |
| 529 | + {id: 'cell-high', name: 'High', value: highVolt}, |
| 530 | + {id: 'cell-low', name: 'Low', value: lowVolt}, |
| 531 | + {id: 'cell-diff', name: 'Diff', value: voltageDiff}, |
| 532 | + {id: 'cell-avg', name: 'Avg', value: averageVoltage.toFixed(3)}, |
| 533 | + ]; |
| 534 | + |
510 | 535 | const element = ` |
511 | 536 | <div id="cellsSection"> |
| 537 | +
|
| 538 | +
|
512 | 539 | <div class="cells-title-description"> |
513 | | - <div class="cells-title">Cells</div> |
514 | | - <div class="cells-high-low"> |
515 | | - <div class="highvolt">High: ${highVolt}V</div> |
516 | | - <div class="lowvolt">Low: ${lowVolt}V</div> |
517 | | - </div> |
518 | | - <div class="cells-diff-avg"> |
519 | | - <div class="diff">Diff: ${voltageDiff}V</div> |
520 | | - <div class="avg">Avg: ${averageVoltage.toFixed(3)}V</div> |
521 | | - </div> |
| 540 | + ${els |
| 541 | + .map(el => { |
| 542 | + let existingEl = document.getElementById(el.id); |
| 543 | + if (existingEl) { |
| 544 | + const newNum = parseFloat(el.value); |
| 545 | + const oldNum = parseFloat( |
| 546 | + existingEl.getAttribute('data-value'), |
| 547 | + ); |
| 548 | + console.log(newNum, oldNum); |
| 549 | + if (oldNum !== newNum) { |
| 550 | + setTimeout(() => { |
| 551 | + let existingEl = document.getElementById(el.id); |
| 552 | + existingEl.style.animation = |
| 553 | + (newNum > oldNum ? 'fadeGreen' : 'fadeRed') + |
| 554 | + ' 1.5s'; |
| 555 | + setTimeout(() => { |
| 556 | + existingEl.style.animation = ''; |
| 557 | + }, 1500); |
| 558 | + }, 0); |
| 559 | + } |
| 560 | + } |
| 561 | + return ` |
| 562 | + <div class="cellDetail"> |
| 563 | + <div class="cells-title">${el.name}</div> |
| 564 | + <div class="value" id="${el.id}" data-value=${el.value}>${el.value}V</div> |
| 565 | + </div> |
| 566 | + `; |
| 567 | + }) |
| 568 | + .join('')} |
522 | 569 | </div> |
523 | 570 |
|
524 | | - ${balanceStatus |
525 | | - .map((v, i) => { |
526 | | - const id = `cells-volt-bal-${i}`; |
527 | | - if (!v) { |
528 | | - delete estimateBalanceCells[i]; |
529 | | - } |
530 | | - let bde; |
531 | | - if (v) { |
532 | | - bde = |
533 | | - estimateBalanceCells[i] || |
534 | | - new BatteryDischargeEstimator( |
535 | | - cellVolts[i], |
536 | | - cellVolts[indicesOfLow[0]], |
| 571 | +
|
| 572 | + <div class="cells"> |
| 573 | + ${balanceStatus |
| 574 | + .map((v, i) => { |
| 575 | + const id = `cells-volt-bal-${i}`; |
| 576 | + if (!v) { |
| 577 | + delete estimateBalanceCells[i]; |
| 578 | + } |
| 579 | + let bde; |
| 580 | + if (v) { |
| 581 | + bde = |
| 582 | + estimateBalanceCells[i] || |
| 583 | + new BatteryDischargeEstimator( |
| 584 | + cellVolts[i], |
| 585 | + cellVolts[indicesOfLow[0]], |
| 586 | + ); |
| 587 | + bde.recordVoltage(cellVolts[i]); |
| 588 | + estimateBalanceCells[i] = bde; |
| 589 | + } |
| 590 | + const remainingBalTime = bde?.estimateRemainingTime(); |
| 591 | +
|
| 592 | + let existingEl = document.getElementById(id); |
| 593 | + const text = `${ |
| 594 | + v |
| 595 | + ? `(Bal${ |
| 596 | + remainingBalTime |
| 597 | + ? ' Est ' + remainingBalTime.toFixed(2) + 'h' |
| 598 | + : '' |
| 599 | + }) ` |
| 600 | + : ' ' |
| 601 | + }${cellVolts[i].toFixed(3)}V`; |
| 602 | +
|
| 603 | + if (existingEl) { |
| 604 | + const newNum = cellVolts[i]; |
| 605 | + const oldNum = parseFloat( |
| 606 | + existingEl.getAttribute('data-volt'), |
537 | 607 | ); |
538 | | - bde.recordVoltage(cellVolts[i]); |
539 | | - estimateBalanceCells[i] = bde; |
540 | | - } |
541 | | - const remainingBalTime = bde?.estimateRemainingTime(); |
542 | | -
|
543 | | - let existingEl = document.getElementById(id); |
544 | | - const text = `${ |
545 | | - v |
546 | | - ? `(Bal${ |
547 | | - remainingBalTime |
548 | | - ? ' Est ' + remainingBalTime.toFixed(2) + 'h' |
549 | | - : '' |
550 | | - }) ` |
551 | | - : ' ' |
552 | | - }${cellVolts[i].toFixed(3)}V`; |
553 | | -
|
554 | | - if (existingEl) { |
555 | | - const newNum = cellVolts[i]; |
556 | | - const oldNum = parseFloat( |
557 | | - existingEl.getAttribute('data-volt'), |
558 | | - ); |
559 | | -
|
560 | | - if (oldNum !== newNum) { |
561 | | - setTimeout(() => { |
562 | | - existingEl = document.getElementById(id); |
563 | | - existingEl.style.animation = |
564 | | - (newNum > oldNum ? 'fadeGreen' : 'fadeRed') + |
565 | | - ' 1.5s'; |
| 608 | +
|
| 609 | + if (oldNum !== newNum) { |
566 | 610 | setTimeout(() => { |
567 | | - existingEl.style.animation = ''; |
568 | | - }, 1500); |
569 | | - }, 0); |
| 611 | + existingEl = document.getElementById(id); |
| 612 | + existingEl.style.animation = |
| 613 | + (newNum > oldNum ? 'fadeGreen' : 'fadeRed') + |
| 614 | + ' 1.5s'; |
| 615 | + setTimeout(() => { |
| 616 | + existingEl.style.animation = ''; |
| 617 | + }, 1500); |
| 618 | + }, 0); |
| 619 | + } |
570 | 620 | } |
571 | | - } |
572 | | -
|
573 | | - return ` |
574 | | - <div class="cell-item" > |
575 | | - <div class="cell-title">${i + 1} </div> |
576 | | - <div class="cells-volt-bal" id="${id}" data-volt="${ |
577 | | - cellVolts[i] |
578 | | - }"> |
579 | | - ${highVoltageIndex === i ? '🟢' : ''} |
580 | | - ${lowVoltageIndex === i ? '🔴' : ''} |
| 621 | +
|
| 622 | + return ` |
| 623 | + <div class="cell-item"> |
| 624 | + <div class="cell-title">Cell ${i + 1} </div> |
| 625 | + <div class="cells-volt-bal" id="${id}" data-volt="${ |
| 626 | + cellVolts[i] |
| 627 | + }"> |
581 | 628 | ${text} |
| 629 | + </div> |
| 630 | + <span> |
| 631 | + ${(() => { |
| 632 | + const off = |
| 633 | + '<span style="filter: grayscale(100%);">🔴</span>'; |
| 634 | +
|
| 635 | + const isHigh = indicesOfHigh.includes(i); |
| 636 | + const isLow = indicesOfLow.includes(i); |
| 637 | +
|
| 638 | + if (isHigh) { |
| 639 | + return '🟢'; |
| 640 | + } |
| 641 | + if (isLow) { |
| 642 | + return '🔴'; |
| 643 | + } |
| 644 | + return off; |
| 645 | + })()} |
| 646 | + </span> |
| 647 | +
|
| 648 | +
|
582 | 649 | </div> |
| 650 | + `; |
| 651 | + }) |
| 652 | + .join('')} |
583 | 653 | </div> |
584 | | - `; |
585 | | - }) |
586 | | - .join('')} |
587 | | -
|
588 | 654 | </div> |
589 | 655 | `; |
590 | 656 |
|
|
671 | 737 | 'remaining-capacity', |
672 | 738 | ' Capacity', |
673 | 739 | '', |
674 | | - info.remainingCapacityAh + 'Ah', |
| 740 | + info.remainingCapacityAh.toFixed(2) + 'Ah', |
675 | 741 | ); |
676 | 742 |
|
677 | 743 | createOrUpdateSection( |
|
0 commit comments