Skip to content

Commit

Permalink
Stats Year map
Browse files Browse the repository at this point in the history
  • Loading branch information
aceberg committed Feb 25, 2024
1 parent b624551 commit 5ca419e
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 32 deletions.
5 changes: 1 addition & 4 deletions internal/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,9 @@ type Check struct {
type Stat struct {
Name string
Group string
DWeek int
DMonth int
DTotal int
CWeek int
CMonth int
CTotal int
Checks []Check
}

// GuiData - web gui data
Expand Down
5 changes: 5 additions & 0 deletions internal/web/public/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
}
.tr-button:hover {
background-color: #0000001a;
}
@media (max-width: 1299px) {
.horiz-scroll {
overflow-x: scroll;
}
}
96 changes: 96 additions & 0 deletions internal/web/public/js/heatmap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

function lowerData(heat) {
var ldata = [];
let arrayLength = heat.length;
for (let i = 0 ; i < arrayLength; i++) {
let val = heat[i];
ldata.push({
x: val.X,
y: val.Y,
d: val.D,
v: val.V
});
}
// console.log('LDATA =', ldata);
return ldata;
};

function makeChart(heat, hcolor) {
let ldata = lowerData(heat);
var ctx = document.getElementById('matrix-chart').getContext('2d');
window.myMatrix = new Chart(ctx, {
type: 'matrix',
data: {
datasets: [{
label: 'Heatmap',
data: ldata,
backgroundColor(context) {
const value = context.dataset.data[context.dataIndex].v;
const alpha = 2 * value / 3;
return Chart.helpers.color(hcolor).alpha(alpha).rgbString();
},
borderColor(context) {
const value = context.dataset.data[context.dataIndex].v;
const alpha = 0.5;
return Chart.helpers.color('grey').alpha(alpha).rgbString();
},
borderWidth: 1,
hoverBackgroundColor: 'lightgrey',
hoverBorderColor: 'grey',
width() {
return 20;
},
height() {
return 20;
}
}]
},
options: {
plugins: {
legend: false,
tooltip: {
callbacks: {
title() {
return '';
},
label(context) {
const v = context.dataset.data[context.dataIndex];
return [v.v, v.d];
}
}
}
},
scales: {
x: {
type: 'category',
offset: true,
reverse: false,
ticks: {
display: false
},
border: {
display: false
},
grid: {
display: false
}
},
y: {
type: 'category',
labels: ['Mo', 'Tu', 'We','Th','Fr','Sa','Su'],
reverse: false,
ticks: {
stepSize: 1,
display: true
},
border: {
display: false
},
grid: {
display: false
}
},
}
}
});
};
22 changes: 22 additions & 0 deletions internal/web/public/js/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

async function getMore(key) {
let checks = [];
let url = '/smore/'+key;

heat = await (await fetch(url)).json();

document.getElementById('statsHeader').innerHTML = key;
document.getElementById('statsTable').innerHTML = '';

html = `<div class="horiz-scroll">
<div style="max-height: 150px; width: 1200px;">
<canvas id="matrix-chart" style="height: 100%; width: 100%;"></canvas>
</div>
</div>`;

document.getElementById('statsTable').insertAdjacentHTML('beforeend', html);

let color = getComputedStyle(document.body).getPropertyValue('--bs-primary');

makeChart(heat, color);
}
85 changes: 85 additions & 0 deletions internal/web/stats-more.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package web

import (
// "log"
"net/http"
"strconv"
"time"

"github.com/gin-gonic/gin"

"github.com/aceberg/ClickAHabit/internal/models"
)

// HeatMapData - data for HeatMap
type HeatMapData struct {
X string
Y string
D string
V int
}

func statsMore(c *gin.Context) {
var heatMap []HeatMapData

key := c.Param("key")
stat, ok := statsMap[key]

if ok {
heatMap = generateHeatMap(stat.Checks)
}

c.IndentedJSON(http.StatusOK, heatMap)
}

