Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,55 @@ entities:
- map_y: y + vars.temp1.ys[i]
```

### Universal functions
### Entity click handlers

When the legend is clicked (or doubleclicked), the trace will be hidden (or showed alone) by default. This behaviour is controlled by [layout-legend-itemclick](https://plotly.com/javascript/reference/layout/#layout-legend-itemclick).
On top of that, a `$fn` function can be used to add custom behaviour.
If a handler returns false, the default behaviour trace toggle behaviour will be disabled, but this will also inhibit the `on_legend_dblclick ` handler. Disable the default behaviour via layout-legend-itemclick instead if you want to use both click and dblclick handlers.

```yaml
type: custom:plotly-graph
entities:
- entity: sensor.temperature1
on_legend_click: |-
$fn () => (event_data) => {
event = new Event( "hass-more-info")
event.detail = { entityId: 'sensor.temperature1' };
document.querySelector('home-assistant').dispatchEvent(event);
return false; // disable trace toggling
}
```

Alternatively, clicking on points of the trace itself.

```yaml
type: custom:plotly-graph
entities:
- entity: sensor.temperature1
on_click: |-
$fn () => (event_data) => {
...
// WARNING: this doesn't work and I don't understand why. Help welcome
}
```

There is also a double click plot handler, it works on the whole plotting area (not points of an entity). Beware that double click also autoscales the plot.

```yaml
type: custom:plotly-graph
entities:
- entity: sensor.temperature1
on_dblclick: |-
$fn ({ hass }) => () => {
hass.callService('light', 'turn_on', {
entity_id: 'light.portique_lumiere'
})
}
```

See more in plotly's [official docs](https://plotly.com/javascript/plotlyjs-events)

## Universal functions

Javascript functions allowed everywhere in the yaml. Evaluation is top to bottom and shallow to deep (depth first traversal).

Expand Down
1 change: 0 additions & 1 deletion src/filters/fft-regression.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export default class FFTRegression extends BaseRegression {
const sorted = Array.from(re.data)
.map((x, i) => [x, i])
.sort((a, b) => b[0] - a[0]);
console.log(`sorted`, sorted);

for (let i = degree; i < sorted.length; i++) {
re.set(sorted[i][1], 0);
Expand Down
6 changes: 5 additions & 1 deletion src/parse-config/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import { Config, InputConfig } from "../types";
import { parseColorScheme } from "./parse-color-scheme";
import { getEntityIndex } from "./parse-config";
import getThemedLayout, { HATheme } from "./themed-layout";

const noop$fn = () => () => {};
const defaultEntityRequired = {
entity: "",
show_value: false,
internal: false,
time_offset: "0s",
on_legend_click: noop$fn,
on_legend_dblclick: noop$fn,
on_click: noop$fn,
};
const defaultEntityOptional = {
mode: "lines",
Expand Down Expand Up @@ -59,6 +62,7 @@ const defaultYamlRequired = {
yaxes: {},
},
layout: {},
on_dblclick: noop$fn,
};

//
Expand Down
53 changes: 52 additions & 1 deletion src/plotly-graph-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export class PlotlyGraph extends HTMLElement {
relayoutListener?: EventEmitter;
restyleListener?: EventEmitter;
refreshTimeout?: number;
legendItemClick?: EventEmitter;
legendItemDoubleclick?: EventEmitter;
dataClick?: EventEmitter;
doubleclick?: EventEmitter;
} = {};

constructor() {
Expand Down Expand Up @@ -161,6 +165,18 @@ export class PlotlyGraph extends HTMLElement {
"plotly_restyle",
this.onRestyle
)!;
this.handles.legendItemClick = this.contentEl.on(
"plotly_legendclick",
this.onLegendItemClick
)!;
this.handles.legendItemDoubleclick = this.contentEl.on(
"plotly_legenddoubleclick",
this.onLegendItemDoubleclick
)!;
this.handles.doubleclick = this.contentEl.on(
"plotly_doubleclick",
this.onDoubleclick
)!;
this.resetButtonEl.addEventListener("click", this.exitBrowsingMode);
this.touchController.connect();
this.plot({ should_fetch: true });
Expand All @@ -170,6 +186,16 @@ export class PlotlyGraph extends HTMLElement {
this.handles.resizeObserver!.disconnect();
this.handles.relayoutListener!.off("plotly_relayout", this.onRelayout);
this.handles.restyleListener!.off("plotly_restyle", this.onRestyle);
this.handles.legendItemClick!.off(
"plotly_legendclick",
this.onLegendItemClick
)!;
this.handles.legendItemDoubleclick!.off(
"plotly_legenddoubleclick",
this.onLegendItemDoubleclick
)!;
this.handles.dataClick!.off("plotly_click", this.onDataClick)!;
this.handles.doubleclick!.off("plotly_doubleclick", this.onDoubleclick)!;
clearTimeout(this.handles.refreshTimeout!);
this.resetButtonEl.removeEventListener("click", this.exitBrowsingMode);
this.touchController.disconnect();
Expand Down Expand Up @@ -261,6 +287,27 @@ export class PlotlyGraph extends HTMLElement {
await this.plot({ should_fetch: true });
});
};
onLegendItemClick = ({ curveNumber, ...rest }) => {
return this.parsed_config.entities[curveNumber].on_legend_click({
curveNumber,
...rest,
});
};
onLegendItemDoubleclick = ({ curveNumber, ...rest }) => {
return this.parsed_config.entities[curveNumber].on_legend_dblclick({
curveNumber,
...rest,
});
};
onDataClick = ({ points, ...rest }) => {
return this.parsed_config.entities[points[0].curveNumber].on_click({
points,
...rest,
});
};
onDoubleclick = () => {
return this.parsed_config.on_dblclick();
};
onRestyle = async () => {
// trace visibility changed, fetch missing traces
if (this.isInternalRelayout) return;
Expand Down Expand Up @@ -346,7 +393,6 @@ export class PlotlyGraph extends HTMLElement {
.map((e) => "<span>" + (e || "See devtools console") + "</span>")
.join("\n<br />\n");
this.parsed_config = parsed;
console.log("fetched", this.parsed_config);

const { entities, layout, config, refresh_interval } = this.parsed_config;
clearTimeout(this.handles.refreshTimeout!);
Expand All @@ -364,6 +410,11 @@ export class PlotlyGraph extends HTMLElement {
await Plotly.react(this.contentEl, entities, layout, config);
this.contentEl.style.visibility = "";
});
// this.handles.dataClick?.off("plotly_click", this.onDataClick)!;
this.handles.dataClick = this.contentEl.on(
"plotly_click",
this.onDataClick
)!;
});
// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.
Expand Down
17 changes: 8 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export type InputConfig = {
statistic?: StatisticType;
period?: StatisticPeriod | "auto" | AutoPeriodConfig;
unit_of_measurement?: string;
lambda?: string;
internal?: boolean;
show_value?:
| boolean
Expand All @@ -38,11 +37,15 @@ export type InputConfig = {
offset?: TimeDurationStr;
extend_to_present?: boolean;
filters?: (Record<string, any> | string)[];
on_legend_click?: Function;
on_legend_dblclick?: Function;
on_click?: Function;
} & Partial<Plotly.PlotData>)[];
defaults?: {
entity?: Partial<Plotly.PlotData>;
yaxes?: Partial<Plotly.Layout["yaxis"]>;
};
on_dblclick?: Function;
layout?: Partial<Plotly.Layout>;
config?: Partial<Plotly.Config>;
ha_theme?: boolean;
Expand All @@ -54,14 +57,6 @@ export type InputConfig = {

export type EntityConfig = EntityIdConfig & {
unit_of_measurement?: string;
lambda?: (
y: YValue[],
x: Date[],
raw_entity: ((StatisticValue | HassEntity) & {
timestamp: number;
value: any;
})[]
) => YValue[] | { x?: Date[]; y?: YValue[] };
internal: boolean;
show_value:
| boolean
Expand All @@ -71,6 +66,9 @@ export type EntityConfig = EntityIdConfig & {
offset: number;
extend_to_present: boolean;
filters: FilterFn[];
on_legend_click: Function;
on_legend_dblclick: Function;
on_click: Function;
} & Partial<Plotly.PlotData>;

export type Config = {
Expand All @@ -87,6 +85,7 @@ export type Config = {
minimal_response: boolean;
disable_pinch_to_zoom: boolean;
visible_range: [number, number];
on_dblclick: Function;
};
export type EntityIdStateConfig = {
entity: string;
Expand Down