mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add drag to zoom & double click in echarts (#24401)
This commit is contained in:
parent
3b272ae411
commit
1fdadbf1b8
@ -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 });
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user