Show sankey chart in vertical layout on mobile (#26439)

* Show sankey chart in vertical layout on mobile

* ts fix
This commit is contained in:
Petar Petrov 2025-08-08 16:37:44 +03:00 committed by GitHub
parent 49c7dad6eb
commit a7db401b62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 84 additions and 37 deletions

View File

@ -387,24 +387,25 @@ export class HaChartBase extends LitElement {
lastTipX = e.x;
lastTipY = e.y;
this.chart?.setOption({
xAxis: ensureArray(this.chart?.getOption().xAxis as any).map(
(axis: XAXisOption) =>
axis.show
? {
...axis,
axisPointer: {
...axis.axisPointer,
status: "show",
handle: {
color: style.getPropertyValue("primary-color"),
margin: 0,
size: 20,
...axis.axisPointer?.handle,
show: true,
},
xAxis: ensureArray(
(this.chart?.getOption().xAxis as any) ?? []
).map((axis: XAXisOption) =>
axis.show
? {
...axis,
axisPointer: {
...axis.axisPointer,
status: "show",
handle: {
color: style.getPropertyValue("primary-color"),
margin: 0,
size: 20,
...axis.axisPointer?.handle,
show: true,
},
}
: axis
},
}
: axis
),
});
});
@ -417,21 +418,22 @@ export class HaChartBase extends LitElement {
return;
}
this.chart?.setOption({
xAxis: ensureArray(this.chart?.getOption().xAxis as any).map(
(axis: XAXisOption) =>
axis.show
? {
...axis,
axisPointer: {
...axis.axisPointer,
handle: {
...axis.axisPointer?.handle,
show: false,
},
status: "hide",
xAxis: ensureArray(
(this.chart?.getOption().xAxis as any) ?? []
).map((axis: XAXisOption) =>
axis.show
? {
...axis,
axisPointer: {
...axis.axisPointer,
handle: {
...axis.axisPointer?.handle,
show: false,
},
}
: axis
status: "hide",
},
}
: axis
),
});
this.chart?.dispatchAction({

View File

@ -186,14 +186,16 @@ export class HaSankeyChart extends LitElement {
""
);
const wordWidth = measureTextWidth(longestWord, FONT_SIZE);
const availableWidth = params.rect.width + 6;
const fontSize = Math.min(
FONT_SIZE,
(params.rect.width / wordWidth) * FONT_SIZE
(availableWidth / wordWidth) * FONT_SIZE
);
return {
fontSize: fontSize > 1 ? fontSize : 0,
width: params.rect.width,
width: availableWidth,
align: "center",
dy: -2, // shift up or the lowest row labels may be cut off
};
}

View File

@ -0,0 +1,34 @@
import type { LitElement } from "lit";
import { state } from "lit/decorators";
import type { Constructor } from "../types";
import { isMobileClient } from "../util/is_mobile";
import { listenMediaQuery } from "../common/dom/media_query";
export const MobileAwareMixin = <T extends Constructor<LitElement>>(
superClass: T
) => {
class MobileAwareClass extends superClass {
@state() protected _isMobileSize = false;
protected _isMobileClient = isMobileClient;
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery(
"all and (max-width: 450px), all and (max-height: 500px)",
(matches) => {
this._isMobileSize = matches;
}
);
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
}
return MobileAwareClass;
};

View File

@ -23,6 +23,7 @@ import type { Link, Node } from "../../../../components/chart/ha-sankey-chart";
import { getGraphColorByIndex } from "../../../../common/color/colors";
import { formatNumber } from "../../../../common/number/format_number";
import { getEntityContext } from "../../../../common/entity/context/get_entity_context";
import { MobileAwareMixin } from "../../../../mixins/mobile-aware-mixin";
const DEFAULT_CONFIG: Partial<EnergySankeyCardConfig> = {
group_by_floor: true,
@ -31,7 +32,7 @@ const DEFAULT_CONFIG: Partial<EnergySankeyCardConfig> = {
@customElement("hui-energy-sankey-card")
class HuiEnergySankeyCard
extends SubscribeMixin(LitElement)
extends SubscribeMixin(MobileAwareMixin(LitElement))
implements LovelaceCard
{
@property({ attribute: false }) public hass!: HomeAssistant;
@ -70,7 +71,11 @@ class HuiEnergySankeyCard
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
return changedProps.has("_config") || changedProps.has("_data");
return (
changedProps.has("_config") ||
changedProps.has("_data") ||
changedProps.has("_isMobileSize")
);
}
protected render() {
@ -373,13 +378,17 @@ class HuiEnergySankeyCard
const hasData = nodes.some((node) => node.value > 0);
const vertical =
this._config.layout === "vertical" ||
(this._config.layout !== "horizontal" && this._isMobileSize);
return html`
<ha-card .header=${this._config.title}>
<div class="card-content">
${hasData
? html`<ha-sankey-chart
.data=${{ nodes, links }}
.vertical=${this._config.layout === "vertical"}
.vertical=${vertical}
.valueFormatter=${this._valueFormatter}
></ha-sankey-chart>`
: html`${this.hass.localize(

View File

@ -213,7 +213,7 @@ export interface EnergyCarbonGaugeCardConfig extends EnergyCardBaseConfig {
export interface EnergySankeyCardConfig extends EnergyCardBaseConfig {
type: "energy-sankey";
title?: string;
layout?: "vertical" | "horizontal";
layout?: "vertical" | "horizontal" | "auto";
group_by_floor?: boolean;
group_by_area?: boolean;
}