headmap
This commit is contained in:
parent
adf64dc6ff
commit
538af45cf6
7 changed files with 175 additions and 1 deletions
10
assets/colorscales/green-blue-9.csv
Normal file
10
assets/colorscales/green-blue-9.csv
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
R,G,B
|
||||||
|
247,252,240
|
||||||
|
224,243,219
|
||||||
|
204,235,197
|
||||||
|
168,221,181
|
||||||
|
123,204,196
|
||||||
|
78,179,211
|
||||||
|
43,140,190
|
||||||
|
8,104,172
|
||||||
|
8,64,129
|
|
BIN
assets/fonts/Sunflower-Medium.ttf
Normal file
BIN
assets/fonts/Sunflower-Medium.ttf
Normal file
Binary file not shown.
116
daily-headmap.go
Normal file
116
daily-headmap.go
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/nikolaydubina/calendarheatmap/charts"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/image/font"
|
||||||
|
"golang.org/x/image/font/opentype"
|
||||||
|
"image/color"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/nikolaydubina/calendarheatmap/charts"
|
||||||
|
_ "golang.org/x/image/font"
|
||||||
|
_ "golang.org/x/image/font/opentype"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed assets/fonts/Sunflower-Medium.ttf
|
||||||
|
var defaultFontFaceBytes []byte
|
||||||
|
|
||||||
|
//go:embed assets/colorscales/green-blue-9.csv
|
||||||
|
var defaultColorScaleBytes []byte
|
||||||
|
|
||||||
|
func dailyHabitImage(cCtx *cli.Context) error {
|
||||||
|
folder := DATAPATH
|
||||||
|
files, err := os.ReadDir(folder)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
counts := make(map[string]int)
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if f.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
day := strings.TrimSuffix(f.Name(), ".json")
|
||||||
|
|
||||||
|
content, err := os.ReadFile(fmt.Sprintf("%v/%v", folder, f.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []archivCard
|
||||||
|
err = json.Unmarshal(content, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inToDo := 0
|
||||||
|
all := 0
|
||||||
|
|
||||||
|
for _, archivCard := range data {
|
||||||
|
if archivCard.List == "ToDo" {
|
||||||
|
inToDo++
|
||||||
|
}
|
||||||
|
all++
|
||||||
|
}
|
||||||
|
|
||||||
|
var percent float64
|
||||||
|
percent = float64(all-inToDo) / float64(all) * 100
|
||||||
|
|
||||||
|
counts[day] = int(percent)
|
||||||
|
}
|
||||||
|
|
||||||
|
colorscale, err := charts.NewBasicColorscaleFromCSV(bytes.NewBuffer(defaultColorScaleBytes))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fontFace, err := charts.LoadFontFace(defaultFontFaceBytes, opentype.FaceOptions{
|
||||||
|
Size: 26,
|
||||||
|
DPI: 280,
|
||||||
|
Hinting: font.HintingNone,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := charts.HeatmapConfig{
|
||||||
|
Counts: counts,
|
||||||
|
ColorScale: colorscale,
|
||||||
|
DrawMonthSeparator: false,
|
||||||
|
DrawLabels: true,
|
||||||
|
Margin: 30,
|
||||||
|
BoxSize: 150,
|
||||||
|
MonthSeparatorWidth: 5,
|
||||||
|
MonthLabelYOffset: 50,
|
||||||
|
TextWidthLeft: 300,
|
||||||
|
TextHeightTop: 200,
|
||||||
|
TextColor: color.RGBA{100, 100, 100, 255},
|
||||||
|
BorderColor: color.RGBA{200, 200, 200, 255},
|
||||||
|
Locale: "en_US",
|
||||||
|
Format: "png",
|
||||||
|
FontFace: fontFace,
|
||||||
|
ShowWeekdays: map[time.Weekday]bool{
|
||||||
|
time.Monday: true,
|
||||||
|
time.Wednesday: true,
|
||||||
|
time.Friday: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile("headmap.png", os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
|
defer f.Close()
|
||||||
|
err = charts.WriteHeatmap(conf, f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
3
go.mod
3
go.mod
|
@ -4,8 +4,10 @@ go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adlio/trello v1.10.0
|
github.com/adlio/trello v1.10.0
|
||||||
|
github.com/nikolaydubina/calendarheatmap v1.7.0
|
||||||
github.com/rs/zerolog v1.32.0
|
github.com/rs/zerolog v1.32.0
|
||||||
github.com/urfave/cli/v2 v2.27.1
|
github.com/urfave/cli/v2 v2.27.1
|
||||||
|
golang.org/x/image v0.15.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -16,5 +18,6 @@ require (
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
golang.org/x/sys v0.12.0 // indirect
|
golang.org/x/sys v0.12.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -9,6 +9,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/nikolaydubina/calendarheatmap v1.7.0 h1:NRzVfydhxRYMzcj3SYAy31y+yi1DCCzcD0YxDy57Nco=
|
||||||
|
github.com/nikolaydubina/calendarheatmap v1.7.0/go.mod h1:PIfHapXuizDttmpJsATJA1snrjibFQdIAbmm5Xh3SrQ=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
@ -21,9 +23,15 @@ github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||||
|
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
5
main.go
5
main.go
|
@ -43,6 +43,11 @@ func main() {
|
||||||
Usage: "Assign all cards without member to current users",
|
Usage: "Assign all cards without member to current users",
|
||||||
Action: unassignCards,
|
Action: unassignCards,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "daily-habit-image",
|
||||||
|
Usage: "Daily habit image",
|
||||||
|
Action: dailyHabitImage,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/adlio/trello"
|
"github.com/adlio/trello"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type archivCard struct {
|
||||||
|
Name string
|
||||||
|
List string
|
||||||
|
}
|
||||||
|
|
||||||
|
const DATAPATH = "/home/pi/dailyhabbit"
|
||||||
|
|
||||||
func resetDailyTasks(cCtx *cli.Context) error {
|
func resetDailyTasks(cCtx *cli.Context) error {
|
||||||
client := getTrelloClient()
|
client := getTrelloClient()
|
||||||
board, err := client.GetBoard(trelloBordID, trello.Defaults())
|
board, err := client.GetBoard(trelloBordID, trello.Defaults())
|
||||||
|
@ -48,10 +58,12 @@ func resetDailyTasks(cCtx *cli.Context) error {
|
||||||
|
|
||||||
var todoList *trello.List
|
var todoList *trello.List
|
||||||
|
|
||||||
|
listnames := make(map[string]string)
|
||||||
|
|
||||||
for _, list := range lists {
|
for _, list := range lists {
|
||||||
|
listnames[list.ID] = list.Name
|
||||||
if list.Name == "ToDo" {
|
if list.Name == "ToDo" {
|
||||||
todoList = list
|
todoList = list
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +79,8 @@ func resetDailyTasks(cCtx *cli.Context) error {
|
||||||
|
|
||||||
log.Debug().Int("number of cards", len(cards)).Msg("Get Cards")
|
log.Debug().Int("number of cards", len(cards)).Msg("Get Cards")
|
||||||
|
|
||||||
|
var dailyCards []archivCard
|
||||||
|
|
||||||
for _, card := range cards {
|
for _, card := range cards {
|
||||||
log.Debug().Str("name", card.Name).Msg("Check")
|
log.Debug().Str("name", card.Name).Msg("Check")
|
||||||
foundLabel := false
|
foundLabel := false
|
||||||
|
@ -83,11 +97,29 @@ func resetDailyTasks(cCtx *cli.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cd := archivCard{
|
||||||
|
Name: card.Name,
|
||||||
|
List: listnames[card.IDList],
|
||||||
|
}
|
||||||
|
dailyCards = append(dailyCards, cd)
|
||||||
|
|
||||||
err = card.MoveToList(todoList.ID, trello.Defaults())
|
err = card.MoveToList(todoList.ID, trello.Defaults())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cant move card to todo list: %w", err)
|
return fmt.Errorf("cant move card to todo list: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(dailyCards)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cant marshal data for archiov: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(fmt.Sprintf("%v/%v.json", DATAPATH, time.Now().Format(time.DateOnly)), data, 0744)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cant wrote daily habbit file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(data))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue