diff --git a/public/images/image-broken.svg b/public/images/image-broken.svg
new file mode 100644
index 0000000000..cbd2559a26
--- /dev/null
+++ b/public/images/image-broken.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/panels/lovelace/components/hui-image.js b/src/panels/lovelace/components/hui-image.js
index 7926501752..5ec4d1accd 100644
--- a/src/panels/lovelace/components/hui-image.js
+++ b/src/panels/lovelace/components/hui-image.js
@@ -4,9 +4,9 @@ import '@polymer/paper-toggle-button/paper-toggle-button.js';
import { STATES_OFF } from '../../../common/const.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
-import isValidObject from '../common/is-valid-object';
const UPDATE_INTERVAL = 10000;
+const DEFAULT_FILTER = 'grayscale(100%)';
/*
* @appliesMixin LocalizeMixin
@@ -15,35 +15,33 @@ class HuiImage extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
-
-
-
-
-
- [[localize('ui.card.camera.not_available')]]
-
+
+
+
`;
}
@@ -57,11 +55,8 @@ class HuiImage extends LocalizeMixin(PolymerElement) {
image: String,
stateImage: Object,
cameraImage: String,
- _error: {
- type: Boolean,
- value: false
- },
- _imageClass: String,
+ filter: String,
+ stateFilter: Object,
_imageSrc: String
};
}
@@ -91,14 +86,16 @@ class HuiImage extends LocalizeMixin(PolymerElement) {
}
_onImageError() {
- this.setProperties({
- _imageSrc: null,
- _error: true
- });
+ this._imageSrc = null;
+ this.$.image.classList.add('hidden');
+ this.$.brokenImage.style.setProperty('height', `${this._lastImageHeight || '100'}px`);
+ this.$.brokenImage.classList.remove('hidden');
}
_onImageLoad() {
- this._error = false;
+ this.$.image.classList.remove('hidden');
+ this.$.brokenImage.classList.add('hidden');
+ this._lastImageHeight = this.$.image.offsetHeight;
}
_hassChanged(hass) {
@@ -106,20 +103,36 @@ class HuiImage extends LocalizeMixin(PolymerElement) {
return;
}
- const state = hass.states[this.entity];
- const unavailable = !isValidObject(state, ['state']);
+ const stateObj = hass.states[this.entity];
+ const newState = !stateObj ? 'unavailable' : stateObj.state;
+ if (newState === this._currentState) return;
+ this._currentState = newState;
+
+ this._updateStateImage();
+ this._updateStateFilter(stateObj);
+ }
+
+ _updateStateImage() {
if (!this.stateImage) {
- this._imageClass = unavailable || STATES_OFF.includes(state.state) ? 'state-off' : '';
+ this._imageFallback = true;
return;
}
+ const stateImg = this.stateImage[this._currentState];
+ this._imageSrc = stateImg || this.image;
+ this._imageFallback = !stateImg;
+ }
- const stateImg = !unavailable ? this.stateImage[state.state] : this.stateImage.unavailable;
+ _updateStateFilter(stateObj) {
+ let filter;
+ if (!this.stateFilter) {
+ filter = this.filter;
+ } else {
+ filter = this.stateFilter[this._currentState] || this.filter;
+ }
- this.setProperties({
- _imageClass: !stateImg && (unavailable || STATES_OFF.includes(state.state)) ? 'state-off' : '',
- _imageSrc: stateImg || this.image
- });
+ const isOff = !stateObj || STATES_OFF.includes(stateObj.state);
+ this.$.image.style.filter = filter || (isOff && this._imageFallback && DEFAULT_FILTER) || '';
}
_updateCameraImageSrc() {
@@ -128,17 +141,12 @@ class HuiImage extends LocalizeMixin(PolymerElement) {
entity_id: this.cameraImage,
}).then((resp) => {
if (resp.success) {
- this.setProperties({
- _imageSrc: `data:${resp.result.content_type};base64, ${resp.result.content}`,
- _error: false
- });
+ this._imageSrc = `data:${resp.result.content_type};base64, ${resp.result.content}`;
+ this._onImageLoad();
} else {
- this.setProperties({
- _imageSrc: null,
- _error: true
- });
+ this._onImageError();
}
- });
+ }, () => this._onImageError());
}
}