fix: analytics charts now show y-axis units & tick labels
5 tick labels (0/25/50/75/100% of max) appear on every analytics
chart's y-axis — line_chart macro accepts unit ("s") or as_pct=True
for percentage charts, plus an optional axis_label rendered top-left
above the highest tick. Daily-views bar chart gets the same treatment
inline (unit "views").
Per chart:
Daily views bar → "views" axis, integer ticks
Session Duration line → "s" unit, "seconds" axis label
Engagement line → 0-100% formatting
Bounce Rate line → 0-100% formatting
External Referrer line → "visits" axis, integer ticks
viewBox widens from 560→610 to reserve ~50px on the left for the
y-tick labels; SVG scales to container so no CSS change is needed.
This commit is contained in:
parent
4cbd7e4b20
commit
14ebda23a0
1 changed files with 41 additions and 22 deletions
|
|
@ -6,29 +6,43 @@
|
|||
|
||||
{% block content -%}
|
||||
|
||||
{% macro line_chart(data, max_value, label, color) %}
|
||||
{# y-axis tick label — `as_pct` formats v as a percentage (0..1 → 0%..100%),
|
||||
otherwise show v rounded as integer with `unit` suffix appended. #}
|
||||
{% macro y_tick_label(v, unit, as_pct) -%}
|
||||
{%- if as_pct -%}{{ (v * 100) | round(0) | int }}%{%- else -%}{{ v | round(0) | int }}{{ unit }}{%- endif -%}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro line_chart(data, max_value, label, color, unit="", as_pct=False, axis_label="") %}
|
||||
{% if data and max_value > 0 %}
|
||||
<div class="analytics-chart-svg">
|
||||
<svg viewBox="0 0 560 160" role="img" aria-label="{{ label }}">
|
||||
{% for pct in [25, 50, 75] %}
|
||||
<line x1="0" y1="{{ 140 - (pct / 100 * 130) }}" x2="556" y2="{{ 140 - (pct / 100 * 130) }}"
|
||||
stroke="var(--border-light, #e9ecef)" stroke-width="1" />
|
||||
<svg viewBox="0 0 610 170" role="img" aria-label="{{ label }}">
|
||||
{# y-axis label (top-left, above the highest tick) #}
|
||||
{% if axis_label %}
|
||||
<text x="50" y="8" text-anchor="start"
|
||||
font-size="9" fill="var(--text-muted, #999)">{{ axis_label }}</text>
|
||||
{% endif %}
|
||||
{# gridlines + y-axis tick labels (0/25/50/75/100% of max) #}
|
||||
{% for pct in [0, 25, 50, 75, 100] %}
|
||||
{% set y_pos = 140 - (pct / 100 * 130) %}
|
||||
<line x1="50" y1="{{ y_pos }}" x2="606" y2="{{ y_pos }}"
|
||||
stroke="{{ 'var(--border-color, #dee2e6)' if pct == 0 else 'var(--border-light, #e9ecef)' }}" stroke-width="1" />
|
||||
<text x="46" y="{{ y_pos }}" text-anchor="end" dominant-baseline="middle"
|
||||
font-size="9" fill="var(--text-muted, #999)">{{ y_tick_label((pct / 100) * max_value, unit, as_pct) }}</text>
|
||||
{% endfor %}
|
||||
<line x1="0" y1="140" x2="556" y2="140" stroke="var(--border-color, #dee2e6)" stroke-width="1" />
|
||||
<polygon points="{% for b in data %}{{ loop.index0 * 20 + 8 }},{{ 140 - (b.value / max_value * 130) }} {% endfor %}{{ (data|length - 1) * 20 + 8 }},140 8,140"
|
||||
<polygon points="{% for b in data %}{{ loop.index0 * 20 + 58 }},{{ 140 - (b.value / max_value * 130) }} {% endfor %}{{ (data|length - 1) * 20 + 58 }},140 58,140"
|
||||
fill="{{ color }}" opacity="0.15" />
|
||||
<polyline
|
||||
points="{% for b in data %}{{ loop.index0 * 20 + 8 }},{{ 140 - (b.value / max_value * 130) }} {% endfor %}"
|
||||
points="{% for b in data %}{{ loop.index0 * 20 + 58 }},{{ 140 - (b.value / max_value * 130) }} {% endfor %}"
|
||||
fill="none" stroke="{{ color }}" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" />
|
||||
{% for b in data %}
|
||||
<circle cx="{{ loop.index0 * 20 + 8 }}" cy="{{ 140 - (b.value / max_value * 130) }}"
|
||||
<circle cx="{{ loop.index0 * 20 + 58 }}" cy="{{ 140 - (b.value / max_value * 130) }}"
|
||||
r="3" fill="{{ color }}">
|
||||
<title>{{ b.label }}: {{ b.tooltip }}</title>
|
||||
</circle>
|
||||
{% endfor %}
|
||||
{% for b in data %}
|
||||
{% if loop.index0 % 7 == 0 %}
|
||||
<text x="{{ loop.index0 * 20 + 8 }}" y="155" text-anchor="middle"
|
||||
<text x="{{ loop.index0 * 20 + 58 }}" y="155" text-anchor="middle"
|
||||
font-size="9" fill="var(--text-muted, #999)">{{ b.label }}</text>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
@ -73,17 +87,22 @@
|
|||
{% if daily_views and daily_views_max > 0 %}
|
||||
<h4>Daily Views (last 28 days)</h4>
|
||||
<div class="analytics-chart-svg">
|
||||
<svg viewBox="0 0 560 160" role="img" aria-label="Daily views bar chart">
|
||||
{# Gridlines #}
|
||||
{% for pct in [25, 50, 75] %}
|
||||
<line x1="0" y1="{{ 140 - (pct / 100 * 130) }}" x2="556" y2="{{ 140 - (pct / 100 * 130) }}"
|
||||
stroke="var(--border-light, #e9ecef)" stroke-width="1" />
|
||||
<svg viewBox="0 0 610 170" role="img" aria-label="Daily views bar chart">
|
||||
{# y-axis label #}
|
||||
<text x="50" y="8" text-anchor="start"
|
||||
font-size="9" fill="var(--text-muted, #999)">views</text>
|
||||
{# Gridlines + y-axis tick labels #}
|
||||
{% for pct in [0, 25, 50, 75, 100] %}
|
||||
{% set y_pos = 140 - (pct / 100 * 130) %}
|
||||
<line x1="50" y1="{{ y_pos }}" x2="606" y2="{{ y_pos }}"
|
||||
stroke="{{ 'var(--border-color, #dee2e6)' if pct == 0 else 'var(--border-light, #e9ecef)' }}" stroke-width="1" />
|
||||
<text x="46" y="{{ y_pos }}" text-anchor="end" dominant-baseline="middle"
|
||||
font-size="9" fill="var(--text-muted, #999)">{{ ((pct / 100) * daily_views_max) | round(0) | int }}</text>
|
||||
{% endfor %}
|
||||
<line x1="0" y1="140" x2="556" y2="140" stroke="var(--border-color, #dee2e6)" stroke-width="1" />
|
||||
{# Bars #}
|
||||
{% for b in daily_views %}
|
||||
{% set bar_h = (b.count / daily_views_max * 130) if daily_views_max > 0 else 0 %}
|
||||
<rect x="{{ loop.index0 * 20 }}" y="{{ 140 - bar_h }}" width="16" height="{{ bar_h }}"
|
||||
<rect x="{{ loop.index0 * 20 + 50 }}" y="{{ 140 - bar_h }}" width="16" height="{{ bar_h }}"
|
||||
rx="2" fill="var(--green-color, #a3c765)">
|
||||
<title>{{ b.label }}: {{ b.count }} view{{ 's' if b.count != 1 else '' }}</title>
|
||||
</rect>
|
||||
|
|
@ -91,7 +110,7 @@
|
|||
{# Date labels every 7th bar #}
|
||||
{% for b in daily_views %}
|
||||
{% if loop.index0 % 7 == 0 %}
|
||||
<text x="{{ loop.index0 * 20 + 8 }}" y="155" text-anchor="middle"
|
||||
<text x="{{ loop.index0 * 20 + 58 }}" y="155" text-anchor="middle"
|
||||
font-size="9" fill="var(--text-muted, #999)">{{ b.label }}</text>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
@ -103,19 +122,19 @@
|
|||
{% if daily_session_duration_max > 0 %}
|
||||
<h4>Session Duration Trend (last 28 days)</h4>
|
||||
<p class="analytics-hint">Average time visitors spend per session.</p>
|
||||
{{ line_chart(daily_session_duration, daily_session_duration_max, "Session duration trend", "var(--blue-color, #98b6fa)") }}
|
||||
{{ line_chart(daily_session_duration, daily_session_duration_max, "Session duration trend", "var(--blue-color, #98b6fa)", unit="s", axis_label="seconds") }}
|
||||
{% endif %}
|
||||
|
||||
{% if daily_engagement %}
|
||||
<h4>Engagement Trend (last 28 days)</h4>
|
||||
<p class="analytics-hint">Active interaction time as a fraction of total session time.</p>
|
||||
{{ line_chart(daily_engagement, 1.0, "Engagement trend", "var(--green-color, #a3c765)") }}
|
||||
{{ line_chart(daily_engagement, 1.0, "Engagement trend", "var(--green-color, #a3c765)", as_pct=True, axis_label="%") }}
|
||||
{% endif %}
|
||||
|
||||
{% if daily_bounce %}
|
||||
<h4>Bounce Rate Trend (last 28 days)</h4>
|
||||
<p class="analytics-hint">Sessions under 7 seconds visible. Lower is better.</p>
|
||||
{{ line_chart(daily_bounce, 1.0, "Bounce rate trend", "var(--red-color, #bc2131)") }}
|
||||
{{ line_chart(daily_bounce, 1.0, "Bounce rate trend", "var(--red-color, #bc2131)", as_pct=True, axis_label="%") }}
|
||||
{% endif %}
|
||||
|
||||
{# --- Ring Consumed breakdown --- #}
|
||||
|
|
@ -429,7 +448,7 @@
|
|||
{% if daily_referrers_max > 0 %}
|
||||
<h4>External Referrer Trend (last 28 days)</h4>
|
||||
<p class="analytics-hint">Daily count of visits from external referrers (excludes direct and internal traffic).</p>
|
||||
{{ line_chart(daily_referrers, daily_referrers_max, "External referrer trend", "var(--orange-color, #e8a838)") }}
|
||||
{{ line_chart(daily_referrers, daily_referrers_max, "External referrer trend", "var(--orange-color, #e8a838)", axis_label="visits") }}
|
||||
{% endif %}
|
||||
|
||||
{# --- Top Referrer Domains (21d) --- #}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue