History: normalize tooltip units, add total row (#32262)
This commit is contained in:
parent
03a8c744d0
commit
ce75e49192
6 changed files with 81 additions and 39 deletions
|
|
@ -466,14 +466,9 @@ export default defineComponent({
|
|||
return Math.max(0, this.gridPower * -1);
|
||||
},
|
||||
powerUnit() {
|
||||
const watt = Math.max(this.gridImport, this.selfPv, this.selfBattery, this.pvExport);
|
||||
if (watt >= 1_000_000) {
|
||||
return POWER_UNIT.MW;
|
||||
} else if (watt >= 1000) {
|
||||
return POWER_UNIT.KW;
|
||||
} else {
|
||||
return POWER_UNIT.W;
|
||||
}
|
||||
return this.getPowerUnit(
|
||||
Math.max(this.gridImport, this.selfPv, this.selfBattery, this.pvExport)
|
||||
);
|
||||
},
|
||||
inPower() {
|
||||
return this.gridImport + this.pvProduction + this.batteryDischarge;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ export function tooltipStyle(
|
|||
export interface TooltipRow {
|
||||
name?: string;
|
||||
values: string[];
|
||||
total?: boolean;
|
||||
}
|
||||
|
||||
// Shared tooltip: bold date headline, non-bold rows, optional name + value columns.
|
||||
|
|
@ -127,28 +128,40 @@ export function tooltipTable(head: string, rows: TooltipRow[], headers?: string[
|
|||
const hasName = rows.some((r) => r.name != null);
|
||||
const valueCols = Math.max(1, ...rows.map((r) => r.values.length));
|
||||
const colCount = (hasName ? 1 : 0) + valueCols;
|
||||
// No name col + two value cols: first col left-aligned, second right-aligned.
|
||||
// Otherwise: lone value centers, multiple/named columns right-align.
|
||||
const valClsFn = (i: number): string => {
|
||||
if (!hasName && valueCols > 1 && i === 0) return "fw-normal text-start";
|
||||
if (hasName || valueCols > 1) return "fw-normal text-end ps-3";
|
||||
return "fw-normal text-center";
|
||||
// first of two unnamed value cols
|
||||
if (!hasName && valueCols > 1 && i === 0) return "text-start";
|
||||
// named or multiple cols
|
||||
if (hasName || valueCols > 1) return "text-end ps-3";
|
||||
// lone value
|
||||
return "text-center";
|
||||
};
|
||||
const headerRow = headers?.length
|
||||
? `<tr>${hasName ? "<td></td>" : ""}${headers
|
||||
.map((h, i) => `<td class="${valClsFn(i)}">${h}</td>`)
|
||||
.map((h, i) => `<td class="fw-normal tabular ${valClsFn(i)}">${h}</td>`)
|
||||
.join("")}</tr>`
|
||||
: "";
|
||||
const body = rows
|
||||
.map((r) => {
|
||||
const rowHtml = (r: TooltipRow) => {
|
||||
const cls = r.total ? " pt-1" : "";
|
||||
const nameTd = hasName
|
||||
? `<td class="fw-normal text-start">${escapeHtml(r.name ?? "")}</td>`
|
||||
? `<td class="fw-normal text-start${cls}">${escapeHtml(r.name ?? "")}</td>`
|
||||
: "";
|
||||
const valTds = r.values.map((v, i) => `<td class="${valClsFn(i)}">${v}</td>`).join("");
|
||||
return `<tr>${nameTd}${valTds}</tr>`;
|
||||
})
|
||||
const valTds = r.values
|
||||
.map((v, i) => `<td class="fw-normal tabular ${valClsFn(i)}${cls}">${v}</td>`)
|
||||
.join("");
|
||||
return `<table class="lh-sm"><thead><tr><th colspan="${colCount}" class="fw-bold text-center">${head}</th></tr></thead><tbody>${headerRow}${body}</tbody></table>`;
|
||||
return `<tr>${nameTd}${valTds}</tr>`;
|
||||
};
|
||||
const body = rows
|
||||
.filter((r) => !r.total)
|
||||
.map(rowHtml)
|
||||
.join("");
|
||||
const footRows = rows.filter((r) => r.total);
|
||||
const foot = footRows.length
|
||||
? `<tfoot><tr><td colspan="${colCount}" class="pt-1 border-bottom"></td></tr>${footRows
|
||||
.map(rowHtml)
|
||||
.join("")}</tfoot>`
|
||||
: "";
|
||||
return `<table class="lh-sm"><thead><tr><th colspan="${colCount}" class="fw-bold text-center pb-1">${head}</th></tr></thead><tbody>${headerRow}${body}</tbody>${foot}</table>`;
|
||||
}
|
||||
|
||||
export function forecastGrid() {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
tooltipStyle,
|
||||
tooltipTable,
|
||||
xAxisLabelStyle,
|
||||
type TooltipRow,
|
||||
} from "../Forecast/echarts";
|
||||
import colors, { resolveColors, deviceColorMap, darken, batteryColor, setAlpha } from "@/colors";
|
||||
import store from "@/store";
|
||||
|
|
@ -528,12 +529,6 @@ export default defineComponent({
|
|||
if (!first) return "";
|
||||
const ts = cats[first.dataIndex];
|
||||
const head = ts != null ? tooltipDate(ts) : "";
|
||||
const formatValue = (v: number) => {
|
||||
const watts = Math.abs(v) * 1000;
|
||||
return this.period === PERIODS.DAY
|
||||
? this.fmtW(watts, POWER_UNIT.AUTO)
|
||||
: this.fmtWh(watts, POWER_UNIT.AUTO);
|
||||
};
|
||||
|
||||
// Collect energy/returnEnergy values per entity from this slot's params.
|
||||
const totals = new Map<number, { energy: number; returnEnergy: number }>();
|
||||
|
|
@ -559,8 +554,29 @@ export default defineComponent({
|
|||
);
|
||||
const showName = this.series.length > 1 && this.focusedEntity === null;
|
||||
|
||||
const rows = indices.map((i) => {
|
||||
const t = totals.get(i) ?? { energy: 0, returnEnergy: 0 };
|
||||
// one unit for all rows, based on the largest individual value (not the total)
|
||||
const rowValues = indices.map(
|
||||
(i) => totals.get(i) ?? { energy: 0, returnEnergy: 0 }
|
||||
);
|
||||
const unit = this.getPowerUnit(
|
||||
Math.max(
|
||||
0,
|
||||
...rowValues.flatMap((t) =>
|
||||
this.isBidirectional
|
||||
? [t.energy, t.returnEnergy]
|
||||
: [t.energy + t.returnEnergy]
|
||||
)
|
||||
) * 1000
|
||||
);
|
||||
const formatValue = (v: number) => {
|
||||
const watts = Math.abs(v) * 1000;
|
||||
return this.period === PERIODS.DAY
|
||||
? this.fmtW(watts, unit)
|
||||
: this.fmtWh(watts, unit);
|
||||
};
|
||||
|
||||
const rows: TooltipRow[] = indices.map((i, idx) => {
|
||||
const t = rowValues[idx] ?? { energy: 0, returnEnergy: 0 };
|
||||
const values = this.isBidirectional
|
||||
? [formatValue(t.energy), formatValue(t.returnEnergy)]
|
||||
: [formatValue(t.energy + t.returnEnergy)];
|
||||
|
|
@ -569,6 +585,17 @@ export default defineComponent({
|
|||
values,
|
||||
};
|
||||
});
|
||||
if (showName) {
|
||||
const sum = (key: "energy" | "returnEnergy") =>
|
||||
rowValues.reduce((acc, t) => acc + t[key], 0);
|
||||
rows.push({
|
||||
name: this.$t("sessions.total"),
|
||||
values: this.isBidirectional
|
||||
? [formatValue(sum("energy")), formatValue(sum("returnEnergy"))]
|
||||
: [formatValue(sum("energy") + sum("returnEnergy"))],
|
||||
total: true,
|
||||
});
|
||||
}
|
||||
return tooltipTable(head, rows, this.directionHeaders ?? undefined);
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,6 +56,16 @@ describe("fmtW", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("getPowerUnit", () => {
|
||||
test("should pick unit based on largest value", () => {
|
||||
expect(fmt.getPowerUnit(0)).eq(POWER_UNIT.W);
|
||||
expect(fmt.getPowerUnit(999)).eq(POWER_UNIT.W);
|
||||
expect(fmt.getPowerUnit(1000)).eq(POWER_UNIT.KW);
|
||||
expect(fmt.getPowerUnit(9_999_999)).eq(POWER_UNIT.KW);
|
||||
expect(fmt.getPowerUnit(10_000_000)).eq(POWER_UNIT.MW);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fmtWh", () => {
|
||||
test("should format with units", () => {
|
||||
expect(fmt.fmtWh(0, POWER_UNIT.AUTO)).eq("0,0 kWh");
|
||||
|
|
|
|||
|
|
@ -73,17 +73,14 @@ export default defineComponent({
|
|||
const base = 10 ** precision;
|
||||
return (Math.round(num * base) / base).toFixed(precision);
|
||||
},
|
||||
getPowerUnit(watt: number): POWER_UNIT {
|
||||
return watt >= 10_000_000 ? POWER_UNIT.MW : watt >= 1000 ? POWER_UNIT.KW : POWER_UNIT.W;
|
||||
},
|
||||
fmtW(watt = 0, format = POWER_UNIT.KW, withUnit = true, digits?: number) {
|
||||
let unit = format;
|
||||
let d = digits;
|
||||
if (POWER_UNIT.AUTO === unit) {
|
||||
if (watt >= 10_000_000) {
|
||||
unit = POWER_UNIT.MW;
|
||||
} else if (watt >= 1000 || 0 === watt) {
|
||||
unit = POWER_UNIT.KW;
|
||||
} else {
|
||||
unit = POWER_UNIT.W;
|
||||
}
|
||||
unit = watt === 0 ? POWER_UNIT.KW : this.getPowerUnit(watt);
|
||||
}
|
||||
let value = watt;
|
||||
if (POWER_UNIT.KW === unit) {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ test("tooltip shows one merged grid entity", async ({ page }) => {
|
|||
|
||||
const tooltip = chart.locator("table");
|
||||
await expect(tooltip).toBeVisible();
|
||||
// single unnamed row, no per-entity rows
|
||||
// single unnamed row, no per-entity rows; one unit across both columns
|
||||
await expect(tooltip).toHaveText(
|
||||
["12:00 – 12:15", "imported", "exported", "2.0 kW", "400 W"].join("")
|
||||
["12:00 – 12:15", "imported", "exported", "2.0 kW", "0.4 kW"].join("")
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue