# Stats overview page rendering. Split out of stats.source.sh (task cn0) so the # HTML/layout concern lives apart from the EXIF aggregation/bucketing (now in # stats-aggregate.source.sh) and the per-filter mini-albums (now in # stats-filter-album.source.sh). This module reads the STATS_* globals filled by # collect_photo_exif_stats and turns them into the static stats overview page # (bar charts, sections, camera leaderboard). All libs are sourced before run, # so the STATS_* maps and the STATS_*_DIR constants defined in the sibling # modules are available here at runtime. # ---------------------------------------------------------------------------- # Rendering (task pm0) # ---------------------------------------------------------------------------- # render_stats_page turns the STATS_* globals filled by the aggregation above # into a static stats.html. The page is variable-length (each category may be # empty, sparse, or large) which does not fit the fixed field-spec template # engine cleanly, so we follow the same approach view/details pages use for # their dynamic EXIF table: build the whole body as an HTML string here, hand it # to stats.tmpl through the raw context field stats_body, and let the engine wrap # it with the shared header/footer chrome. Bars are plain CSS (width as a percent # of the section's top bucket) so the output stays JavaScript-free. # Print the largest counter in the named stats array, or 0 when it is empty. # Used to scale each section's bars relative to its own busiest bucket. _stats_max_count() { local -n counts_ref="$1"; shift local key local -i max=0 for key in "${!counts_ref[@]}"; do if (( counts_ref[$key] > max )); then max=${counts_ref[$key]} fi done printf '%d' "$max" } # Print the integer percentage count/total (0 when total is 0). awk keeps the # rounding off bash integer math; STATS_TOTALS[photos] is the denominator. _stats_percent() { local -ri count="$1"; shift local -ri total="$1"; shift if (( total <= 0 )); then printf '0' return fi awk -v c="$count" -v t="$total" 'BEGIN { printf "%.0f", 100 * c / t }' } # Emit one bar-chart
  • : an already-escaped label, a CSS-width bar scaled to # the section maximum, and the count plus its share of all photos. Callers escape # labels themselves because some come from EXIF (camera/lens) and some are # trusted bucket names we build internally. _stats_bar_row() { local -r label_html="$1"; shift local -ri count="$1"; shift local -ri total="$1"; shift local -ri max="$1"; shift local -i width=0 if (( max > 0 )); then width=$(( 100 * count / max )) fi printf '
  • ' printf '%s' "$label_html" printf '' printf '' \ "$width" printf '%d (%s%%)' \ "$count" "$(_stats_percent "$count" "$total")" printf '
  • \n' } # Open a
    with an escaped heading and the