diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 6f6f8a40aa..8ebea677b3 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -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`
{ 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 }); } diff --git a/src/resources/echarts.ts b/src/resources/echarts.ts index 77a328722f..2f5c27e483 100644 --- a/src/resources/echarts.ts +++ b/src/resources/echarts.ts @@ -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;