func generateHeatMap(checks []models.Check) (heatMap []HeatMapData) {
var heat HeatMapData

w := 52 // weeks to show

max := time.Now()
min := max.AddDate(0, 0, -7*w)

startDate := weekStartDate(min)
countMap := countHeat(checks)

dow := []string{"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}

for _, day := range dow {

heat.Y = day

for i := 0; i < w+1; i++ {

heat.X = strconv.Itoa(i)
heat.D = startDate.AddDate(0, 0, 7*i).Format("2006-01-02")
heat.V = countMap[heat.D]
heatMap = append(heatMap, heat)
}

startDate = startDate.AddDate(0, 0, 1)
}

return heatMap
}

func weekStartDate(date time.Time) time.Time {
offset := (int(time.Monday) - int(date.Weekday()) - 7) % 7
result := date.Add(time.Duration(offset*24) * time.Hour)
return result
}

func countHeat(checks []models.Check) map[string]int {
countMap := make(map[string]int)

for _, check := range checks {
count, exists := countMap[check.Date]
if exists {
countMap[check.Date] = count + check.Count
} else {
countMap[check.Date] = check.Count
}
}

return countMap
}
6 changes: 4 additions & 2 deletions internal/web/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ import (
"github.com/aceberg/ClickAHabit/internal/models"
)

var statsMap map[string]models.Stat

func statsHandler(c *gin.Context) {
var guiData models.GuiData
var key string

allChecks = db.Select(appConfig.DBPath)
guiData.Config = appConfig

statsMap := make(map[string]models.Stat)
statsMap = make(map[string]models.Stat)

for _, check := range allChecks {
if check.Count != 0 {
Expand All @@ -33,7 +35,7 @@ func statsHandler(c *gin.Context) {
stat.DTotal = 1
stat.CTotal = check.Count
}

stat.Checks = append(stat.Checks, check)
statsMap[key] = stat
}
}
Expand Down
6 changes: 6 additions & 0 deletions internal/web/templates/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
<link href="https://cdn.jsdelivr.net/gh/aceberg/aceberg-bootswatch-fork@v5/dist/{{ .Config.Theme }}/bootstrap.min.css" rel="stylesheet">
<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Charts -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
{{ else }} <!-- Local node_modules -->
<link rel="stylesheet" href="{{ .Config.NodePath }}/node_modules/bootstrap-icons/font/bootstrap-icons.css">
<link href="{{ .Config.NodePath }}/node_modules/bootswatch/dist/{{ .Config.Theme }}/bootstrap.min.css" rel="stylesheet">
<script src="{{ .Config.NodePath }}/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ .Config.NodePath }}/node_modules/chart.js/dist/chart.umd.js"></script>
<script src="{{ .Config.NodePath }}/node_modules/chartjs-chart-matrix/dist/chartjs-chart-matrix.min.js"></script>
{{ end }}
</head>
<link rel="stylesheet" type="text/css" href="/fs/public/css/index.css" />
<style>
.my-btn-lg {
width: {{ .Config.BtnWidth }};
Expand Down
2 changes: 1 addition & 1 deletion internal/web/templates/history.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{ define "history.html" }}
<link rel="stylesheet" type="text/css" href="/fs/public/css/index.css" />

<script src="/fs/public/js/history.js"></script>
<body>
<div class="container-lg mt-3 table-responsive">
Expand Down
1 change: 0 additions & 1 deletion internal/web/templates/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{{ define "index.html" }}
</head>
<script src="/fs/public/js/index.js"></script>
<link rel="stylesheet" type="text/css" href="/fs/public/css/index.css" />
<body>
<div class="container-lg">
<br>
Expand Down
55 changes: 31 additions & 24 deletions internal/web/templates/stats.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
{{ define "stats.html" }}

<script src="/fs/public/js/stats.js"></script>
<script src="/fs/public/js/heatmap.js"></script>
<body>
<div class="container-lg mt-3">
<div class="card border-primary">
<div class="card-header">
<h5>Stats</h5>
</div>
<div class="card-body table-responsive">
<table class="table table-striped table-hover">
<thead>
<th>Group</th>
<th>Name</th>
<th>Days Total</th>
<th>Count Total</th>
</thead>
<tbody>
{{ range .Stats }}
<tr>
<td>{{ .Group }}</td>
<td>{{ .Name }}</td>
<td>{{ .DTotal }}</td>
<td>{{ .CTotal }}</td>
</tr>
{{ end }}
</tbody>
</table>
<div class="row">
<div class="col-md">
<div class="card border-primary">
<div class="card-header">
<h5 id="statsHeader">Stats</h5>
</div>
<div class="card-body table-responsive" id="statsTable">
<table class="table table-striped table-hover">
<thead>
<th>Group</th>
<th>Name</th>
<th>Days Total</th>
<th>Count Total</th>
<th></th>
</thead>
<tbody>
{{ range $key, $value := .Stats }}
<tr>
<td>{{ .Group }}</td>
<td>{{ .Name }}</td>
<td>{{ .DTotal }}</td>
<td>{{ .CTotal }}</td>
<td><a href="#" onclick="getMore({{ $key }})">Year map</a></td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions internal/web/webgui.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func Gui(dirPath, nodePath string) {
router.GET("/planedit/:id", editHandler) // plan-edit.go
router.GET("/plandel/:id", planDel) // plan.go
router.GET("/stats/", statsHandler) // stats.go
router.GET("/smore/:key", statsMore) // stats-more.go
router.GET("/update/:date", updatePlan) // update.go

router.POST("/config/", saveConfigHandler) // config.go
Expand Down

0 comments on commit 5ca419e

Please sign in to comment.