mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
feat(apexcharts): add legend toggle for best/peak price overlays
Implement clickable legend items to show/hide best/peak price period overlays in generated ApexCharts YAML configuration. Legend behavior by configuration: - Only best price: No legend (overlay always visible) - Only peak price: Legend shown, peak toggleable (starts hidden) - Both enabled: Legend shown, both toggleable (best visible, peak hidden) Changes: - Best price overlay: in_legend only when peak also enabled - Peak price overlay: always in_legend with hidden_by_default: true - Enable experimental.hidden_by_default when peak price active - Price level series (LOW/NORMAL/HIGH): hidden from legend when overlays active, visible otherwise (preserves easy legend enable) - Add triangle icons (▼/▲) before overlay names for visual distinction - Custom legend markers (size: 0) only when overlays active - Increased itemMargin for better visual separation Impact: Users can toggle best/peak price period visibility directly in the chart via legend click. Without overlays, legend behavior unchanged - users can still enable it by setting show: true.
This commit is contained in:
parent
2f36c73c18
commit
b541f7b15e
1 changed files with 46 additions and 7 deletions
|
|
@ -338,8 +338,15 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
series = []
|
||||
|
||||
# Get translated names for overlays (best/peak)
|
||||
best_price_name = get_translation(["apexcharts", "best_price_period_name"], user_language) or "Best Price Period"
|
||||
peak_price_name = get_translation(["apexcharts", "peak_price_period_name"], user_language) or "Peak Price Period"
|
||||
# Include triangle icons for visual distinction in legend
|
||||
# ▼ (U+25BC) = down/minimum = best price periods
|
||||
# ▲ (U+25B2) = up/maximum = peak price periods
|
||||
best_price_name = "▼ " + (
|
||||
get_translation(["apexcharts", "best_price_period_name"], user_language) or "Best Price Period"
|
||||
)
|
||||
peak_price_name = "▲ " + (
|
||||
get_translation(["apexcharts", "peak_price_period_name"], user_language) or "Peak Price Period"
|
||||
)
|
||||
|
||||
# Track overlays added for tooltip index calculation later
|
||||
best_overlay_added = False
|
||||
|
|
@ -376,6 +383,11 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
# Use first entity from entity_map (reuse existing entity to avoid extra header entries)
|
||||
best_price_entity = next(iter(entity_map.values()))
|
||||
|
||||
# Legend toggle logic:
|
||||
# - Only best price selected: no legend (in_legend: False)
|
||||
# - Both selected: show in legend, toggleable (in_legend: True)
|
||||
best_price_in_legend = highlight_peak_price # Only show in legend if peak is also enabled
|
||||
|
||||
series.append(
|
||||
{
|
||||
"entity": best_price_entity,
|
||||
|
|
@ -383,7 +395,7 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
"type": "area",
|
||||
"color": "rgba(46, 204, 113, 0.05)", # Ultra-subtle green overlay (barely visible)
|
||||
"yaxis_id": "highlight", # Use separate Y-axis (0-1) for full-height overlay
|
||||
"show": {"legend_value": False, "in_header": False, "in_legend": False},
|
||||
"show": {"legend_value": False, "in_header": False, "in_legend": best_price_in_legend},
|
||||
"data_generator": best_price_generator,
|
||||
"stroke_width": 0,
|
||||
}
|
||||
|
|
@ -414,6 +426,7 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
|
||||
peak_price_entity = next(iter(entity_map.values()))
|
||||
|
||||
# Peak price: always show in legend when enabled (for toggle), start hidden by default
|
||||
series.append(
|
||||
{
|
||||
"entity": peak_price_entity,
|
||||
|
|
@ -421,7 +434,12 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
"type": "area",
|
||||
"color": "rgba(231, 76, 60, 0.06)", # Subtle red overlay for peak price
|
||||
"yaxis_id": "highlight",
|
||||
"show": {"legend_value": False, "in_header": False, "in_legend": False},
|
||||
"show": {
|
||||
"legend_value": False,
|
||||
"in_header": False,
|
||||
"in_legend": True,
|
||||
"hidden_by_default": True, # Start hidden, user can toggle via legend
|
||||
},
|
||||
"data_generator": peak_price_generator,
|
||||
"stroke_width": 0,
|
||||
}
|
||||
|
|
@ -479,10 +497,13 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
# rating_level LOW/HIGH: Show raw state in header (entity state = min/max price of day)
|
||||
# rating_level NORMAL: Hide from header (not meaningful as extrema)
|
||||
# level (VERY_CHEAP/CHEAP/etc): Hide from header (entity state is aggregated value)
|
||||
# Price level series are hidden from legend only when best/peak overlays are enabled
|
||||
# (to keep legend clean for toggle-only items)
|
||||
hide_from_legend = highlight_best_price or highlight_peak_price
|
||||
if level_type == "rating_level" and level_key in (PRICE_RATING_LOW, PRICE_RATING_HIGH):
|
||||
show_config = {"legend_value": False, "in_header": "raw"}
|
||||
show_config = {"legend_value": False, "in_header": "raw", "in_legend": not hide_from_legend}
|
||||
else:
|
||||
show_config = {"legend_value": False, "in_header": False}
|
||||
show_config = {"legend_value": False, "in_header": False, "in_legend": not hide_from_legend}
|
||||
|
||||
series.append(
|
||||
{
|
||||
|
|
@ -570,10 +591,23 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
},
|
||||
},
|
||||
"dataLabels": {"enabled": False},
|
||||
# Legend is shown only when peak price is enabled (for toggling visibility)
|
||||
# - Only best price: no legend needed
|
||||
# - Peak price (with or without best): show legend for toggle
|
||||
"legend": {
|
||||
"show": False,
|
||||
"show": highlight_peak_price,
|
||||
"position": "bottom",
|
||||
"horizontalAlign": "center",
|
||||
# Custom markers only when overlays are enabled (hide color dots, use text icons)
|
||||
# Without overlays: use default markers so user can enable legend with just show: true
|
||||
**(
|
||||
{
|
||||
"markers": {"size": 0},
|
||||
"itemMargin": {"horizontal": 15},
|
||||
}
|
||||
if highlight_peak_price
|
||||
else {}
|
||||
),
|
||||
},
|
||||
"grid": {
|
||||
"show": True,
|
||||
|
|
@ -637,6 +671,11 @@ async def handle_apexcharts_yaml(call: ServiceCall) -> dict[str, Any]: # noqa:
|
|||
overlay_count = (1 if best_overlay_added else 0) + (1 if peak_overlay_added else 0)
|
||||
result["apex_config"]["tooltip"]["enabledOnSeries"] = list(range(overlay_count, len(series)))
|
||||
|
||||
# Enable hidden_by_default experimental feature when peak price is enabled
|
||||
# This allows peak price overlay to start hidden but be toggled via legend click
|
||||
if highlight_peak_price:
|
||||
result["experimental"] = {"hidden_by_default": True}
|
||||
|
||||
# For rolling window mode and today_tomorrow, wrap in config-template-card for dynamic config
|
||||
if use_template:
|
||||
# Find tomorrow_data_available binary sensor
|
||||
|
|
|
|||
Loading…
Reference in a new issue