Energyflow: keep small consumption segments visible (#30781)

This commit is contained in:
andig 2026-06-14 16:11:43 +02:00 • committed by GitHub
parent 4982bcc025
commit 359e053a40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 53 deletions

View file

@ -3,6 +3,7 @@
class="label-bar"
:class="{
'label-bar--hide-icon': hideIcon,
'label-bar--hide-dot': hideDot,
'label-bar--hidden': !value,
'label-bar--top': top,
'label-bar--bottom': bottom,
@ -26,6 +27,7 @@ export default defineComponent({
props: {
value: { type: Number, default: 0 },
hideIcon: { type: Boolean },
hideDot: { type: Boolean },
top: { type: Boolean },
bottom: { type: Boolean },
first: { type: Boolean },
@ -90,6 +92,9 @@ export default defineComponent({
border-width: 1.5rem;
transition-delay: 400ms, 0s;
}
.label-bar--hide-dot .label-bar-icon {
transform: scale(0);
}
.label-bar--hidden {
opacity: 0;
}

View file

@ -22,7 +22,7 @@
<div class="label-scale-name">In</div>
</div>
<div ref="site_progress" class="site-progress">
<div class="site-progress-bar self-pv" :style="{ width: widthTotal(selfPvAdjusted) }">
<div class="site-progress-bar self-pv" :style="{ width: widthTotal(selfPv) }">
<AnimatedNumber
v-if="selfPv && visualizationReady"
class="power"
@ -30,10 +30,7 @@
:format="fmtBarValue"
/>
</div>
<div
class="site-progress-bar self-battery"
:style="{ width: widthTotal(selfBatteryAdjusted) }"
>
<div class="site-progress-bar self-battery" :style="{ width: widthTotal(selfBattery) }">
<AnimatedNumber
v-if="selfBattery && visualizationReady"
class="power"
@ -41,10 +38,7 @@
:format="fmtBarValue"
/>
</div>
<div
class="site-progress-bar grid-import"
:style="{ width: widthTotal(gridImportAdjusted) }"
>
<div class="site-progress-bar grid-import" :style="{ width: widthTotal(gridImport) }">
<AnimatedNumber
v-if="gridImport && visualizationReady"
class="power"
@ -52,10 +46,7 @@
:format="fmtBarValue"
/>
</div>
<div
class="site-progress-bar pv-export"
:style="{ width: widthTotal(pvExportAdjusted) }"
>
<div class="site-progress-bar pv-export" :style="{ width: widthTotal(pvExport) }">
<AnimatedNumber
v-if="pvExport && visualizationReady"
class="power"
@ -74,7 +65,7 @@
:format="fmtBarValue"
/>
</div>
<div v-if="totalAdjusted <= 0" class="site-progress-bar w-100 grid-import">
<div v-if="total <= 0" class="site-progress-bar w-100 grid-import">
<span>{{ fmtW(0, POWER_UNIT.AUTO, true) }}</span>
</div>
</div>
@ -93,7 +84,7 @@
<LabelBar v-bind="labelBarProps('bottom', 'batteryCharge')">
<BatteryIcon :soc="batterySoc" :gridCharge="batteryGridCharge" />
</LabelBar>
<LabelBar v-bind="labelBarProps('bottom', 'gridExport')">
<LabelBar v-bind="labelBarProps('bottom', 'pvExport')">
<shopicon-regular-powersupply></shopicon-regular-powersupply>
</LabelBar>
<LabelBar v-bind="labelBarProps('bottom', 'unknownOutput')">
@ -143,32 +134,9 @@ export default defineComponent({
return { width: 0, transitionsEnabled: false };
},
computed: {
gridExport() {
return this.applyThreshold(this.pvExport);
},
totalRaw() {
total() {
return this.gridImport + this.selfPv + this.selfBattery + this.pvExport;
},
gridImportAdjusted() {
return this.applyThreshold(this.gridImport);
},
selfPvAdjusted() {
return this.applyThreshold(this.selfPv);
},
selfBatteryAdjusted() {
return this.applyThreshold(this.selfBattery);
},
pvExportAdjusted() {
return this.applyThreshold(this.pvExport);
},
totalAdjusted() {
return (
this.gridImportAdjusted +
this.selfPvAdjusted +
this.selfBatteryAdjusted +
this.pvExportAdjusted
);
},
unknownImport() {
// input/output mismatch > 10%
return this.applyThreshold(Math.max(0, this.outPower - this.inPower), 10);
@ -180,12 +148,12 @@ export default defineComponent({
unknownPower() {
if (this.unknownImport || this.unknownOutput) {
const total = Math.max(this.inPower, this.outPower);
return Math.abs(total - this.totalAdjusted);
return Math.abs(total - this.total);
}
return 0;
},
visualizationReady() {
return this.totalAdjusted > 0 && this.width > 0;
return this.total > 0 && this.width > 0;
},
},
@ -212,8 +180,8 @@ export default defineComponent({
},
methods: {
widthTotal(power: number) {
if (this.totalAdjusted === 0 || power === 0) return "0";
return (100 / this.totalAdjusted) * power + "%";
if (this.total === 0 || power === 0) return "0";
return (100 / this.total) * power + "%";
},
fmtBarValue(watt: number) {
if (!this.enoughSpaceForValue(watt)) {
@ -223,8 +191,8 @@ export default defineComponent({
return this.fmtW(watt, this.powerUnit, withUnit);
},
powerLabelAvailableSpace(power: number) {
if (this.totalAdjusted === 0) return 0;
const percent = (100 / this.totalAdjusted) * power;
if (this.total === 0) return 0;
const percent = (100 / this.total) * power;
return (this.width / 100) * percent;
},
enoughSpaceForValue(power: number) {
@ -233,13 +201,8 @@ export default defineComponent({
enoughSpaceForUnit(power: number) {
return this.powerLabelAvailableSpace(power) > 60;
},
hideLabelIcon(power: number, minWidth = 32) {
if (this.totalAdjusted === 0) return true;
const percent = (100 / this.totalAdjusted) * power;
return (this.width / 100) * percent < minWidth;
},
applyThreshold(power: number, threshold = 2) {
const percent = (100 / this.totalRaw) * power;
const percent = (100 / this.total) * power;
return percent < threshold ? 0 : power;
},
updateElementWidth() {
@ -247,10 +210,13 @@ export default defineComponent({
},
labelBarProps(position: string, name: string, val?: number) {
const value = val === undefined ? (this as any)[name] : val;
const minWidth = 40;
const space = this.powerLabelAvailableSpace(value);
return {
value,
hideIcon: this.hideLabelIcon(value, minWidth),
// shrink the icon to an anonymous dot when the bar gets narrow,
// drop the dot once the bar is too thin to render it cleanly
hideIcon: space < 40,
hideDot: space < 16,
style: { "flex-basis": this.widthTotal(value) },
[position]: true,
};