From da4814f091647f9d775110edecca466b65127b18 Mon Sep 17 00:00:00 2001 From: mentalilll <159670055+mentalilll@users.noreply.github.com> Date: Wed, 21 Feb 2024 00:09:10 +0100 Subject: [PATCH] Update ha-vpd-chart.js Added huge Performance boost, Added bar view --- ha-vpd-chart.js | 539 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 375 insertions(+), 164 deletions(-) diff --git a/ha-vpd-chart.js b/ha-vpd-chart.js index 2cac1cf..315199d 100644 --- a/ha-vpd-chart.js +++ b/ha-vpd-chart.js @@ -11,9 +11,11 @@ class HaVpdChart extends HTMLElement { vpd_phases: {type: Array}, air_text: {type: String}, rh_text: {type: String}, - enable_tooltip: {type: Boolean} + enable_tooltip: {type: Boolean}, + is_bar_view: {type: Boolean} }; } + constructor() { super(); this.vpd_phases = [ @@ -25,6 +27,7 @@ class HaVpdChart extends HTMLElement { ]; this.vpdCache = new Map(); this.sensors = []; + this.is_bar_view = false; this.min_temperature = 5; this.max_temperature = 35; this.min_humidity = 10; @@ -39,139 +42,360 @@ class HaVpdChart extends HTMLElement { // Whenever the state changes, a new `hass` object is set. Use this to // update your content. set hass(hass) { + if (this.is_bar_view === false) { + this.buildChart(hass); + } else { + this.buildBarChart(hass); + } + } + + setConfig(config) { + this.config = config; + if (!config.sensors) { + throw new Error('You need to define sensors'); + } + + this.vpd_phases = config.vpd_phases || this.vpd_phases; + this.sensors = config.sensors || this.sensors; + this.airText = config.air_text || "Air"; + this.rhText = config.rh_text || "RH"; + this.min_temperature = config.min_temperature || this.min_temperature; + this.max_temperature = config.max_temperature || this.max_temperature; + this.min_humidity = config.min_humidity || this.min_humidity; + this.max_humidity = config.max_humidity || this.max_humidity; + this.steps_temperature = config.steps_temperature || this.steps_temperature; + this.steps_humidity = config.steps_humidity || this.steps_humidity; + this.is_bar_view = config.is_bar_view || this.is_bar_view; + } + + buildBarChart(hass) { + if (!this.content) { + this.innerHTML = ` + + +
+
+
+
+ +
+ + + Under Transpiration + + + + Early Veg + + + + Late Veg + + + + Mid Late Flower + + + + Danger Zone + + + +
+
+ `; + this.content = this.querySelector("div.vpd-card-container"); + } + + let container = document.createElement('div'); + + this.config.sensors.forEach((sensor, index) => { + let humidity = hass.states[sensor.humidity].state; + let temperature = hass.states[sensor.temperature].state; + let leafTemperature = temperature - 2; + if (sensor.leaf_temperature !== undefined) { + leafTemperature = hass.states[sensor.leaf_temperature].state; + } + let vpd = sensor.vpd || this.calculateVPD(parseFloat(leafTemperature), parseFloat(temperature), parseFloat(humidity)).toFixed(2) + let card = document.createElement('ha-card'); + card.innerHTML += ` +
+ ${sensor.name} + ${vpd} kPa + ${this.rhText}: ${humidity}% + ${this.airText}: ${temperature}°C + +
+ `; + container.appendChild(card); + if (this.enable_tooltip) { + this.content.addEventListener('mouseover', (event) => { + if (event.target.classList.contains('tooltip')) { + this.buildMouseTooltip(event.target, hass); + } + }); + this.addEventListener('mouseleave', (event) => { + let tooltip = this.querySelector('.mousePointer'); + let fadeOut = setInterval(function () { + if (!tooltip.style.opacity) { + tooltip.style.opacity = 1; + } + if (tooltip.style.opacity > 0) { + tooltip.style.opacity -= 0.1; + } else { + clearInterval(fadeOut); + } + }, 100); + }); + } else { + this.querySelector('.mousePointer').style.display = 'none'; + } + }); + this.content.replaceChildren(container); + } + + buildChart(hass) { // Initialize the content if it's not there yet. if (!this.content) { this.innerHTML = ` - - +
+
+
+
+
- margin-bottom: 5px; - /*margin-left: -120px;*/ - margin-left: -5px; - padding: 7px; - width: 240px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - background-color: #000000; - background-color: hsla(0, 0%, 20%, 0.9); - color: #ffffff; - - text-align: center; - font-size: 12px; - line-height: 1.2; - position: absolute; - } - - .custom-tooltip:after { - - position: absolute; - bottom: -15%; - left: 2%; - - width: 0; - border-top: 5px solid #000000; - border-top: 5px solid hsla(0, 0%, 20%, 0.9); - border-right: 5px solid transparent; - border-left: 5px solid transparent; - content: " "; - font-size: 0; - line-height: 0; - } - - .vpd-table { - display: table; - width: 100%; - height: 100%; - } - - .row { - display: table-row; - background-color: #ffffff; - } - - .cell { - display: table-cell; - } - -
-
-
-
-
- `; + + `; this.content = this.querySelector("div.vpd-card-container"); + + let table; + if (localStorage.getItem('vpd-table-card')) { + table = localStorage.getItem('vpd-table-card'); + } else { + table = this.buildTable(); + localStorage.setItem('vpd-table-card', table); + } + this.content.innerHTML = "
" + table + "
"; + } - let table; - if (localStorage.getItem('vpd-table-card')) { - table = localStorage.getItem('vpd-table-card'); - } else { - table = this.buildTable(); - localStorage.setItem('vpd-table-card', table); - } - this.content.innerHTML = "
" + table + "
"; this.buildTooltip(this.content, hass); if (this.enable_tooltip) { this.content.addEventListener('mouseover', (event) => { @@ -192,27 +416,10 @@ class HaVpdChart extends HTMLElement { } }, 100); }); - } else { + } else { this.querySelector('.mousePointer').style.display = 'none'; } } - setConfig(config) { - this.config = config; - if (!config.sensors) { - throw new Error('You need to define sensors'); - } - - this.vpd_phases = config.vpd_phases || this.vpd_phases; - this.sensors = config.sensors || this.sensors; - this.airText = config.air_text || "Air"; - this.rhText = config.rh_text || "RH"; - this.min_temperature = config.min_temperature || this.min_temperature; - this.max_temperature = config.max_temperature || this.max_temperature; - this.min_humidity = config.min_humidity || this.min_humidity; - this.max_humidity = config.max_humidity || this.max_humidity; - this.steps_temperature = config.steps_temperature || this.steps_temperature; - this.steps_humidity = config.steps_humidity || this.steps_humidity; - } getCardSize() { return 3; @@ -225,6 +432,7 @@ class HaVpdChart extends HTMLElement { } getPhaseClass(vpd) { + /* add randomizer for development */ for (const phase of this.vpd_phases) { if (phase.upper === undefined) { if (vpd >= phase.lower) { @@ -279,6 +487,7 @@ class HaVpdChart extends HTMLElement { buildTooltip(table, hass) { const fragment = document.createDocumentFragment(); + const sensors = this.querySelector('#sensors'); this.config.sensors.forEach((sensor, index) => { let humidity = hass.states[sensor.humidity].state; let temperature = hass.states[sensor.temperature].state; @@ -293,47 +502,48 @@ class HaVpdChart extends HTMLElement { const relativeTemperature = temperature - this.min_temperature; const totalTemperatureRange = this.max_temperature - this.min_temperature; const percentageTemperature = (relativeTemperature / totalTemperatureRange) * 100; + // Check if the circle already exists, if not create a new one and set a already_created_bool to not append + let circle = document.getElementsByClassName('sensor-circle-' + index)[0] || document.createElement('div'); + circle.className = 'highlight sensor-circle-' + index; + circle.style.width = "10px"; + circle.style.height = "10px"; + circle.style.backgroundColor = "white"; + circle.style.borderRadius = "50%"; + circle.style.position = "absolute"; + circle.style.left = `${percentageHumidity}%`; + circle.style.bottom = `${100 - percentageTemperature}%`; + circle.style.transform = "translateX(-50%)"; - const horizontalLine = document.createElement('div'); + let horizontalLine = document.getElementsByClassName('horizontal-line-' + index)[0] || document.createElement('div'); horizontalLine.style.position = 'absolute'; horizontalLine.style.left = 0; horizontalLine.style.right = 0; + horizontalLine.className = 'horizontal-line horizontal-line-' + index; horizontalLine.style.top = `calc(${percentageTemperature}% - 5px)`; horizontalLine.style.height = '1px'; horizontalLine.style.backgroundColor = 'rgba(255,255,255,0.4)'; - this.content.appendChild(horizontalLine); + fragment.appendChild(horizontalLine); - const verticalLine = document.createElement('div'); + let verticalLine = document.getElementsByClassName('vertical-line-' + index)[0] || document.createElement('div'); verticalLine.style.position = 'absolute'; + verticalLine.className = 'vertical-line vertical-line-' + index; verticalLine.style.top = 0; verticalLine.style.bottom = 0; verticalLine.style.left = `calc(${percentageHumidity}% - 0.5px)`; verticalLine.style.width = '1px'; verticalLine.style.backgroundColor = 'rgba(255,255,255,0.4)'; - this.content.appendChild(verticalLine); + fragment.appendChild(verticalLine); - const circle = document.createElement('div'); - circle.className = 'highlight'; - circle.style.width = "10px"; - circle.style.height = "10px"; - circle.style.backgroundColor = "white"; - circle.style.borderRadius = "50%"; - circle.style.position = "absolute"; - circle.style.left = `${percentageHumidity}%`; - circle.style.bottom = `${100 - percentageTemperature}%`; - circle.style.transform = "translateX(-50%)"; - - const tooltip = document.createElement('div'); + let tooltip = document.createElement('div'); tooltip.className = 'custom-tooltip'; tooltip.innerHTML = `${sensor.name}: kPa: ${vpd} | ${this.rhText}: ${humidity}% | ${this.airText}: ${temperature}°C`; circle.appendChild(tooltip); - fragment.appendChild(circle); }); requestAnimationFrame(() => { - table.appendChild(fragment); + sensors.replaceChildren(fragment); }); } @@ -354,6 +564,7 @@ class HaVpdChart extends HTMLElement { circle.appendChild(tooltip); } } + } customElements.define('ha-vpd-chart', HaVpdChart);