From 19e590148d1ae3a028b98b4239b26e38bfcd14d9 Mon Sep 17 00:00:00 2001 From: troinine Date: Wed, 31 Dec 2025 20:58:19 +0200 Subject: [PATCH 1/4] fix: implement hard limit for canvas width when using forecast mode --- README.md | 3 + src/components/wfc-forecast-chart.ts | 88 +++++++++++++++++++++++----- test/weather-forecast-chart.test.ts | 56 ++++++++++++++++++ 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 293c0a2..d252e31 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,9 @@ The `current` object controls the display of current weather information and att | `show_sun_times` | boolean | `true` | Displays sunrise and sunset times in the hourly forecast, and uses specific icons to visualize clear night conditions. | | `use_color_thresholds` | boolean | `false` | Replaces solid temperature lines with a gradient based on actual values when using forecast chart mode. Colors transition at fixed intervals: -10° (Cold), 0° (Freezing), 8° (Chilly), 18° (Mild), 26° (Warm), and 34° (Hot). These thresholds are specified in degrees Celsius (°C). | +> [!IMPORTANT] +> **Canvas width limit:** To ensure compatibility across different browsers and prevent rendering errors, the canvas width is capped at 16384 pixels when using forecast chart mode. This limit is sufficient for most forecast services. However, any data exceeding this width will be truncated. + ### Forecast Actions Actions support standard Home Assistant card actions. However, one additional action has been defined: `toggle-forecast` will toggle the forecast between daily and hourly forecast. diff --git a/src/components/wfc-forecast-chart.ts b/src/components/wfc-forecast-chart.ts index 9cbacfa..18ceb1f 100644 --- a/src/components/wfc-forecast-chart.ts +++ b/src/components/wfc-forecast-chart.ts @@ -6,6 +6,7 @@ import { styleMap } from "lit/directives/style-map.js"; import ChartDataLabels from "chartjs-plugin-datalabels"; import { getRelativePosition } from "chart.js/helpers"; import { actionHandler } from "../hass"; +import { logger } from "../logger"; import { ExtendedHomeAssistant, ForecastActionDetails, @@ -63,6 +64,21 @@ type ForecastLineStyle = Pick< | "borderDash" >; +// A safe maximum canvas width to avoid exceeding browser limits. This limit covers +// most of the modern mobile and desktop browsers and covers enought forecast data +// for reliable forecast information. This roughly covers over 300 forecast items +// which should be more than enough to provide a reliable forecast view. +const MAX_CANVAS_WIDTH = 16384; + +/** + * A chart component to display weather forecast data. + * + * It supports both daily and hourly forecasts, rendering temperature and precipitation data. + * This component manages its own chart instance and updates it based on property changes. + * + * Note: As canvas width limits vary between browsers, this component includes logic to compute + * a safe maximum width based on the user's environment. + */ @customElement("wfc-forecast-chart") export class WfcForecastChart extends LitElement { @property({ attribute: false }) hass!: ExtendedHomeAssistant; @@ -117,11 +133,12 @@ export class WfcForecastChart extends LitElement { } render(): TemplateResult | typeof nothing { - if (!this.forecast?.length || this.itemWidth <= 0) { + const forecast = this.safeForecast; + if (!forecast?.length || this.itemWidth <= 0) { return nothing; } - const count = this.forecast.length; + const count = forecast.length; const gaps = Math.max(count - 1, 0); const totalWidthCalc = `calc(${count} * var(--forecast-item-width) + ${gaps} * var(--forecast-item-gap))`; @@ -154,7 +171,9 @@ export class WfcForecastChart extends LitElement { @pointerdown=${this._onPointerDown} @action=${this._onForecastAction} > -
${this.renderHeaderItems()}
+
+ ${this.renderHeaderItems(forecast)} +