From ab2e546b06330edf9ebdf7c1dfe54cc975557d73 Mon Sep 17 00:00:00 2001 From: selvalt7 <52136675+selvalt7@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:16:52 +0200 Subject: [PATCH 1/4] feat: sections support --- .eslintrc.yaml | 1 + src/main.js | 135 +++++++++++++++++++++++++++++++++++++++++++++++-- src/style.js | 23 +++++++++ 3 files changed, 155 insertions(+), 4 deletions(-) mode change 100755 => 100644 .eslintrc.yaml diff --git a/.eslintrc.yaml b/.eslintrc.yaml old mode 100755 new mode 100644 index 6020c9c..889d79b --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -14,3 +14,4 @@ globals: window: true Event: true customElements: true + document: true diff --git a/src/main.js b/src/main.js index 46496c4..a8c9a0b 100644 --- a/src/main.js +++ b/src/main.js @@ -48,6 +48,9 @@ class MiniGraphCard extends LitElement { this.stateChanged = false; this.initial = true; this._md5Config = undefined; + this.sections = this.checkSections(); + this.graphHeight = 100; + this.graphWidth = 500; } static get styles() { @@ -105,12 +108,17 @@ class MiniGraphCard extends LitElement { this._md5Config = SparkMD5.hash(JSON.stringify(this.config)); const entitiesChanged = !compareArray(this.config.entities || [], config.entities); + const layout = this.getCurrentLayout(); + + this.graphWidth = this.sections ? layout.grid_columns * 120 : 500; + this.graphHeight = this.sections ? this.getGraphHeightSections() * 56 : this.config.height; + if (!this.Graph || entitiesChanged) { if (this._hass) this.hass = this._hass; this.Graph = this.config.entities.map( entity => new Graph( - 500, - this.config.height, + this.graphWidth, + this.graphHeight, [this.config.show.fill ? 0 : this.config.line_width, this.config.line_width], this.config.hours_to_show, this.config.points_per_hour, @@ -127,6 +135,68 @@ class MiniGraphCard extends LitElement { } } + checkSections() { + let root = document.querySelector('home-assistant'); + root = root && root.shadowRoot; + root = root && root.querySelector('home-assistant-main'); + root = root && root.shadowRoot; + root = root && root.querySelector('ha-drawer'); + root = root && root.querySelector('partial-panel-resolver'); + root = root && root.shadowRoot || root; + root = root && root.querySelector('ha-panel-lovelace'); + root = root && root.shadowRoot; + root = root && root.querySelector('hui-root'); + if (root) { + const ll = root.lovelace; + ll.current_view = root.___curView; + const panelType = ll.rawConfig.views[ll.current_view].type; + return panelType === 'sections'; + } + return false; + } + + getCurrentLayout() { + const layout = this.getLayoutOptions(); + const layoutConfigured = this.config.layout_options !== undefined; + const columns = Math.max(layoutConfigured + ? this.config.layout_options.grid_columns : layout.grid_columns, layout.grid_min_columns); + const rows = Math.max(layoutConfigured + ? this.config.layout_options.grid_rows : layout.grid_rows, layout.grid_min_rows); + return { grid_columns: columns, grid_rows: rows }; + } + + getLayoutSize(layout) { + if (!this.sections) { + return ''; + } + if (layout.grid_rows === 2) { + return 'small'; + } + return ''; + } + + getGraphHeightSections() { + const layout = this.getCurrentLayout(); + if (!this.config.show.name + && !this.config.show.state + && !this.config.show.icon + && this.config.show.extrema) { + return Math.max(layout.grid_rows - 1, 1); + } + if (!this.config.show.name + && !this.config.show.state + && !this.config.show.icon) { + return layout.grid_rows; + } + if (this.config.show.extrema) { + return Math.max(layout.grid_rows - 3, 1); + } + if (layout.grid_rows >= 3) { + return Math.max(layout.grid_rows - 2, 1); + } + return Math.max(layout.grid_rows - 1, 1); + } + connectedCallback() { super.connectedCallback(); if (this.config.update_interval) { @@ -181,9 +251,10 @@ class MiniGraphCard extends LitElement { if (this.config.entities.some((_, index) => this.entity[index] === undefined)) { return this.renderWarnings(); } + const layout = this.getCurrentLayout(); return html` e.stopPropagation()}> @@ -1014,6 +1085,62 @@ class MiniGraphCard extends LitElement { } } + getLayoutOptions() { + if (!this.config.show.state + && this.config.show.extrema) { + return { + grid_rows: 2, + grid_columns: 2, + grid_min_rows: 3, + grid_min_columns: 2, + }; + } + if (!this.config.show.name + && !this.config.show.state + && !this.config.show.icon) { + return { + grid_rows: 2, + grid_columns: 2, + grid_min_rows: 1, + grid_min_columns: 2, + }; + } + if (!this.config.show.name + && !this.config.show.state + && !this.config.show.icon + && this.config.show.extrema) { + return { + grid_rows: 2, + grid_columns: 2, + grid_min_rows: 2, + grid_min_columns: 2, + }; + } + if (this.config.show.extrema + && !this.config.show.fill) { + return { + grid_rows: 5, + grid_columns: 2, + grid_min_rows: 5, + grid_min_columns: 2, + }; + } + if (this.config.show.extrema) { + return { + grid_rows: 4, + grid_columns: 2, + grid_min_rows: 4, + grid_min_columns: 2, + }; + } + return { + grid_rows: 2, + grid_columns: 2, + grid_min_rows: 2, + grid_min_columns: 2, + }; + } + getCardSize() { return 3; } diff --git a/src/style.js b/src/style.js index 497c2ae..b5024b6 100644 --- a/src/style.js +++ b/src/style.js @@ -12,6 +12,10 @@ const style = css` position: relative; overflow: hidden; } + ha-card.sections { + min-height: calc((var(--row-size, 1)*(var(--row-height) + var(--row-gap))) - var(--row-gap)); + max-height: calc((var(--row-size, 1)*(var(--row-height) + var(--row-gap))) - var(--row-gap)); + } ha-card > div { padding: 0px 16px 16px 16px; } @@ -49,6 +53,9 @@ const style = css` order: -1; padding: 0 16px 8px 16px; } + ha-card[fill].sections .graph__legend { + padding: 0 16px 0px 16px; + } ha-card[fill] .info { padding-bottom: 16px; } @@ -120,6 +127,12 @@ const style = css` justify-content: space-between; flex-wrap: nowrap; } + .sections.small .states { + padding: 0px 16px 0px 16px; + } + .sections.small .header { + padding: 0px 16px 0px 16px; + } .states .icon { align-self: center; margin-left: 0; @@ -238,6 +251,10 @@ const style = css` margin-top: auto; width: 100%; } + .sections .graph { + position: absolute; + bottom: 0; + } .graph__container { display: flex; flex-direction: row; @@ -348,6 +365,9 @@ const style = css` padding-top: 16px; flex-wrap: wrap; } + .sections .graph__legend { + padding-top: 8px; + } .graph__legend__item { cursor: pointer; display: flex; @@ -355,6 +375,9 @@ const style = css` margin: .4em; align-items: center } + .sections .graph__legend__item { + margin: .4em .4em 0px .4em; + } .graph__legend__item span { opacity: .75; margin-left: .4em; From b1653e8c12f770b29d1432a82154460f7c0b6dd3 Mon Sep 17 00:00:00 2001 From: selvalt7 <52136675+selvalt7@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:02:17 +0200 Subject: [PATCH 2/4] fix: invisible graph in non `sections` type dashboards --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index a8c9a0b..1a37283 100644 --- a/src/main.js +++ b/src/main.js @@ -580,7 +580,7 @@ class MiniGraphCard extends LitElement { renderSvg() { const { height } = this.config; return svg` - e.stopPropagation()}> From 295554c5fbae99be754335810ba13ef6bcac25d6 Mon Sep 17 00:00:00 2001 From: selvalt7 <52136675+selvalt7@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:26:29 +0200 Subject: [PATCH 3/4] fix: hide state time label when card is considered small --- src/style.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/style.js b/src/style.js index b5024b6..53ad910 100644 --- a/src/style.js +++ b/src/style.js @@ -243,6 +243,9 @@ const style = css` left: initial; right: 0; } + .sections.small .state__time { + display: none; + } .graph { align-self: flex-end; box-sizing: border-box; From 2c9a8b75390994530584ad802c6f84595abe2b94 Mon Sep 17 00:00:00 2001 From: selvalt7 <52136675+selvalt7@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:15:32 +0200 Subject: [PATCH 4/4] Cleaner minimum row calculation Card is considered small when its row size is 3 or less Simpler sections checking Simpler card height style --- src/graph.js | 4 ++ src/main.js | 124 ++++++++++++--------------------------------------- src/style.js | 6 +-- 3 files changed, 33 insertions(+), 101 deletions(-) diff --git a/src/graph.js b/src/graph.js index 58abebf..4ba20b3 100644 --- a/src/graph.js +++ b/src/graph.js @@ -45,6 +45,10 @@ export default class Graph { set history(data) { this._history = data; } + setHeight(newHeight) { this.height = newHeight - this.margin[Y] * 4; } + + setWidth(newWidth) { this.width = newWidth - this.margin[X] * 2; } + update(history = undefined) { if (history) { this._history = history; diff --git a/src/main.js b/src/main.js index 1a37283..54b62c5 100644 --- a/src/main.js +++ b/src/main.js @@ -48,7 +48,7 @@ class MiniGraphCard extends LitElement { this.stateChanged = false; this.initial = true; this._md5Config = undefined; - this.sections = this.checkSections(); + this.sections = false; this.graphHeight = 100; this.graphWidth = 500; } @@ -108,10 +108,7 @@ class MiniGraphCard extends LitElement { this._md5Config = SparkMD5.hash(JSON.stringify(this.config)); const entitiesChanged = !compareArray(this.config.entities || [], config.entities); - const layout = this.getCurrentLayout(); - - this.graphWidth = this.sections ? layout.grid_columns * 120 : 500; - this.graphHeight = this.sections ? this.getGraphHeightSections() * 56 : this.config.height; + this.graphHeight = this.config.height; if (!this.Graph || entitiesChanged) { if (this._hass) this.hass = this._hass; @@ -136,23 +133,7 @@ class MiniGraphCard extends LitElement { } checkSections() { - let root = document.querySelector('home-assistant'); - root = root && root.shadowRoot; - root = root && root.querySelector('home-assistant-main'); - root = root && root.shadowRoot; - root = root && root.querySelector('ha-drawer'); - root = root && root.querySelector('partial-panel-resolver'); - root = root && root.shadowRoot || root; - root = root && root.querySelector('ha-panel-lovelace'); - root = root && root.shadowRoot; - root = root && root.querySelector('hui-root'); - if (root) { - const ll = root.lovelace; - ll.current_view = root.___curView; - const panelType = ll.rawConfig.views[ll.current_view].type; - return panelType === 'sections'; - } - return false; + return this.layout === 'grid'; } getCurrentLayout() { @@ -166,35 +147,14 @@ class MiniGraphCard extends LitElement { } getLayoutSize(layout) { - if (!this.sections) { - return ''; - } - if (layout.grid_rows === 2) { - return 'small'; - } - return ''; + return this.sections && layout.grid_rows <= 3 ? 'small' : ''; } getGraphHeightSections() { const layout = this.getCurrentLayout(); - if (!this.config.show.name - && !this.config.show.state - && !this.config.show.icon - && this.config.show.extrema) { - return Math.max(layout.grid_rows - 1, 1); - } - if (!this.config.show.name - && !this.config.show.state - && !this.config.show.icon) { - return layout.grid_rows; - } - if (this.config.show.extrema) { - return Math.max(layout.grid_rows - 3, 1); - } - if (layout.grid_rows >= 3) { - return Math.max(layout.grid_rows - 2, 1); - } - return Math.max(layout.grid_rows - 1, 1); + const headerRows = this.getHeaderRows() + (this.getLayoutSize(layout) === '' ? 1 : 0); + + return Math.max(layout.grid_rows - headerRows, 1); } connectedCallback() { @@ -252,6 +212,7 @@ class MiniGraphCard extends LitElement { return this.renderWarnings(); } const layout = this.getCurrentLayout(); + this.sections = this.checkSections(); return html` { + this.Graph[index].setWidth(this.graphWidth); + this.Graph[index].setHeight(this.graphHeight); + }); + } + return this.config.show.graph ? html`
@@ -1085,58 +1059,16 @@ class MiniGraphCard extends LitElement { } } + getHeaderRows() { + return ((this.config.show.name || this.config.show.icon || this.config.show.state) ? 1 : 0) + + ((this.config.show.extrema || this.config.show.average) ? 1 : 0); + } + getLayoutOptions() { - if (!this.config.show.state - && this.config.show.extrema) { - return { - grid_rows: 2, - grid_columns: 2, - grid_min_rows: 3, - grid_min_columns: 2, - }; - } - if (!this.config.show.name - && !this.config.show.state - && !this.config.show.icon) { - return { - grid_rows: 2, - grid_columns: 2, - grid_min_rows: 1, - grid_min_columns: 2, - }; - } - if (!this.config.show.name - && !this.config.show.state - && !this.config.show.icon - && this.config.show.extrema) { - return { - grid_rows: 2, - grid_columns: 2, - grid_min_rows: 2, - grid_min_columns: 2, - }; - } - if (this.config.show.extrema - && !this.config.show.fill) { - return { - grid_rows: 5, - grid_columns: 2, - grid_min_rows: 5, - grid_min_columns: 2, - }; - } - if (this.config.show.extrema) { - return { - grid_rows: 4, - grid_columns: 2, - grid_min_rows: 4, - grid_min_columns: 2, - }; - } return { - grid_rows: 2, + grid_rows: 1 + this.getHeaderRows(), grid_columns: 2, - grid_min_rows: 2, + grid_min_rows: 1 + this.getHeaderRows(), grid_min_columns: 2, }; } diff --git a/src/style.js b/src/style.js index 53ad910..3f0c829 100644 --- a/src/style.js +++ b/src/style.js @@ -4,6 +4,7 @@ const style = css` :host { display: flex; flex-direction: column; + height: 100%; } ha-card { flex-direction: column; @@ -13,8 +14,6 @@ const style = css` overflow: hidden; } ha-card.sections { - min-height: calc((var(--row-size, 1)*(var(--row-height) + var(--row-gap))) - var(--row-gap)); - max-height: calc((var(--row-size, 1)*(var(--row-height) + var(--row-gap))) - var(--row-gap)); } ha-card > div { padding: 0px 16px 16px 16px; @@ -53,9 +52,6 @@ const style = css` order: -1; padding: 0 16px 8px 16px; } - ha-card[fill].sections .graph__legend { - padding: 0 16px 0px 16px; - } ha-card[fill] .info { padding-bottom: 16px; }