132 lines
4.0 KiB
Plaintext
132 lines
4.0 KiB
Plaintext
{% import "includes/macros" as macros %}
|
|
|
|
{% extends "base" %}
|
|
|
|
{% block content %}
|
|
|
|
|
|
<div class="max-w-screen-lg w-full">
|
|
<h1 class="h1">Statistik</h1>
|
|
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
|
|
<label for="name" class="sr-only">Suche</label>
|
|
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Namen...">
|
|
</div>
|
|
|
|
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
|
|
|
|
<div class="border-r border-l">
|
|
{% set_global km = 0 %}
|
|
{% set_global index = 1 %}
|
|
{% for s in stat %}
|
|
<div class="border-t {% if loop.last %} border-b {% endif %} bg-white flex justify-between items-center px-3 py-1" data-filterable="true" data-filter="{{ s.name }}">
|
|
<span class="text-sm text-gray-600 w-10">
|
|
{% if km != s.rowed_km %}
|
|
{{loop.index}}
|
|
{% set_global index = loop.index %}
|
|
{% else %}
|
|
{{ index }}
|
|
{% endif %}
|
|
</span>
|
|
<span class="grow">{{s.name}}</span>
|
|
<span>{{s.rowed_km}} km</span>
|
|
|
|
{% set_global km = s.rowed_km %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
<div id="container" class="w-full"></div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
|
|
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
|
|
|
|
|
|
// Declare the chart dimensions and margins.
|
|
const width = 928;
|
|
const height = 500;
|
|
const marginTop = 20;
|
|
const marginRight = 30;
|
|
const marginBottom = 30;
|
|
const marginLeft = 40;
|
|
|
|
// Declare the x (horizontal position) scale.
|
|
const parseTime = d3.timeParse("%d-%b-%y");
|
|
|
|
const x = d3.scaleTime()
|
|
.rangeRound([0, width]);
|
|
|
|
const y = d3.scaleLinear()
|
|
.rangeRound([height, 0]);
|
|
|
|
// Declare the line generator.
|
|
const line = d3.line()
|
|
.x(d => x(d.date))
|
|
.y(d => y(d.km));
|
|
|
|
// Create the SVG container.
|
|
const svg = d3.create("svg")
|
|
.attr("width", width)
|
|
.attr("height", height)
|
|
.attr("viewBox", [0, 0, width, height])
|
|
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");
|
|
|
|
// Add the x-axis.
|
|
svg.append("g")
|
|
.attr("transform", `translate(0,${height - marginBottom})`)
|
|
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
|
|
|
|
// Add the y-axis, remove the domain line, add grid lines and a label.
|
|
svg.append("g")
|
|
.attr("transform", `translate(${marginLeft},0)`)
|
|
.call(d3.axisLeft(y).ticks(height / 40))
|
|
.call(g => g.select(".domain").remove())
|
|
.call(g => g.selectAll(".tick line").clone()
|
|
.attr("x2", width - marginLeft - marginRight)
|
|
.attr("stroke-opacity", 0.1))
|
|
.call(g => g.append("text")
|
|
.attr("x", -marginLeft)
|
|
.attr("y", 10)
|
|
.attr("fill", "currentColor")
|
|
.attr("text-anchor", "start")
|
|
.text("↑ Daily km ($)"));
|
|
|
|
d3.csv("../public/csv/stats.csv", function(d) {
|
|
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.km }
|
|
|
|
}, function(error, data) {
|
|
if (error) throw error;
|
|
|
|
x.domain(d3.extent(data, function(d) { return d.date; }));
|
|
y.domain(d3.extent(data, function(d) { return d.km; }));
|
|
|
|
g.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x))
|
|
.select(".domain")
|
|
.remove();
|
|
|
|
g.append("g")
|
|
.call(d3.axisLeft(y))
|
|
.append("text")
|
|
.attr("fill", "#000")
|
|
.attr("transform", "rotate(-90)")
|
|
.attr("y", 6)
|
|
.attr("dy", "0.71em")
|
|
.attr("text-anchor", "end")
|
|
.text("Price ($)");
|
|
|
|
g.append("path")
|
|
.datum(data)
|
|
.attr("fill", "none")
|
|
.attr("stroke", "steelblue")
|
|
.attr("stroke-linejoin", "round")
|
|
.attr("stroke-linecap", "round")
|
|
.attr("stroke-width", 1.5)
|
|
.attr("d", line);
|
|
});
|
|
|
|
container.append(svg.node());
|
|
</script>
|
|
{% endblock content%}
|