From 239987bf8d626e52022c5dc7a086c19448a34886 Mon Sep 17 00:00:00 2001 From: Viet Ngoc Date: Wed, 20 Nov 2024 15:30:40 +0100 Subject: [PATCH] refactor: Improve MoonHorizon chart responsiveness and resizing --- src/components/moon-horizon.ts | 53 ++++++++++++++++++++---------- src/lunar-phase-card.ts | 60 +++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 44 deletions(-) diff --git a/src/components/moon-horizon.ts b/src/components/moon-horizon.ts index 344cab3..4b51b6e 100644 --- a/src/components/moon-horizon.ts +++ b/src/components/moon-horizon.ts @@ -31,6 +31,7 @@ export class MoonHorizon extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) moon!: Moon; @property({ attribute: false }) card!: LunarPhaseCard; + @property({ type: Number }) cardWidth = 0; @state() _chart!: Chart; @state() moreInfo = false; @@ -39,8 +40,6 @@ export class MoonHorizon extends LitElement { @state() private _timeAnimationFrame: number | null = null; @state() private _lastTime: string | null = null; - @state() _resizeInitiated = false; - @state() _resizeObserver: ResizeObserver | null = null; connectedCallback(): void { super.connectedCallback(); @@ -59,10 +58,17 @@ export class MoonHorizon extends LitElement { protected async firstUpdated(changedProps: PropertyValues): Promise { super.firstUpdated(changedProps); - await new Promise((resolve) => setTimeout(resolve, 50)); + await new Promise((resolve) => setTimeout(resolve, 20)); this.setupChart(); } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (changedProps.has('cardWidth')) { + this._chart?.update('resize'); + } + } + static get styles(): CSSResultGroup { return [ css` @@ -84,6 +90,7 @@ export class MoonHorizon extends LitElement { .moon-horizon canvas { width: 100%; height: 100%; + display: block; } .moon-data-wrapper { @@ -137,6 +144,7 @@ export class MoonHorizon extends LitElement { plugins.push(this.timeMarkerPlugin()); plugins.push(this.moonMarkerPlugin()); plugins.push(this.highestAltitudePlugin()); + plugins.push(this.expandChartArea()); return plugins; } @@ -178,8 +186,9 @@ export class MoonHorizon extends LitElement { data: data, options: { ...options, - resizeDelay: 1000, - aspectRatio: 2, + responsive: true, // Make sure chart is responsive + maintainAspectRatio: false, // Allow dynamic resizing + resizeDelay: 0, // Adjust delay for smoother resizing scales: { ...options.scales, x: { @@ -222,13 +231,6 @@ export class MoonHorizon extends LitElement { // console.log('Clicked on', dataIndex, element); } }, - onResize: (_chart, size) => { - // Resize the chart if the width has changed - if (this.card._cardWidth !== size.width) { - _chart.resize(); - _chart.update('none'); - } - }, }, plugins: [...customPlugins], @@ -250,7 +252,7 @@ export class MoonHorizon extends LitElement { protected render(): TemplateResult { return html`
- +
@@ -515,11 +517,9 @@ export class MoonHorizon extends LitElement { }; const layout: ChartOptions['layout'] = { + autoPadding: false, padding: { - bottom: 10, - left: 4, - right: 4, - top: 10, + left: -8, }, }; // Options @@ -758,6 +758,25 @@ export class MoonHorizon extends LitElement { }, }; }; + + private expandChartArea = (): Plugin => { + return { + id: 'expandChartArea', + beforeDraw: (chart: Chart) => { + chart.chartArea.left = 0; + chart.chartArea.right = chart.width; + chart.chartArea.top = 0; + chart.chartArea.bottom = chart.height; + }, + + afterUpdate: (chart: Chart) => { + chart.chartArea.left = 0; + chart.chartArea.right = chart.width; + chart.chartArea.top = 0; + chart.chartArea.bottom = chart.height; + }, + }; + }; } declare global { diff --git a/src/lunar-phase-card.ts b/src/lunar-phase-card.ts index ef6369c..ade734e 100644 --- a/src/lunar-phase-card.ts +++ b/src/lunar-phase-card.ts @@ -24,7 +24,7 @@ import './components/moon-phase-calendar'; // styles import style from './css/style.css'; -const BASE_REFRESH_INTERVAL = 15 * 1000; +const BASE_REFRESH_INTERVAL = 60 * 1000; const LOADING_TIMEOUT = 1500; @customElement('lunar-phase-card') @@ -44,12 +44,12 @@ export class LunarPhaseCard extends LitElement { @property({ type: Object }) protected moon!: Moon; @state() _activeCard: PageType | null = null; @state() selectedDate: Date | undefined; - @state() _refreshInterval: number | undefined; @state() _calendarPopup: boolean = false; - @state() _state: MoonState = MoonState.READY; @state() _resizeInitiated = false; @state() public _cardWidth = 0; + @state() private _state: MoonState = MoonState.READY; + @state() private _refreshInterval: number | undefined; @state() _activeEditorPage?: PageType; @state() _resizeObserver: ResizeObserver | null = null; @@ -83,13 +83,14 @@ export class LunarPhaseCard extends LitElement { window.LunarCard = this; window.Moon = this.moon; } + this.startRefreshInterval(); + if (isEditorMode(this)) { document.addEventListener('toggle-graph-editor', (ev) => this._handleEditorEvent(ev as CustomEvent)); } if (!this._resizeInitiated && !this._resizeObserver) { this.delayedAttachResizeObserver(); } - this.startRefreshInterval(); } disconnectedCallback(): void { @@ -107,16 +108,14 @@ export class LunarPhaseCard extends LitElement { } attachResizeObserver(): void { - if (this._resizeObserver) { - return; - } - this._resizeObserver = new ResizeObserver(() => { + const ro = new ResizeObserver(() => { this.measureCard(); }); const card = this.shadowRoot?.querySelector('ha-card') as HTMLElement; if (card) { - this._resizeObserver.observe(card); + ro.observe(card); + this._resizeObserver = ro; } } @@ -132,11 +131,7 @@ export class LunarPhaseCard extends LitElement { const header = this.shadowRoot?.getElementById('lpc-header') as HTMLElement; if (card) { this._cardWidth = card.clientWidth; - } - - if (header) { - const sizes = header.getBoundingClientRect(); - // console.log(JSON.stringify(sizes, null, 2)); + // console.log('card width', this._cardWidth); } } @@ -257,19 +252,25 @@ export class LunarPhaseCard extends LitElement { if (this._refreshInterval !== undefined) { clearInterval(this._refreshInterval); } - + // Calculate the remaining time until the next full minute + const now = new Date(); + const remainingMs = (60 - now.getSeconds()) * 1000; // Set up a new interval - this._refreshInterval = window.setInterval(() => { - if (this._activeCard === PageType.BASE || this._activeCard === PageType.HORIZON) { - this._state = MoonState.LOADING; - setTimeout(() => { - this._state = MoonState.READY; - }, LOADING_TIMEOUT); - this.requestUpdate(); - } else { - this.clearRefreshInterval(); - } - }, BASE_REFRESH_INTERVAL); + setTimeout(() => { + this._refreshInterval = window.setInterval(() => { + if (this._activeCard === PageType.BASE || this._activeCard === PageType.HORIZON) { + if (this._state !== MoonState.LOADING) { + this._state = MoonState.LOADING; + setTimeout(() => { + // console.log('Refresh interval triggered'); + this._state = MoonState.READY; + this.requestUpdate(); + }, LOADING_TIMEOUT); + } + } + }, BASE_REFRESH_INTERVAL); + // console.log('Triggering first refresh'); + }, remainingMs); } private clearRefreshInterval() { @@ -437,7 +438,12 @@ export class LunarPhaseCard extends LitElement { } private renderHorizon(): TemplateResult | void { - return html``; + return html``; } private updateDate(action?: 'next' | 'prev') {