Skip to content

Commit

Permalink
feat: soft bounds and extended bounds for yaxis min/max (#161)
Browse files Browse the repository at this point in the history
* feat: soft bounds and extended bounds for yaxis min/max

* doc: add new min/max format documentation

* doc: slight doc improvment
  • Loading branch information
RomRider committed May 24, 2021
1 parent 5252c8f commit c57278b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .devcontainer/ui-lovelace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,8 @@ views:
apex_config:
tickAmount: 4
- id: second
max: '|+100|'
min: ~100
opposite: true
show: true
apex_config:
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ However, some things might be broken :grin:
- [`transform` Option](#transform-option)
- [`data_generator` Option](#data_generator-option)
- [`yaxis` Options. Multi-Y axis](#yaxis-options-multi-y-axis)
- [Min/Max Format](#minmax-format)
- [Example](#example)
- [Apex Charts Options Example](#apex-charts-options-example)
- [Layouts](#layouts)
- [Configuration Templates](#configuration-templates)
Expand Down Expand Up @@ -434,10 +436,24 @@ You can have as many y-axis as there are series defined in your configuration or
| :white_check_mark: `id` | string | | NEXT_VERSION | The identification name of the yaxis used to map it to a serie. Needs to be unique. |
| `show` | boolean | `true` | NEXT_VERSION | Whether to show or not the axis on the chart |
| `opposite` | boolean | `false` | NEXT_VERSION | If `true`, the axis will be shown on the right side of the chart |
| `min` | `auto` or number | `auto` | NEXT_VERSION | If undefined or `auto`, the `min` of the yaxis will be automatically calculated based on the min value of all the series associated to this axis. If a number is set, the min will be forced to this number |
| `max` | `auto` or number | `auto` | NEXT_VERSION | If undefined or `auto`, the `min` of the yaxis will be automatically calculated based on the max value of all the series associated to this axis. If a number is set, the max will be forced to this number |
| `min` | `auto`, number or string | `auto` | NEXT_VERSION | If undefined or `auto`, the `min` of the yaxis will be automatically calculated based on the min value of all the series associated to this axis. See [below](#minmax-format) for other formats. |
| `max` | `auto`, number or string | `auto` | NEXT_VERSION | If undefined or `auto`, the `min` of the yaxis will be automatically calculated based on the max value of all the series associated to this axis. See [below](#minmax-format) for other formats. |
| `apex_config` | object | | NEXT_VERSION | Any configuration from https://apexcharts.com/docs/options/yaxis/, except `min`, `max`, `show` and `opposite` |

#### Min/Max Format

`min` and `max` support multiple types of format:
* not set or `auto` (this is the default): if it is set to `auto`, the min or max will be automatically calculated
* any number: if a number is set, the min or max will be fixed on the y-axis
* `~90`: if the format is `~` followed by a number, the min or max will be defined as a soft bounds
* `min: ~90` and the min of the data in the series is `120`: the y-axis min value will be `90`
* `min: ~90` and the min of the data in the series is `60`: the y-axis min value will be `60`
* `'|+20|'` or `'|-20|'`: This will add/remove the value between `| |` from the min/max
* `min: '|-20|'`: The min of the data in the series is `32`, the y-axis min will be `12` (= `32 - 20`)
* `max: '|+10|'`: The max of the data in the series is `32`, the y-axis max will be `42` (= `32 + 10`)

#### Example

In this example, we have 2 sensors:
* `sensor.random0_100`: goes from `0` to `100`
* `sensor.random_0_1000`: goes from `0` to `1000`
Expand Down
70 changes: 65 additions & 5 deletions src/apexcharts-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
EntityCachePoints,
EntityEntryCache,
HistoryPoint,
minmax_type,
} from './types';
import { getLovelace, HomeAssistant } from 'custom-card-helpers';
import localForage from 'localforage';
Expand Down Expand Up @@ -358,6 +359,10 @@ class ChartsCard extends LitElement {
yaxis: yAxisConfig,
};
}
this._yAxisConfig?.forEach((yaxis) => {
[yaxis.min, yaxis.min_type] = this._getTypeOfMinMax(yaxis.min);
[yaxis.max, yaxis.max_type] = this._getTypeOfMinMax(yaxis.max);
});
}
this._graphs = this._config.series.map((serie, index) => {
serie.index = index;
Expand Down Expand Up @@ -957,7 +962,7 @@ class ChartsCard extends LitElement {
private _computeYAxisAutoMinMax(start: Date, end: Date) {
if (!this._config) return;
this._yAxisConfig?.map((yaxis) => {
if (typeof yaxis.min !== 'number' || typeof yaxis.max !== 'number') {
if (yaxis.min_type !== minmax_type.FIXED || yaxis.max_type !== minmax_type.FIXED) {
const minMax = yaxis.series_id?.map((id) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const lMinMax = this._graphs![id]?.minMaxWithTimestamp(start.getTime(), end.getTime());
Expand Down Expand Up @@ -986,16 +991,71 @@ class ChartsCard extends LitElement {
}
});
yaxis.series_id?.forEach((id) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (yaxis.min === undefined || yaxis.min === 'auto') this._config!.apex_config!.yaxis![id].min = min;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (yaxis.max === undefined || yaxis.max === 'auto') this._config!.apex_config!.yaxis![id].max = max;
if (min !== null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this._config!.apex_config!.yaxis![id].min = this._getMinMaxBasedOnType(
true,
min,
yaxis.min as number,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
yaxis.min_type!,
);
}
if (max !== null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this._config!.apex_config!.yaxis![id].max = this._getMinMaxBasedOnType(
false,
max,
yaxis.max as number,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
yaxis.max_type!,
);
}
});
}
});
return this._config?.apex_config?.yaxis;
}

private _getMinMaxBasedOnType(isMin: boolean, value: number, configMinMax: number, type: minmax_type): number {
switch (type) {
case minmax_type.AUTO:
return value;
case minmax_type.SOFT:
if ((isMin && value > configMinMax) || (!isMin && value < configMinMax)) {
return configMinMax;
} else {
return value;
}
case minmax_type.ABSOLUTE:
return value + configMinMax;
default:
return value;
}
}

private _getTypeOfMinMax(value?: 'auto' | number | string): [number | undefined, minmax_type] {
const regexFloat = /[+-]?\d+(\.\d+)?/g;
if (typeof value === 'number') {
return [value, minmax_type.FIXED];
} else if (value === undefined || value === 'auto') {
return [undefined, minmax_type.AUTO];
}
if (typeof value === 'string' && value !== 'auto') {
const matched = value.match(regexFloat);
if (!matched || matched.length !== 1) {
throw new Error(`Bad yaxis min/max format: ${value}`);
}
const floatValue = parseFloat(matched[0]);
if (value.startsWith('~')) {
return [floatValue, minmax_type.SOFT];
} else if (value.startsWith('|') && value.endsWith('|')) {
return [floatValue, minmax_type.ABSOLUTE];
}
}
throw new Error(`Bad yaxis min/max format: ${value}`);
}

private _computeChartColors(brush: boolean): (string | (({ value }) => string))[] {
const defaultColors: (string | (({ value }) => string))[] = computeColors(brush ? this._brushColors : this._colors);
const series = brush ? this._config?.series_in_brush : this._config?.series_in_graph;
Expand Down
4 changes: 2 additions & 2 deletions src/types-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ export interface ChartCardYAxisExternal {
id: string;
show?: boolean;
opposite?: boolean;
min?: 'auto' | number;
max?: 'auto' | number;
min?: 'auto' | number | string;
max?: 'auto' | number | string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
apex_config?: any;
}
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,13 @@ export type HistoryBuckets = Array<HistoryBucket>;

export interface ChartCardYAxis extends ChartCardYAxisExternal {
series_id?: number[];
min_type?: minmax_type;
max_type?: minmax_type;
}

export enum minmax_type {
AUTO,
FIXED,
SOFT,
ABSOLUTE,
}

0 comments on commit c57278b

Please sign in to comment.