func (s *Server) HandleDashboard(w http.ResponseWriter, r *http.Request) { ctx := NewContext(r, w) user := ctx.User() if user == nil { s.redirectToSignIn(w, r) return } logs, err := s.db.RecentUserLogs(user, dashboardRecentLogsCount) if err != nil { panic(err) } data := new(dashboardData) for _, log := range logs { data.Logs = append(data.Logs, dashboardLog{ ID: log.ID, Name: log.Name, Date: log.Start.Format(logTimeFormat), Duration: utils.Duration(log.Duration).String(), Distance: utils.Distance(log.Distance).String(), Tags: log.Tags, }) } ctx.SetTitle("Dashboard") ctx.Breadcrumb().Add("Dashboard", "", true) ctx.SetActiveTab("dashboard") ctx.SetData(data) s.render(w, r, "dashboard") }
func (s *Server) HandleGetLogs(w http.ResponseWriter, r *http.Request) { ctx := NewContext(r, w) user := ctx.User() if user == nil { s.redirectToSignIn(w, r) return } years, err := s.db.UserLogYears(user) if err != nil { panic(err) } year := 0 explicitYear := false if s := r.FormValue("year"); s != "" { if y, err := strconv.Atoi(s); err == nil { year = y explicitYear = true } } if year == 0 && len(years) > 0 { year = years[len(years)-1] } logs, err := s.db.UserLogsByYear(user, year) if err != nil { panic(err) } var ( data logsData group *logDataGroup duration uint distance uint month time.Month ) for _, log := range logs { if month != log.Start.Month() { if group != nil { group.Duration = utils.Duration(duration).String() group.Distance = utils.Distance(distance).String() } duration = 0 distance = 0 month = log.Start.Month() group = &logDataGroup{ Title: fmt.Sprintf("%s %d", month, year), } data.Groups = append(data.Groups, group) } group.Logs = append(group.Logs, logsDataLog{ ID: log.ID, Name: log.Name, Start: log.Start.Format(logTimeFormat), Duration: utils.Duration(log.Duration).String(), Distance: utils.Distance(log.Distance).String(), Tags: log.Tags, }) distance += log.Distance duration += log.Duration } if group != nil { group.Duration = utils.Duration(duration).String() group.Distance = utils.Distance(distance).String() } for _, y := range years { data.Years = append(data.Years, logsDataYear{ Year: y, Active: y == year, }) } if explicitYear { ctx.SetTitle(fmt.Sprintf("Logs %d", year)) ctx.Breadcrumb().Add("Logs", "/logs", false) ctx.Breadcrumb().Add(strconv.Itoa(year), "", true) } else { ctx.SetTitle("Logs") ctx.Breadcrumb().Add("Logs", "", true) } ctx.SetActiveTab("logs") ctx.SetData(data) s.render(w, r, "logs") }
func (s *Server) HandleGetLog(w http.ResponseWriter, r *http.Request) { ctx := NewContext(r, w) user := ctx.User() if user == nil { s.redirectToSignIn(w, r) return } id, err := strconv.Atoi(ctx.Params().ByName("id")) if err != nil { http.NotFound(w, r) return } log, err := s.db.UserLogByID(user, id) if err != nil { panic(err) } if log == nil { http.NotFound(w, r) return } data := logData{ Log: logDataLog{ ID: log.ID, Name: log.Name, Start: log.Start.Format(logTimeFormat), End: log.End.Format(logTimeFormat), Duration: utils.Duration(log.Duration).String(), Distance: utils.Distance(log.Distance).String(), Speed: utils.Speed(log.Speed()).String(), Pace: utils.Speed(log.Speed()).Pace().String(), Tracks: make([][]logDataPoint, 0, len(log.Tracks)), Tags: log.Tags, }, } if data.Log.Tags == nil { data.Log.Tags = make([]string, 0, 0) } var cumDistance, ascent, descent float64 performReduce := r.FormValue("reduce") != "no" for _, track := range log.Tracks { points := track.Points if performReduce { rdpPoints := make([]rdp.Point, 0, len(track.Points)) for _, point := range track.Points { λ, φ := geo.ToRad(point.Longitude), geo.ToRad(point.Latitude) x, y := geo.EquirectangularProjection(λ, φ, 0) rdpPoints = append(rdpPoints, rdp.Point{ X: x, Y: y, Data: point, }) } const epsilon = 0.0000001 // ≈ 1m reducedPoints := rdp.Reduce(rdpPoints, epsilon) points = make([]*models.Point, 0, len(reducedPoints)) for _, rp := range reducedPoints { points = append(points, rp.Data.(*models.Point)) } } var ps []logDataPoint for i, point := range points { p := logDataPoint{ Lat: point.Latitude, Lon: point.Longitude, Ele: point.Elevation, HR: point.Heartrate, } if i > 0 { lastPoint := points[i-1] cumDistance += point.DistanceTo(lastPoint) p.CumulatedDistance = cumDistance p.Speed = point.SpeedTo(lastPoint) dEle := point.Elevation - lastPoint.Elevation if dEle >= 0 { ascent += dEle } else { descent += -dEle } } else if len(points) > 1 { nextPoint := points[i+1] p.CumulatedDistance = cumDistance p.Speed = nextPoint.SpeedTo(point) } ps = append(ps, p) } data.Log.Tracks = append(data.Log.Tracks, ps) } if ascent != 0 || descent != 0 { data.Log.Ascent = fmt.Sprintf("%d m", int(ascent)) data.Log.Descent = fmt.Sprintf("%d m", int(descent)) } hrSummary := heartrate.SummaryForLog(log) if len(hrSummary.Rates) > 0 { data.Log.HR = strconv.Itoa(hrSummary.Average) perc := func(zone heartrate.Zone) float64 { return float64(hrSummary.Zones[zone]) / float64(len(hrSummary.Rates)) * 100.0 } data.Log.HRZones.Red = perc(heartrate.ZoneRed) data.Log.HRZones.Anaerobic = perc(heartrate.ZoneAnaerobic) data.Log.HRZones.Aerobic = perc(heartrate.ZoneAerobic) data.Log.HRZones.FatBurning = perc(heartrate.ZoneFatBurning) data.Log.HRZones.Easy = perc(heartrate.ZoneEasy) data.Log.HRZones.None = perc(heartrate.ZoneNone) } ctx.SetTitle(log.Name) ctx.Breadcrumb().Add("Logs", "/logs", false) ctx.Breadcrumb().Add(log.Name, "", true) ctx.SetActiveTab("logs") ctx.SetData(data) s.render(w, r, "log") }