mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 00:27:49 +01:00
Only center bars for sub-daily periods using getSuggestedPeriod
This commit is contained in:
@@ -39,7 +39,7 @@ import { getSuggestedPeriod } from "../../../../../data/energy";
|
||||
|
||||
/**
|
||||
* Energy chart data point tuple:
|
||||
* [0] displayX - midpoint of the period, used for bar positioning
|
||||
* [0] displayX - bar position (midpoint for sub-daily periods, start otherwise)
|
||||
* [1] value - the energy value
|
||||
* [2] originalStart - original period start timestamp, used for tooltips
|
||||
*/
|
||||
@@ -228,8 +228,8 @@ function formatTooltip(
|
||||
if (!params[0]?.value) {
|
||||
return "";
|
||||
}
|
||||
// displayX is the period midpoint; originalStart has the real date for display.
|
||||
// Gap-filled entries lack originalStart, so find the first real one.
|
||||
// displayX may be shifted from the period start (see EnergyDataPoint);
|
||||
// originalStart has the real date for display. Gap-filled entries lack it.
|
||||
const origDate = params.find((p) => p.value?.[2] != null)?.value?.[2];
|
||||
const date = new Date(origDate ?? params[0].value?.[0]);
|
||||
let period: string;
|
||||
@@ -393,11 +393,24 @@ export function fillLineGaps(datasets: LineSeriesOption[]) {
|
||||
return datasets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the display x-position for an energy bar chart data point.
|
||||
* For sub-daily periods (hour/5minute), returns the midpoint to center bars
|
||||
* between ticks. For daily or longer periods, returns the start timestamp.
|
||||
*/
|
||||
export function computeStatMidpoint(
|
||||
start: number,
|
||||
end: number,
|
||||
period: string,
|
||||
compareTransform?: (ts: Date) => Date
|
||||
): number {
|
||||
const center = period === "hour" || period === "5minute";
|
||||
if (!center) {
|
||||
if (compareTransform) {
|
||||
return compareTransform(new Date(start)).getTime();
|
||||
}
|
||||
return start;
|
||||
}
|
||||
if (compareTransform) {
|
||||
return (
|
||||
(compareTransform(new Date(start)).getTime() +
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
getEnergyDataCollection,
|
||||
getSuggestedPeriod,
|
||||
getSummedData,
|
||||
computeConsumptionData,
|
||||
validateEnergyCollectionKey,
|
||||
@@ -399,6 +400,7 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
this._start,
|
||||
this._compareStart!
|
||||
);
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
|
||||
const untrackedConsumption: BarSeriesOption["data"] = [];
|
||||
const sortedTimes = Object.keys(consumptionData.used_total).sort(
|
||||
@@ -407,7 +409,7 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
// Only start timestamps available here, so estimate midpoint from the gap
|
||||
// between the first two entries. Assumes uniform period spacing.
|
||||
const periodOffset =
|
||||
sortedTimes.length >= 2
|
||||
(period === "hour" || period === "5minute") && sortedTimes.length >= 2
|
||||
? (Number(sortedTimes[1]) - Number(sortedTimes[0])) / 2
|
||||
: 0;
|
||||
sortedTimes.forEach((time) => {
|
||||
@@ -466,6 +468,7 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
this._start,
|
||||
this._compareStart!
|
||||
);
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
|
||||
devices.forEach((source, idx) => {
|
||||
const order = sorted_devices.indexOf(source.stat_consumption);
|
||||
@@ -509,6 +512,7 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
computeStatMidpoint(
|
||||
point.start,
|
||||
point.end,
|
||||
period,
|
||||
compare ? compareTransform : undefined
|
||||
),
|
||||
point.change - sumChildren,
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
getEnergyDataCollection,
|
||||
getSuggestedPeriod,
|
||||
validateEnergyCollectionKey,
|
||||
} from "../../../../data/energy";
|
||||
import type { Statistics, StatisticsMetaData } from "../../../../data/recorder";
|
||||
@@ -267,6 +268,7 @@ export class HuiEnergyGasGraphCard
|
||||
this._start,
|
||||
this._compareStart!
|
||||
);
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
|
||||
gasSources.forEach((source, idx) => {
|
||||
let prevStart: number | null = null;
|
||||
@@ -291,6 +293,7 @@ export class HuiEnergyGasGraphCard
|
||||
computeStatMidpoint(
|
||||
point.start,
|
||||
point.end,
|
||||
period,
|
||||
compare ? compareTransform : undefined
|
||||
),
|
||||
point.change,
|
||||
|
||||
@@ -289,6 +289,7 @@ export class HuiEnergySolarGraphCard
|
||||
this._start,
|
||||
this._compareStart!
|
||||
);
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
|
||||
solarSources.forEach((source, idx) => {
|
||||
let prevStart: number | null = null;
|
||||
@@ -314,6 +315,7 @@ export class HuiEnergySolarGraphCard
|
||||
computeStatMidpoint(
|
||||
point.start,
|
||||
point.end,
|
||||
period,
|
||||
compare ? compareTransform : undefined
|
||||
),
|
||||
point.change,
|
||||
@@ -413,15 +415,19 @@ export class HuiEnergySolarGraphCard
|
||||
|
||||
if (forecastsData) {
|
||||
const solarForecastData: LineSeriesOption["data"] = [];
|
||||
// Only start timestamps available for forecasts, so estimate midpoint
|
||||
// from the gap between the first two entries. Assumes uniform spacing.
|
||||
const forecastTimes = Object.keys(forecastsData)
|
||||
.map(Number)
|
||||
.sort((a, b) => a - b);
|
||||
const forecastOffset =
|
||||
forecastTimes.length >= 2
|
||||
? (forecastTimes[1] - forecastTimes[0]) / 2
|
||||
: 0;
|
||||
// Only center forecast points for sub-daily periods to align with bars.
|
||||
// Only start timestamps available, so estimate midpoint from the gap
|
||||
// between the first two entries. Assumes uniform spacing.
|
||||
let forecastOffset = 0;
|
||||
if (period === "hour" || period === "5minute") {
|
||||
const forecastTimes = Object.keys(forecastsData)
|
||||
.map(Number)
|
||||
.sort((a, b) => a - b);
|
||||
forecastOffset =
|
||||
forecastTimes.length >= 2
|
||||
? (forecastTimes[1] - forecastTimes[0]) / 2
|
||||
: 0;
|
||||
}
|
||||
for (const [time, value] of Object.entries(forecastsData)) {
|
||||
solarForecastData.push([
|
||||
Number(time) + forecastOffset,
|
||||
|
||||
@@ -24,6 +24,7 @@ import type {
|
||||
import {
|
||||
computeConsumptionData,
|
||||
getEnergyDataCollection,
|
||||
getSuggestedPeriod,
|
||||
getSummedData,
|
||||
validateEnergyCollectionKey,
|
||||
} from "../../../../data/energy";
|
||||
@@ -483,10 +484,14 @@ export class HuiEnergyUsageGraphCard
|
||||
|
||||
const uniqueKeys = summedData.timestamps;
|
||||
|
||||
// Only center bars for sub-daily periods (hour/5min).
|
||||
// Only start timestamps available here, so estimate midpoint from the gap
|
||||
// between the first two entries. Assumes uniform period spacing.
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
const periodOffset =
|
||||
uniqueKeys.length >= 2 ? (uniqueKeys[1] - uniqueKeys[0]) / 2 : 0;
|
||||
(period === "hour" || period === "5minute") && uniqueKeys.length >= 2
|
||||
? (uniqueKeys[1] - uniqueKeys[0]) / 2
|
||||
: 0;
|
||||
|
||||
const compareTransform = getCompareTransform(
|
||||
this._start,
|
||||
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
getEnergyDataCollection,
|
||||
getSuggestedPeriod,
|
||||
validateEnergyCollectionKey,
|
||||
} from "../../../../data/energy";
|
||||
import type { Statistics, StatisticsMetaData } from "../../../../data/recorder";
|
||||
@@ -267,6 +268,7 @@ export class HuiEnergyWaterGraphCard
|
||||
this._start,
|
||||
this._compareStart!
|
||||
);
|
||||
const period = getSuggestedPeriod(this._start, this._end);
|
||||
|
||||
waterSources.forEach((source, idx) => {
|
||||
let prevStart: number | null = null;
|
||||
@@ -291,6 +293,7 @@ export class HuiEnergyWaterGraphCard
|
||||
computeStatMidpoint(
|
||||
point.start,
|
||||
point.end,
|
||||
period,
|
||||
compare ? compareTransform : undefined
|
||||
),
|
||||
point.change,
|
||||
|
||||
Reference in New Issue
Block a user