Add drag to zoom & double click in echarts (#24401)

This commit is contained in:
Petar Petrov 2025-02-26 13:33:39 +02:00 committed by GitHub
parent 3b272ae411
commit 1fdadbf1b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 82 additions and 83 deletions

View File

@ -31,6 +31,7 @@ import "../chips/ha-assist-chip";
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
const LEGEND_OVERFLOW_LIMIT = 10;
const LEGEND_OVERFLOW_LIMIT_MOBILE = 6;
const DOUBLE_TAP_TIME = 300;
@customElement("ha-chart-base")
export class HaChartBase extends LitElement {
@ -65,6 +66,8 @@ export class HaChartBase extends LitElement {
private _isTouchDevice = "ontouchstart" in window;
private _lastTapTime?: number;
// @ts-ignore
private _resizeController = new ResizeController(this, {
callback: () => this.chart?.resize(),
@ -110,6 +113,12 @@ export class HaChartBase extends LitElement {
if (!this.options?.dataZoom) {
this._setChartOptions({ dataZoom: this._getDataZoomConfig() });
}
// drag to zoom
this.chart?.dispatchAction({
type: "takeGlobalCursor",
key: "dataZoomSelect",
dataZoomSelectActive: true,
});
}
};
@ -119,6 +128,11 @@ export class HaChartBase extends LitElement {
if (!this.options?.dataZoom) {
this._setChartOptions({ dataZoom: this._getDataZoomConfig() });
}
this.chart?.dispatchAction({
type: "takeGlobalCursor",
key: "dataZoomSelect",
dataZoomSelectActive: false,
});
}
};
@ -160,9 +174,7 @@ export class HaChartBase extends LitElement {
return html`
<div
class="container ${classMap({ "has-height": !!this.height })}"
style=${styleMap({
height: this.height,
})}
style=${styleMap({ height: this.height })}
>
<div
class="chart-container"
@ -288,12 +300,22 @@ export class HaChartBase extends LitElement {
this.chart.on("click", (e: ECElementEvent) => {
fireEvent(this, "chart-click", e);
});
this.chart.on("mousemove", (e: ECElementEvent) => {
if (e.componentType === "series" && e.componentSubType === "custom") {
// custom series do not support cursor style so we need to set it manually
this.chart?.getZr()?.setCursorStyle("default");
}
});
this.chart.getZr().on("dblclick", this._handleClickZoom);
if (this._isTouchDevice) {
this.chart.getZr().on("click", (e: ECElementEvent) => {
if (!e.zrByTouch) {
return;
}
if (
this._lastTapTime &&
Date.now() - this._lastTapTime < DOUBLE_TAP_TIME
) {
this._handleClickZoom(e);
} else {
this._lastTapTime = Date.now();
}
});
}
this.chart.setOption({
...this._createOptions(),
series: this._getSeries(),
@ -350,20 +372,12 @@ export class HaChartBase extends LitElement {
: undefined;
}
return {
axisLine: {
show: false,
},
splitLine: {
show: true,
},
axisLine: { show: false },
splitLine: { show: true },
...axis,
axisLabel: {
formatter: this._formatTimeLabel,
rich: {
bold: {
fontWeight: "bold",
},
},
rich: { bold: { fontWeight: "bold" } },
hideOverlap: true,
...axis.axisLabel,
},
@ -374,14 +388,18 @@ export class HaChartBase extends LitElement {
const options = {
animation: !this._reducedMotion,
darkMode: this._themes.darkMode ?? false,
aria: {
show: true,
},
aria: { show: true },
dataZoom: this._getDataZoomConfig(),
...this.options,
legend: {
show: false,
toolbox: {
top: Infinity,
left: Infinity,
feature: {
dataZoom: { show: true, yAxisIndex: false, filterMode: "none" },
},
iconStyle: { opacity: 0 },
},
...this.options,
legend: { show: false },
xAxis,
};
@ -413,42 +431,28 @@ export class HaChartBase extends LitElement {
fontFamily: "Roboto, Noto, sans-serif",
},
title: {
textStyle: {
color: style.getPropertyValue("--primary-text-color"),
},
textStyle: { color: style.getPropertyValue("--primary-text-color") },
subtextStyle: {
color: style.getPropertyValue("--secondary-text-color"),
},
},
line: {
lineStyle: {
width: 1.5,
},
lineStyle: { width: 1.5 },
symbolSize: 1,
symbol: "circle",
smooth: false,
},
bar: {
itemStyle: {
barBorderWidth: 1.5,
},
},
bar: { itemStyle: { barBorderWidth: 1.5 } },
categoryAxis: {
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
show: true,
color: style.getPropertyValue("--primary-text-color"),
},
splitLine: {
show: false,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
splitArea: {
show: false,
@ -463,15 +467,11 @@ export class HaChartBase extends LitElement {
valueAxis: {
axisLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisTick: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisLabel: {
show: true,
@ -479,9 +479,7 @@ export class HaChartBase extends LitElement {
},
splitLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
splitArea: {
show: false,
@ -496,15 +494,11 @@ export class HaChartBase extends LitElement {
logAxis: {
axisLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisTick: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisLabel: {
show: true,
@ -512,9 +506,7 @@ export class HaChartBase extends LitElement {
},
splitLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
splitArea: {
show: false,
@ -529,15 +521,11 @@ export class HaChartBase extends LitElement {
timeAxis: {
axisLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisTick: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
axisLabel: {
show: true,
@ -545,9 +533,7 @@ export class HaChartBase extends LitElement {
},
splitLine: {
show: true,
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
},
splitArea: {
show: false,
@ -560,9 +546,7 @@ export class HaChartBase extends LitElement {
},
},
legend: {
textStyle: {
color: style.getPropertyValue("--primary-text-color"),
},
textStyle: { color: style.getPropertyValue("--primary-text-color") },
inactiveColor: style.getPropertyValue("--disabled-text-color"),
pageIconColor: style.getPropertyValue("--primary-text-color"),
pageIconInactiveColor: style.getPropertyValue("--disabled-text-color"),
@ -578,12 +562,8 @@ export class HaChartBase extends LitElement {
fontSize: 12,
},
axisPointer: {
lineStyle: {
color: style.getPropertyValue("--divider-color"),
},
crossStyle: {
color: style.getPropertyValue("--divider-color"),
},
lineStyle: { color: style.getPropertyValue("--divider-color") },
crossStyle: { color: style.getPropertyValue("--divider-color") },
},
},
timeline: {},
@ -609,7 +589,7 @@ export class HaChartBase extends LitElement {
}
if (!this._originalZrFlush) {
const dataSize = ensureArray(this.data).reduce(
(acc, series) => acc + (series.data as any[]).length,
(acc, series) => acc + ((series.data as any[]) || []).length,
0
);
if (dataSize > 10000) {
@ -628,6 +608,23 @@ export class HaChartBase extends LitElement {
this.chart.setOption(options, { replaceMerge });
}
private _handleClickZoom = (e: ECElementEvent) => {
if (!this.chart) {
return;
}
const range = this._isZoomed
? [0, 100]
: [
(e.offsetX / this.chart.getWidth()) * 100 - 15,
(e.offsetX / this.chart.getWidth()) * 100 + 15,
];
this.chart.dispatchAction({
type: "dataZoom",
start: range[0],
end: range[1],
});
};
private _handleZoomReset() {
this.chart?.dispatchAction({ type: "dataZoom", start: 0, end: 100 });
}

View File

@ -13,6 +13,7 @@ import {
GridComponent,
DataZoomComponent,
VisualMapComponent,
ToolboxComponent,
} from "echarts/components";
// Features like Universal Transition and Label Layout
@ -69,6 +70,7 @@ echarts.use([
LabelLayout,
UniversalTransition,
CanvasRenderer,
ToolboxComponent,
]);
export default echarts;