217 lines
6.9 KiB
HTML
217 lines
6.9 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% from "macros.html" import format_distance with context %}
|
|
|
|
{% set heading = "Trip statistics" %}
|
|
|
|
{% block title %}{{ heading }} - Edward Betts{% endblock %}
|
|
|
|
{% block style %}
|
|
<style>
|
|
.co2-chart {
|
|
height: 240px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% macro stat_list(id, label, counter, show_top=5) %}
|
|
<div class="mb-2">
|
|
<strong>{{ label }}:</strong> {{ counter | count }}
|
|
{% if counter | count > 0 %}
|
|
<a class="btn btn-sm btn-outline-secondary ms-2" data-bs-toggle="collapse" href="#{{ id }}" role="button" aria-expanded="false">
|
|
show/hide
|
|
</a>
|
|
<div class="collapse mt-2" id="{{ id }}">
|
|
<div class="d-flex flex-wrap gap-1">
|
|
{% for item, count in counter.most_common() %}
|
|
<span class="badge text-bg-secondary">{{ item }} <span class="badge text-bg-light text-dark">{{ count }}</span></span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro format_co2(co2_kg) %}
|
|
{% if co2_kg >= 1000 %}
|
|
{{ "{:,.2f}".format(co2_kg / 1000.0) }} tonnes
|
|
{% else %}
|
|
{{ "{:,.0f}".format(co2_kg) }} kg
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<h1>Trip statistics</h1>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header"><strong>Overall Summary</strong></div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div>Trips: {{ count }}</div>
|
|
<div>Conferences: {{ conferences }}</div>
|
|
<div>Total distance: {{ format_distance(total_distance) }}</div>
|
|
{% for transport_type, distance in distances_by_transport_type %}
|
|
<div class="ms-3">{{ transport_type | title }}: {{ format_distance(distance) }}</div>
|
|
{% endfor %}
|
|
{% if total_co2_kg %}
|
|
<div class="mt-2">CO₂: {{ format_co2(total_co2_kg) }}</div>
|
|
{% endif %}
|
|
{% for transport_type, co2_kg in co2_by_transport_type %}
|
|
<div class="ms-3">{{ transport_type | title }} CO₂: {{ format_co2(co2_kg) }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div>Flight segments: {{ overall_stats.flight_count }}</div>
|
|
<div>Train segments: {{ overall_stats.train_count }}</div>
|
|
{% if co2_by_transport_type %}
|
|
<div class="co2-chart mt-3">
|
|
<canvas id="overall-co2-chart"></canvas>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
{{ stat_list("overall-airlines", "Airlines", overall_stats.airlines) }}
|
|
{{ stat_list("overall-airports", "Airports", overall_stats.airports) }}
|
|
{{ stat_list("overall-stations", "Stations", overall_stats.stations) }}
|
|
</div>
|
|
</div>
|
|
|
|
{% for year, year_stats in yearly_stats | dictsort(reverse=True) %}
|
|
{% set countries = year_stats.countries | default([]) | sort(attribute="name") %}
|
|
{% set new_countries = year_stats.new_countries | default([]) %}
|
|
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<strong>{{ year }}</strong>
|
|
<span class="text-muted ms-2">{{ year_stats.count }} trips</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row mb-2">
|
|
<div class="col-md-6">
|
|
<div>Trips: {{ year_stats.count }}</div>
|
|
<div>Conferences: {{ year_stats.conferences }}</div>
|
|
<div>Distance: {{ format_distance(year_stats.total_distance or 0) }}</div>
|
|
{% if year_stats.distances_by_transport_type %}
|
|
{% for transport_type, distance in year_stats.distances_by_transport_type.items() %}
|
|
<div class="ms-3">{{ transport_type | title }}: {{ format_distance(distance) }}</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div>Flight segments: {{ year_stats.flight_count or 0 }}</div>
|
|
<div>Train segments: {{ year_stats.train_count or 0 }}</div>
|
|
{% if year_stats.co2_kg %}
|
|
<div>CO₂: {{ format_co2(year_stats.co2_kg) }}</div>
|
|
{% for transport_type, co2_kg in year_stats.co2_by_transport_type.items() %}
|
|
<div class="ms-3">{{ transport_type | title }} CO₂: {{ format_co2(co2_kg) }}</div>
|
|
{% endfor %}
|
|
<div class="co2-chart mt-3">
|
|
<canvas id="co2-chart-{{ year }}"></canvas>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-2">
|
|
<strong>Countries:</strong> {{ countries | count }}
|
|
{% if new_countries %}({{ new_countries | count }} new){% endif %}
|
|
<div class="d-flex flex-wrap gap-1 mt-1">
|
|
{% for c in countries %}
|
|
<span class="badge text-bg-light text-dark border">
|
|
{{ c.flag }} {{ c.name }}
|
|
{% if c in new_countries %}
|
|
<span class="badge text-bg-info">new</span>
|
|
{% endif %}
|
|
</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if year_stats.airlines %}
|
|
{{ stat_list("airlines-" ~ year, "Airlines", year_stats.airlines) }}
|
|
{% endif %}
|
|
{% if year_stats.airports %}
|
|
{{ stat_list("airports-" ~ year, "Airports", year_stats.airports) }}
|
|
{% endif %}
|
|
{% if year_stats.stations %}
|
|
{{ stat_list("stations-" ~ year, "Stations", year_stats.stations) }}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
const co2ChartColors = [
|
|
"#4e79a7",
|
|
"#f28e2b",
|
|
"#e15759",
|
|
"#76b7b2",
|
|
"#59a14f",
|
|
"#edc948",
|
|
"#b07aa1",
|
|
"#ff9da7",
|
|
"#9c755f",
|
|
"#bab0ac",
|
|
];
|
|
|
|
function titleCase(value) {
|
|
return value.replace(/\b\w/g, char => char.toUpperCase());
|
|
}
|
|
|
|
function co2TooltipLabel(context) {
|
|
const label = context.label || "";
|
|
const value = context.parsed || 0;
|
|
return `${label}: ${value.toLocaleString(undefined, { maximumFractionDigits: 1 })} kg`;
|
|
}
|
|
|
|
function renderCo2Chart(id, values) {
|
|
const canvas = document.getElementById(id);
|
|
if (!canvas || !values || values.length === 0) {
|
|
return;
|
|
}
|
|
|
|
new Chart(canvas.getContext("2d"), {
|
|
type: "pie",
|
|
data: {
|
|
labels: values.map(item => titleCase(item[0])),
|
|
datasets: [{
|
|
data: values.map(item => item[1]),
|
|
backgroundColor: co2ChartColors,
|
|
}],
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: "right",
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: co2TooltipLabel,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
renderCo2Chart("overall-co2-chart", {{ co2_by_transport_type | tojson }});
|
|
{% for year, year_stats in yearly_stats | dictsort(reverse=True) %}
|
|
{% set year_co2_by_transport_type = year_stats.co2_by_transport_type | default({}) %}
|
|
renderCo2Chart(
|
|
"co2-chart-{{ year }}",
|
|
{{ year_co2_by_transport_type.items() | list | tojson }}
|
|
);
|
|
{% endfor %}
|
|
</script>
|
|
{% endblock %}
|