From c5a8ee2a3e92567fcdc7f327cb838d39bcb372f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Wiedemann?= Date: Fri, 22 Jan 2021 20:15:19 +0000 Subject: [PATCH] feat: Support for header --- .devcontainer/ui-lovelace.yaml | 42 +++++++++++++--------- src/apex-layouts.ts | 38 -------------------- src/apexcharts-card.ts | 64 ++++++++++++++++++++++++---------- src/styles.ts | 34 +++++++++++++++--- src/types.ts | 8 ++++- 5 files changed, 107 insertions(+), 79 deletions(-) diff --git a/.devcontainer/ui-lovelace.yaml b/.devcontainer/ui-lovelace.yaml index 9c9432c..e5e2558 100644 --- a/.devcontainer/ui-lovelace.yaml +++ b/.devcontainer/ui-lovelace.yaml @@ -19,9 +19,8 @@ views: hours_to_show: 0.20 cache: true layout: minimal - apex_config: - chart: - height: 100% + header: + display: false - type: custom:apexcharts-card stacked: true series: @@ -33,19 +32,19 @@ views: type: bar hours_to_show: 0.25 cache: true - apex_config: - chart: - height: 100% - type: custom:apexcharts-card stacked: true series: - entity: sensor.random_0_1000 - name: test1 + name: RAM Usage + unit: Mb type: area - curve: straight + curve: smooth - entity: sensor.random_0_1000 - name: test2 + name: Ram Free + type: area + - entity: sensor.humidity type: area hours_to_show: 0.20 cache: true @@ -63,14 +62,23 @@ views: hours_to_show: 0.25 cache: true - type: custom:apexcharts-card - hours_to_show: 0.25 + hours_to_show: 200 series: - entity: sensor.humidity - - entity: sensor.random0_100 - type: bar + # - entity: sensor.random0_100 + # type: bar # extend_to_end: true - - type: custom:apexcharts-card - hours_to_show: 0.25 - series: - - entity: sensor.non_existent - # extend_to_end: true \ No newline at end of file + # - type: custom:apexcharts-card + # hours_to_show: 0.25 + # series: + # - entity: sensor.non_existent + # # extend_to_end: true + # - type: custom:apexcharts-card + # series: + # - entity: sensor.random0_100 + # type: bubble + # - entity: sensor.random0_100 + # type: bubble + # apex_config: + # chart: + # type: bubble diff --git a/src/apex-layouts.ts b/src/apex-layouts.ts index 33d1df9..3aebd1b 100644 --- a/src/apex-layouts.ts +++ b/src/apex-layouts.ts @@ -9,13 +9,6 @@ export function getLayoutConfig(config: ChartCardConfig): unknown { type: 'line', foreColor: 'var(--primary-text-color)', width: '100%', - // animations: { - // enabled: true, - // easing: 'linear', - // dynamicAnimation: { - // speed: 1000, - // }, - // }, zoom: { enabled: false, }, @@ -26,31 +19,6 @@ export function getLayoutConfig(config: ChartCardConfig): unknown { grid: { strokeDashArray: 3, }, - title: { - text: config?.series[0].name || config?.series[0].entity, - align: 'left', - floating: false, - // offsetX: 10, - style: { - fontSize: '20px', - fontWeight: '500', - fontFamily: 'var(--paper-font-body1_-_font-family)', - // color: '#263238' - }, - }, - subtitle: { - text: undefined, - align: 'right', - floating: true, - offsetY: 0, - margin: 0, - style: { - fontSize: '40px', - fontWeight: '300', - fontFamily: 'var(--paper-font-body1_-_font-family)', - // color: '#9699a2' - }, - }, series: config?.series.map((serie) => { return { name: serie.name || serie.entity, @@ -107,12 +75,6 @@ export function getLayoutConfig(config: ChartCardConfig): unknown { right: 0, }, }, - subtitle: { - offsetY: -15, - }, - title: { - offsetY: -15, - }, xaxis: { labels: { show: false, diff --git a/src/apexcharts-card.ts b/src/apexcharts-card.ts index cc0e13d..b90eb0a 100644 --- a/src/apexcharts-card.ts +++ b/src/apexcharts-card.ts @@ -55,7 +55,7 @@ class ChartsCard extends LitElement { @property() private _config?: ChartCardConfig; - private _entities: HassEntity[] = []; + @property() private _entities: HassEntity[] = []; public connectedCallback() { super.connectedCallback(); @@ -105,6 +105,7 @@ class ChartsCard extends LitElement { hours_to_show: 24, cache: true, useCompress: false, + header: { display: true }, ...JSON.parse(JSON.stringify(config)), }; this._config?.series.map((serie) => { @@ -124,8 +125,11 @@ class ChartsCard extends LitElement { return html` -
-
+
+ ${this._config.header?.display ? this._renderHeader() : html``} +
+
+
`; @@ -133,7 +137,7 @@ class ChartsCard extends LitElement { renderWarnings() { return html` - +
apexcharts-card
${this._config?.series.map((_, index) => @@ -146,10 +150,34 @@ class ChartsCard extends LitElement { `; } + private _renderHeader(): TemplateResult { + return html` +
+
+ ${this._entities[0].state} + ${this._computeUom(0)} +
+
${this._computeName(0)}
+
+ `; + } + + private _computeName(index: number): string { + return ( + this._config?.series[index].name || + this._entities[index].attributes.friendly_name || + this._entities[index].entity_id + ); + } + + private _computeUom(index: number): string { + return this._config?.series[index].unit || this._entities[index].attributes.unit_of_measurement || ''; + } + private async _initialLoad() { await this.updateComplete; - if (!this._apexChart && this.shadowRoot && this._config) { + if (!this._apexChart && this.shadowRoot && this._config && this.shadowRoot.querySelector('#graph')) { this._loaded = true; const graph = this.shadowRoot.querySelector('#graph'); this._apexChart = new ApexCharts(graph, getLayoutConfig(this._config)); @@ -181,7 +209,7 @@ class ChartsCard extends LitElement { start.setTime(start.getTime() - getMilli(config.hours_to_show)); try { - const promise = this._entities.map((entity, i) => this._updateEntity(entity, i, start)); + const promise = this._entities.map((entity, i) => this._updateEntity(entity, i, start, end)); await Promise.all(promise); const graphData = { series: this._history.map((history, index) => { @@ -189,14 +217,10 @@ class ChartsCard extends LitElement { data: this._config?.series[index].extend_to_end && this._config?.series[index].type !== 'bar' ? [...history?.data, ...[[end.getTime(), history?.data.slice(-1)[0][1]]]] - : history?.data, + : history?.data || [], }; }), - subtitle: { - text: this._entities[0].state, - }, xaxis: { - // min: end.get max: end.getTime(), }, }; @@ -207,7 +231,12 @@ class ChartsCard extends LitElement { this._updating = false; } - private async _updateEntity(entity: HassEntity, index: number, start: Date): Promise { + private async _updateEntity( + entity: HassEntity, + index: number, + start: Date, + end: Date, + ): Promise { if (!this._config || !entity || !this._updateQueue.includes(`${entity.entity_id}-${index}`)) return; this._updateQueue = this._updateQueue.filter((entry) => entry !== `${entity.entity_id}-${index}`); @@ -239,15 +268,14 @@ class ChartsCard extends LitElement { entity.entity_id, // if data in cache, get data from last data's time + 1ms history && history.data.length !== 0 ? new Date(history.data.slice(-1)[0][0] + 1) : start, - undefined, + end, skipInitialState, ); if (newHistory && newHistory[0] && newHistory[0].length > 0) { - const filteredNewHistory = newHistory[0].filter((item) => !Number.isNaN(parseFloat(item.state))); - const newStateHistory: [number, number][] = filteredNewHistory.map((item) => [ - new Date(item.last_changed).getTime(), - parseFloat(item.state), - ]); + const newStateHistory: [number, number | null][] = newHistory[0].map((item) => { + const stateParsed = parseFloat(item.state); + return [new Date(item.last_changed).getTime(), !Number.isNaN(stateParsed) ? stateParsed : null]; + }); if (history?.data) { history.hours_to_show = this._config.hours_to_show; history.last_fetched = new Date(); diff --git a/src/styles.ts b/src/styles.ts index 40934f7..554aebe 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -7,14 +7,18 @@ export const styles: CSSResult = css` ha-card { overflow: hidden; - height: 100%; } - #wrapper { - overflow: hidden; - height: 100%; + + .wrapper { + display: grid; + grid-template-areas: "header" "graph"; + grid-template-columns: 1fr; + grid-template-rows: min-content 1fr; } - #graph { + + #graph-wrapper { height: 100%; + grid-area: graph; } /* Needed for minimal layout */ @@ -22,6 +26,26 @@ export const styles: CSSResult = css` overflow: visible !important; } + .header { + padding-top: 10px; + padding-left: 10px; + grid-area: header; + } + .title > .state { + font-size: 1.8em; + font-weight: 500; + } + .title > .uom { + font-size: 1em; + font-weight: 400; + opacity: 0.8; + } + .subtitble { + font-size: 0.8em; + font-weight: 300; + } + + /* Apex Charts Default CSS */ .apexcharts-canvas { position: relative; user-select: none; diff --git a/src/types.ts b/src/types.ts index 6792301..0f40611 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,7 @@ export interface ChartCardExternalConfig { stacked?: boolean; layout?: string; apex_config?: ApexOptions; + header?: ChartCardHeaderExternalConfig; } export interface ChartCardSeriesExternalConfig { @@ -23,16 +24,21 @@ export interface ChartCardSeriesExternalConfig { type: 'line' | 'bar' | 'area'; curve?: 'smooth' | 'straight' | 'stepline'; extend_to_end?: boolean; + unit?: string; } export interface ChartCardSeriesConfig extends ChartCardSeriesExternalConfig { index: number; } +export interface ChartCardHeaderExternalConfig { + display?: boolean; +} + export interface EntityEntryCache { hours_to_show: number; last_fetched: Date; - data: [number, number][]; + data: [number, number | null][]; } export interface HassHistory {