{# Inline SVG chart helpers. No JS deps; everything renders at request time. The SVGs scale via the .chart-svg width:100% rule in brains.css. #} {% macro bar_histogram(data, height=160, max_value=None, label_field='label', value_field='value', show_values=True) %} {# data = list of {label, value}. Renders a vertical bar chart. #} {% set n = data|length %} {% if n %} {% set _max = max_value if max_value is not none else (data|map(attribute=value_field)|max) %} {% set _max = _max if _max else 1 %} {% set _padding_top = 18 %} {% set _padding_bottom = 28 %} {% set _chart_h = height - _padding_top - _padding_bottom %} {% set _gap = 4 %} {% set _viewbox_w = 480 %} {% set _bar_w = ((_viewbox_w - (_gap * (n + 1))) / n) | round(2) %} {% for row in data %} {% set v = row[value_field] %} {% set h = ((v / _max) * _chart_h) | round(2) %} {% set x = (_gap + loop.index0 * (_bar_w + _gap)) | round(2) %} {% set y = (_padding_top + _chart_h - h) | round(2) %} {{ row[label_field] }}: {{ v }} {% if show_values %} {{ v }} {% endif %} {{ row[label_field] }} {% endfor %} {% else %}

No data to chart.

{% endif %} {% endmacro %} {% macro sparkline(values, width=120, height=28) %} {# values = list of numbers. Renders a simple area + line sparkline. #} {% if values and values|length > 1 %} {% set _max = (values|max) %} {% set _max = _max if _max else 1 %} {% set n = values|length %} {% set _step = (width / (n - 1)) | round(3) %} {% set _pts = [] %} {% for v in values %} {% set x = (loop.index0 * _step) | round(2) %} {% set y = (height - (v / _max) * (height - 2) - 1) | round(2) %} {% set _ = _pts.append(x ~ ',' ~ y) %} {% endfor %} {% set line = ' '.join(_pts) %} {% set area = 'M0,' ~ height ~ ' L' ~ line ~ ' L' ~ width ~ ',' ~ height ~ ' Z' %} {% else %} {% endif %} {% endmacro %}