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

View File

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