Speed things up (#2270)

* Speed things up

* Fixes
This commit is contained in:
Paulus Schoutsen 2018-12-12 08:51:59 +01:00 committed by GitHub
parent 7cd6619a79
commit edef4ba2f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 82 deletions

View File

@ -0,0 +1,3 @@
export const afterNextRender = (cb: () => void): void => {
requestAnimationFrame(() => setTimeout(cb, 0));
};

View File

@ -84,7 +84,9 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
super.firstUpdated(changedProperties);
this.addEventListener("click", (ev) => {
ev.stopPropagation();
fireEvent(this, "hass-more-info", { entityId: this.state!.entity_id });
if (this.state) {
fireEvent(this, "hass-more-info", { entityId: this.state.entity_id });
}
});
}

View File

@ -37,13 +37,15 @@ export const hassLocalizeLitMixin = <T extends LitElement>(
public connectedCallback(): void {
super.connectedCallback();
let language;
let resources;
if (this.hass) {
language = this.hass.language;
resources = this.hass.resources;
if (this.localize === empty) {
let language;
let resources;
if (this.hass) {
language = this.hass.language;
resources = this.hass.resources;
}
this.localize = this.__computeLocalize(language, resources);
}
this.localize = this.__computeLocalize(language, resources);
}
public updated(changedProperties: PropertyValues) {

View File

@ -19,6 +19,7 @@ import { LovelaceCardConfig } from "../../../data/lovelace";
import "../../../components/ha-card";
import "../../../components/ha-icon";
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
import { afterNextRender } from "../../../common/util/render-status";
const thermostatConfig = {
radius: 150,
@ -68,6 +69,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
private _config?: Config;
private _roundSliderStyle?: TemplateResult;
private _jQuery?: any;
private _broadCard?: boolean;
static get properties(): PropertyDeclarations {
return {
@ -95,7 +97,6 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
return html``;
}
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
const broadCard = this.clientWidth > 390;
const mode = modeIcons[stateObj.attributes.operation_mode || ""]
? stateObj.attributes.operation_mode!
: "unknown-mode";
@ -104,8 +105,8 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
<ha-card
class="${classMap({
[mode]: true,
large: broadCard,
small: !broadCard,
large: this._broadCard!,
small: !this._broadCard,
})}">
<div id="root">
<div id="thermostat"></div>
@ -146,8 +147,41 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
return hasConfigOrEntityChanged(this, changedProps);
}
protected async firstUpdated(): Promise<void> {
protected firstUpdated(): void {
this._initialLoad();
}
protected updated(changedProps: PropertyValues): void {
if (!this._config || !this.hass || !changedProps.has("hass")) {
return;
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.themes !== this.hass.themes) {
applyThemesOnElement(this, this.hass.themes, this._config.theme);
}
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
if (
this._jQuery &&
// If jQuery changed, we just rendered in firstUpdated
!changedProps.has("_jQuery") &&
(!oldHass || oldHass.states[this._config.entity] !== stateObj)
) {
const [sliderValue, uiValue] = this._genSliderValue(stateObj);
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
value: sliderValue,
});
this._updateSetTemp(uiValue);
}
}
private async _initialLoad(): Promise<void> {
const loaded = await loadRoundslider();
await new Promise((resolve) => afterNextRender(resolve));
this._roundSliderStyle = loaded.roundSliderStyle;
this._jQuery = loaded.jQuery;
@ -160,6 +194,8 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
? "range"
: "min-range";
const [sliderValue, uiValue] = this._genSliderValue(stateObj);
this._broadCard = this.clientWidth > 390;
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
...thermostatConfig,
radius: this.clientWidth / 3,
@ -168,18 +204,14 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
sliderType: _sliderType,
change: (value) => this._setTemperature(value),
drag: (value) => this._dragEvent(value),
value: sliderValue,
});
this._updateSetTemp(uiValue);
}
protected updated(changedProps: PropertyValues): void {
if (!this._config || !this.hass || !this._jQuery) {
return;
}
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
let sliderValue;
let uiValue;
private _genSliderValue(stateObj: ClimateEntity): [string | number, string] {
let sliderValue: string | number;
let uiValue: string;
if (
stateObj.attributes.target_temp_low &&
@ -193,18 +225,11 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
String(stateObj.attributes.target_temp_high),
]);
} else {
sliderValue = uiValue = stateObj.attributes.temperature;
sliderValue = stateObj.attributes.temperature;
uiValue = "" + stateObj.attributes.temperature;
}
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
value: sliderValue,
});
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = uiValue;
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.themes !== this.hass.themes) {
applyThemesOnElement(this, this.hass.themes, this._config.theme);
}
return [sliderValue, uiValue];
}
private renderStyle(): TemplateResult {
@ -383,10 +408,12 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
`;
}
private _updateSetTemp(value: string): void {
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = value;
}
private _dragEvent(e): void {
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = formatTemp(
String(e.value).split(",")
);
this._updateSetTemp(formatTemp(String(e.value).split(",")));
}
private _setTemperature(e): void {

View File

@ -44,6 +44,7 @@ import { HUIView } from "./hui-view";
import createCardElement from "./common/create-card-element";
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
import { Lovelace } from "./types";
import { afterNextRender } from "../../common/util/render-status";
// CSS and JS should only be imported once. Modules and HTML are safe.
const CSS_CACHE = {};
@ -57,10 +58,11 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
public columns?: number;
public route?: { path: string; prefix: string };
private _routeData?: { view: string };
private _curView: number | "unused";
private _curView?: number | "unused";
private notificationsOpen?: boolean;
private _persistentNotifications?: Notification[];
private _haStyle?: DocumentFragment;
private _viewCache?: { [viewId: string]: HUIView };
private _debouncedConfigChanged: () => void;
private _unsubNotifications?: () => void;
@ -82,9 +84,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
constructor() {
super();
this._curView = 0;
this._debouncedConfigChanged = debounce(
() => this._selectView(this._curView),
() => this._selectView(this._curView, true),
100
);
}
@ -349,6 +350,9 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
huiView.hass = this.hass;
}
let newSelectView;
let force = false;
if (changedProperties.has("route")) {
const views = this.config && this.config.views;
if (
@ -367,9 +371,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
break;
}
}
if (index !== this._curView) {
this._selectView(index);
}
newSelectView = index;
}
}
@ -379,15 +381,20 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
| undefined;
if (!oldLovelace || oldLovelace.config !== this.lovelace!.config) {
this._viewCache = {};
this._loadResources(this.lovelace!.config.resources || []);
// On config change, recreate the view from scratch.
this._selectView(this._curView);
force = true;
}
if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) {
this._editModeChanged();
force = true;
}
}
if (newSelectView !== undefined || force) {
this._selectView(newSelectView, force);
}
}
private get _notifications() {
@ -442,7 +449,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
}
private _handleUnusedEntities(): void {
this._selectView("unused");
this._selectView("unused", false);
}
private _deselect(ev): void {
@ -471,10 +478,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
}
}
private _editModeChanged(): void {
this._selectView(this._curView);
}
private _editView() {
showEditViewDialog(this, {
lovelace: this.lovelace!,
@ -501,45 +504,61 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
scrollToTarget(this, this._layout.header.scrollTarget);
}
private _selectView(viewIndex: HUIRoot["_curView"]): void {
private async _selectView(
viewIndex: HUIRoot["_curView"],
force: boolean
): Promise<void> {
if (!force && this._curView === viewIndex) {
return;
}
viewIndex = viewIndex === undefined ? 0 : viewIndex;
this._curView = viewIndex;
// Recreate a new element to clear the applied themes.
const root = this._view;
if (root.lastChild) {
root.removeChild(root.lastChild);
}
let view;
let background = this.config.background || "";
if (viewIndex === "unused") {
view = document.createElement("hui-unused-entities");
view.setConfig(this.config);
const unusedEntities = document.createElement("hui-unused-entities");
unusedEntities.setConfig(this.config);
root.style.background = this.config.background || "";
root.appendChild(unusedEntities);
return;
}
let view;
const viewConfig = this.config.views[viewIndex];
if (!viewConfig) {
this._editModeEnable();
return;
}
if (!force && this._viewCache![viewIndex]) {
view = this._viewCache![viewIndex];
} else {
const viewConfig = this.config.views[this._curView];
if (!viewConfig) {
this._editModeEnable();
return;
}
await new Promise((resolve) => afterNextRender(resolve));
if (viewConfig.panel && viewConfig.cards && viewConfig.cards.length > 0) {
view = createCardElement(viewConfig.cards[0]);
view.isPanel = true;
} else {
view = document.createElement("hui-view");
view.lovelace = this.lovelace;
view.config = viewConfig;
view.columns = this.columns;
view.index = viewIndex;
}
if (viewConfig.background) {
background = viewConfig.background;
}
this._viewCache![viewIndex] = view;
}
this._view.style.background = background;
view.hass = this.hass;
root.style.background =
viewConfig.background || this.config.background || "";
root.appendChild(view);
}

View File

@ -24,6 +24,24 @@ import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog";
let editCodeLoaded = false;
// Find column with < 5 entities, else column with lowest count
const getColumnIndex = (columnEntityCount: number[], size: number) => {
let minIndex = 0;
for (let i = 0; i < columnEntityCount.length; i++) {
if (columnEntityCount[i] < 5) {
minIndex = i;
break;
}
if (columnEntityCount[i] < columnEntityCount[minIndex]) {
minIndex = i;
}
}
columnEntityCount[minIndex] += size;
return minIndex;
};
export class HUIView extends hassLocalizeLitMixin(LitElement) {
public hass?: HomeAssistant;
public lovelace?: Lovelace;
@ -245,28 +263,12 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
columnEntityCount.push(0);
}
// Find column with < 5 entities, else column with lowest count
function getColumnIndex(size) {
let minIndex = 0;
for (let i = 0; i < columnEntityCount.length; i++) {
if (columnEntityCount[i] < 5) {
minIndex = i;
break;
}
if (columnEntityCount[i] < columnEntityCount[minIndex]) {
minIndex = i;
}
}
columnEntityCount[minIndex] += size;
return minIndex;
}
elements.forEach((el, index) => {
const cardSize = computeCardSize(el);
// Element to append might be the wrapped card when we're editing.
columns[getColumnIndex(cardSize)].push(elementsToAppend[index]);
columns[getColumnIndex(columnEntityCount, cardSize)].push(
elementsToAppend[index]
);
});
// Remove empty columns