import { LitElement, html } from 'https://unpkg.com/@polymer/lit-element@^0.5.2/lit-element.js?module'; class CircleSensorCard extends LitElement { static get properties() { return { hass: Object, config: Object, state: Object, dashArray: String } } _render({ state, dashArray, config }) { return html`
${config.name != null ? html`${config.name}` : ''} ${config.attribute ? state.attributes[config.attribute] : state.state} ${config.show_max ? html` / ${config.attribute_max ? state.attributes[config.attribute_max] : config.max}` : (config.units ? config.units : state.attributes.unit_of_measurement)}
`; } _createRoot() { const shadow = this.attachShadow({ mode: 'open' }) if (!this.config.show_card) { return shadow; } const card = document.createElement('ha-card'); shadow.appendChild(card); return card; } _didRender() { this.circle = this._root.querySelector('#circle'); if (this.config) { this._updateConfig(); } } setConfig(config) { if (!config.entity) { throw Error('No entity defined') } this.config = config; if (this.circle) { this._updateConfig(); } } getCardSize() { return 3; } _updateConfig() { const container = this._root.querySelector('.labelContainer'); container.style.color = 'var(--primary-text-color)'; if (this.config.font_style) { Object.keys(this.config.font_style).forEach((prop) => { container.style.setProperty(prop, this.config.font_style[prop]); }); } } set hass(hass) { this.state = hass.states[this.config.entity]; if (this.config.attribute) { if (!this.state.attributes[this.config.attribute] || isNaN(this.state.attributes[this.config.attribute])) { console.error(`Attribute [${this.config.attribute}] is not a number`); return; } } else { if (!this.state || isNaN(this.state.state)) { console.error(`State is not a number`); return; } } const state = this.config.attribute ? this.state.attributes[this.config.attribute] : this.state.state; const r = 200 * .45; const min = this.config.min || 0; const max = this.config.attribute_max ? this.state.attributes[this.config.attribute_max] : (this.config.max || 100); const val = this._calculateValueBetween(min, max, state); const score = val * 2 * Math.PI * r; const total = 10 * r; this.dashArray = `${score} ${total}`; let colorStops = {}; colorStops[min] = this.config.stroke_color || '#03a9f4'; if (this.config.color_stops) { Object.keys(this.config.color_stops).forEach((key) => { colorStops[key] = this.config.color_stops[key]; }); } if (this.circle) { const stroke = this._calculateStrokeColor(state, colorStops); this.circle.setAttribute('stroke', stroke); } } _click() { this._fire('hass-more-info', { entityId: this.config.entity }); } _calculateStrokeColor(state, stops) { const sortedStops = Object.keys(stops).map(n => Number(n)).sort((a, b) => a - b); let start, end, val; const l = sortedStops.length; if (state <= sortedStops[0]) { return stops[sortedStops[0]]; } else if (state >= sortedStops[l - 1]) { return stops[sortedStops[l - 1]]; } else { for (let i = 0; i < l - 1; i++) { const s1 = sortedStops[i]; const s2 = sortedStops[i + 1]; if (state >= s1 && state < s2) { [start, end] = [stops[s1], stops[s2]]; if (!this.config.gradient) { return start; } val = this._calculateValueBetween(s1, s2, state); break; } } } return this._getGradientValue(start, end, val); } _calculateValueBetween(start, end, val) { return (val - start) / (end - start); } _getGradientValue(colorA, colorB, val) { const v1 = 1 - val; const v2 = val; const decA = this._hexColorToDecimal(colorA); const decB = this._hexColorToDecimal(colorB); const rDec = Math.floor((decA[0] * v1) + (decB[0] * v2)); const gDec = Math.floor((decA[1] * v1) + (decB[1] * v2)); const bDec = Math.floor((decA[2] * v1) + (decB[2] * v2)); const rHex = this._padZero(rDec.toString(16)); const gHex = this._padZero(gDec.toString(16)); const bHex = this._padZero(bDec.toString(16)); return `#${rHex}${gHex}${bHex}`; } _hexColorToDecimal(color) { let c = color.substr(1); if (c.length === 3) { c = `${c[0]}${c[0]}${c[1]}${c[1]}${c[2]}${c[2]}`; } const [r, g, b] = c.match(/.{2}/g); return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)]; } _padZero(val) { if (val.length < 2) { val = `0${val}`; } return val.substr(0, 2); } _fire(type, detail) { const event = new Event(type, { bubbles: true, cancelable: false, composed: true }); event.detail = detail || {}; this.shadowRoot.dispatchEvent(event); return event; } } customElements.define('circle-sensor-card', CircleSensorCard);