Skip to content

Commit eafceb2

Browse files
authored
Add presets and xaxes defaults (#526)
1 parent 966afa4 commit eafceb2

File tree

4 files changed

+170
-11
lines changed

4 files changed

+170
-11
lines changed

readme.md

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ hours_to_show: current_day
922922

923923
## Default trace & axis styling
924924

925-
default configurations for all entities and all yaxes (e.g yaxis, yaxis2, yaxis3, etc).
925+
default configurations for all entities and all xaxes (e.g xaxis, xaxis2, xaxis3, etc) and yaxes (e.g yaxis, yaxis2, yaxis3, etc).
926926

927927
```yaml
928928
type: custom:plotly-graph
@@ -934,6 +934,8 @@ defaults:
934934
fill: tozeroy
935935
line:
936936
width: 2
937+
xaxes:
938+
showgrid: false # Disables vertical gridlines
937939
yaxes:
938940
fixedrange: true # disables vertical zoom & scroll
939941
```
@@ -1040,6 +1042,110 @@ config:
10401042

10411043
When using `hours_to_show: current_week`, the "First day of the week" configured in Home Assistant is used
10421044

1045+
## Presets
1046+
1047+
If you find yourself reusing the same card configuration frequently, you can save it as a preset.
1048+
1049+
### Setup
1050+
1051+
Presets are loaded from the global `PlotlyGraphCardPresets` JS object (such that they can be shared across different dashboards).
1052+
The recommended way to add or modify presets is to set up a `plotly_presets.js` script in the `www` subdirectory of your `config` folder.
1053+
```js
1054+
window.PlotlyGraphCardPresets = {
1055+
// Add your presets here with the following format (or check the examples below)
1056+
// PresetName: { PresetConfiguration }
1057+
};
1058+
```
1059+
To ensure this file is loaded on every dashboard, add the following lines to your `configuration.yaml`.
1060+
```yaml
1061+
frontend:
1062+
extra_module_url:
1063+
- /local/plotly_presets.js
1064+
```
1065+
You might have to clear your browser cache or restart HA for changes to take effect.
1066+
1067+
### Examples
1068+
1069+
The preset configuration should be defined as a JS object instead of the YAML format used by the card.
1070+
Below is an example YAML configuration that is split into several corresponding presets.
1071+
1072+
<table>
1073+
<tr>
1074+
<th>YAML configuration</th>
1075+
<th>Preset configurations</th>
1076+
</tr>
1077+
<tr style="vertical-align:top">
1078+
<td>
1079+
1080+
```yaml
1081+
hours_to_show: current_day
1082+
time_offset: -24h
1083+
defaults:
1084+
entity:
1085+
hovertemplate: "$fn ({ get }) => `%{y:,.1f} ${get('.unit_of_measurement')}<extra>${get('.name')}</extra>`"
1086+
xaxes:
1087+
showspikes: true
1088+
spikemode: across
1089+
spikethickness: -2
1090+
```
1091+
1092+
</td>
1093+
<td>
1094+
1095+
```js
1096+
window.PlotlyGraphCardPresets = {
1097+
yesterday: { // Start of preset with name 'yesterday'
1098+
hours_to_show: "current_day",
1099+
time_offset: "-24h",
1100+
},
1101+
simpleHover: { // Start of preset with name 'simpleHover'
1102+
defaults: {
1103+
entity: {
1104+
hovertemplate: ({get}) => `%{y:,.1f} ${get(".unit_of_measurement")}<extra>${get(".name")}</extra>`,
1105+
},
1106+
},
1107+
},
1108+
verticalSpikes: { // Start of preset with name 'verticalSpikes'
1109+
defaults: {
1110+
xaxes: {
1111+
showspikes: true,
1112+
spikemode: "across",
1113+
spikethickness: -2,
1114+
},
1115+
},
1116+
},
1117+
};
1118+
```
1119+
1120+
</td>
1121+
</tr>
1122+
</table>
1123+
1124+
### Usage
1125+
1126+
To use your defined templates, simply specify the preset name under the `preset` key.
1127+
You can also specify a list of preset names to combine several of them.
1128+
1129+
E.g. with the above preset definitions, we can show yesterday's temperatures.
1130+
```yaml
1131+
type: custom:plotly-graph
1132+
entities:
1133+
- sensor.temperature1
1134+
- sensor.temperature2
1135+
preset: yesterday
1136+
```
1137+
1138+
Or show a simplified hover tooltip together with vertical spikes.
1139+
```yaml
1140+
type: custom:plotly-graph
1141+
entities:
1142+
- sensor.temperature1
1143+
- sensor.temperature2
1144+
preset:
1145+
- simpleHover
1146+
- verticalSpikes
1147+
```
1148+
10431149
# deprecations:
10441150
10451151
### `no_theme`

src/parse-config/defaults.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Config, InputConfig } from "../types";
33
import { parseColorScheme } from "./parse-color-scheme";
44
import { getEntityIndex } from "./parse-config";
55
import getThemedLayout, { HATheme } from "./themed-layout";
6+
declare const window: Window & { PlotlyGraphCardPresets?: Record<string, InputConfig> };
67
const noop$fn = () => () => {};
78
const defaultEntityRequired = {
89
entity: "",
@@ -59,6 +60,7 @@ const defaultYamlRequired = {
5960
raw_plotly: false,
6061
defaults: {
6162
entity: {},
63+
xaxes: {},
6264
yaxes: {},
6365
},
6466
layout: {},
@@ -68,6 +70,15 @@ const defaultYamlRequired = {
6870

6971
//
7072

73+
const defaultExtraXAxes: Partial<Plotly.LayoutAxis> = {
74+
// automargin: true, // it makes zooming very jumpy
75+
type: "date",
76+
autorange: false,
77+
overlaying: "x",
78+
showgrid: false,
79+
visible: false,
80+
};
81+
7182
const defaultExtraYAxes: Partial<Plotly.LayoutAxis> = {
7283
// automargin: true, // it makes zooming very jumpy
7384
side: "right",
@@ -98,6 +109,12 @@ const defaultYamlOptional: {
98109
type: "date",
99110
// automargin: true, // it makes zooming very jumpy
100111
},
112+
...Object.fromEntries(
113+
Array.from({ length: 28 }).map((_, i) => [
114+
`xaxis${i + 2}`,
115+
{ ...defaultExtraXAxes },
116+
])
117+
),
101118
yaxis: {
102119
// automargin: true, // it makes zooming very jumpy
103120
},
@@ -144,29 +161,52 @@ const defaultYamlOptional: {
144161
},
145162
};
146163

164+
function getPresetYaml(presets: string | string[] | undefined, skips?: Set<string>): Partial<InputConfig> {
165+
if (!window.PlotlyGraphCardPresets || presets === undefined) return {};
166+
if (!Array.isArray(presets)) presets = [presets];
167+
if (presets.length == 0) return {};
168+
if (skips === undefined) skips = new Set<string>();
169+
const nestedPresets: string[] = [];
170+
const presetYamls = presets.map((preset) => {
171+
const yaml = window.PlotlyGraphCardPresets![preset] ?? {};
172+
if (yaml.preset !== undefined) {
173+
if (!Array.isArray(yaml.preset)) yaml.preset = [yaml.preset];
174+
nestedPresets.push(...yaml.preset);
175+
}
176+
return yaml;
177+
});
178+
const newPresets = nestedPresets.filter((preset) => !skips.has(preset));
179+
const nestedYaml = getPresetYaml(newPresets, new Set([...skips, ...presets]));
180+
return merge({}, ...presetYamls, nestedYaml);
181+
}
182+
147183
export function addPreParsingDefaults(
148184
yaml_in: InputConfig,
149185
css_vars: HATheme
150186
): InputConfig {
151187
// merging in two steps to ensure ha_theme and raw_plotly_config took its default value
152188
let yaml = merge({}, yaml_in, defaultYamlRequired, yaml_in);
189+
const preset = getPresetYaml(yaml.preset);
153190
for (let i = 1; i < 31; i++) {
154-
const yaxis = "yaxis" + (i == 1 ? "" : i);
155-
yaml.layout[yaxis] = merge(
156-
{},
157-
yaml.layout[yaxis],
158-
yaml.defaults.yaxes,
159-
yaml.layout[yaxis]
160-
);
191+
for (const d of ["x", "y"]) {
192+
const axis = d + "axis" + (i == 1 ? "" : i);
193+
yaml.layout[axis] = merge(
194+
{},
195+
yaml.layout[axis],
196+
yaml.defaults[d + "axes"],
197+
preset.defaults?.[d+ "axes"] ?? {},
198+
yaml.layout[axis]
199+
);
200+
}
161201
}
162-
163202
yaml = merge(
164203
{},
165204
yaml,
166205
{
167206
layout: yaml.ha_theme ? getThemedLayout(css_vars) : {},
168207
},
169208
yaml.raw_plotly_config ? {} : defaultYamlOptional,
209+
preset,
170210
yaml
171211
);
172212

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export type InputConfig = {
6363
} & Partial<Plotly.PlotData>)[];
6464
defaults?: {
6565
entity?: Partial<Plotly.PlotData>;
66+
xaxes?: Partial<Plotly.Layout["xaxis"]>;
6667
yaxes?: Partial<Plotly.Layout["yaxis"]>;
6768
};
6869
on_dblclick?: Function;
@@ -74,6 +75,7 @@ export type InputConfig = {
7475
minimal_response?: boolean; // defaults to true
7576
disable_pinch_to_zoom?: boolean; // defaults to false
7677
autorange_after_scroll?: boolean; // defaults to false
78+
preset?: string | string[];
7779
};
7880

7981
export type EntityConfig = EntityIdConfig & {

yaml-editor/src/schema.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73274,7 +73274,7 @@
7327473274
],
7327573275
"type": "object"
7327673276
},
73277-
"With$fn<{entity?:Partial<Plotly.PlotData>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>": {
73277+
"With$fn<{entity?:Partial<Plotly.PlotData>|undefined;xaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>": {
7327873278
"properties": {
7327973279
"entity": {
7328073280
"anyOf": [
@@ -73287,6 +73287,17 @@
7328773287
}
7328873288
]
7328973289
},
73290+
"xaxes": {
73291+
"anyOf": [
73292+
{
73293+
"pattern": "^[\\s]*\\$(ex|fn)\\s[\\s\\S]+$",
73294+
"type": "string"
73295+
},
73296+
{
73297+
"$ref": "#/definitions/With$fn<Partial<Partial<Plotly.LayoutAxis>>>"
73298+
}
73299+
]
73300+
},
7329073301
"yaxes": {
7329173302
"anyOf": [
7329273303
{
@@ -100647,7 +100658,7 @@
100647100658
"type": "string"
100648100659
},
100649100660
{
100650-
"$ref": "#/definitions/With$fn<{entity?:Partial<Plotly.PlotData>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>"
100661+
"$ref": "#/definitions/With$fn<{entity?:Partial<Plotly.PlotData>|undefined;xaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>"
100651100662
}
100652100663
]
100653100664
},

0 commit comments

Comments
 (0)