Example #1
0
func view(user types.UserSettings, filter Filter) (p Page) {

	//get ff data - would be good not to get this on every activity call ********************
	var ffData []types.Ff_data_point
	if filter.ShowTss {
		ffData = ff(user, filter)
	}

	//power curve
	var cpData []Cp3
	var legends Cp3Legend
	if filter.ShowMmp {
		cpData, legends = powercurve(user, filter)
	}

	//Heart vs Power
	var hvpData []Hvp
	if filter.ShowHvp {
		hvpData = hvp(user, filter)
	}
	var hvp_label string
	if filter.HvpFrom == 0 && filter.HvpTo == 0 {
		hvp_label = "All ride durations"
	} else {
		hvp_label = "Rides with durations between <b>" + strconv.Itoa(filter.HvpFrom) + "</b> and <b>" + strconv.Itoa(filter.HvpTo) + "</b> minutes"
	}

	//Tss vs Duration
	var tvdData []Tvd
	var tvdLegend string
	if filter.ShowDur {
		tvdData, tvdLegend = tvd(user, filter)
	}

	//these two are well merged as a function so only don't process if both not required. else just hide the appropriate graphs

	var hbzData []Hbz
	var pbzData []Pbz
	if !filter.ShowHbz && !filter.ShowPbz {
		//these two are well merged as a function so only don't process if both not required. else just hide the appropriate graphs
	} else {
		hbzData, pbzData = hpbz(user, filter)
	}
	var zoneLabels types.ZoneLabels
	zoneLabels.PowerZ1 = int(0.55 * float64(user.Ftp))
	zoneLabels.PowerZ2 = int(0.74 * float64(user.Ftp))
	zoneLabels.PowerZ3 = int(0.89 * float64(user.Ftp))
	zoneLabels.PowerZ4 = int(1.04 * float64(user.Ftp))
	zoneLabels.PowerZ5 = int(1.2 * float64(user.Ftp))
	zoneLabels.HeartZ1 = int(0.81 * float64(user.Thr))
	zoneLabels.HeartZ2 = int(0.89 * float64(user.Thr))
	zoneLabels.HeartZ3 = int(0.93 * float64(user.Thr))
	zoneLabels.HeartZ4 = int(0.99 * float64(user.Thr))
	zoneLabels.HeartZ5a = int(1.02 * float64(user.Thr))
	zoneLabels.HeartZ5b = int(1.06 * float64(user.Thr))

	//cp data - doesn't actually need to be reversed (corrected), but just wanted to for future flexibility
	cpDataRev := make([]Cp3, 0)
	for i := len(cpData) - 1; i >= 0; i-- {
		cpDataRev = append(cpDataRev, cpData[i])
	}
	selectHTML := template.HTML("")

	for _, userval := range user.StandardRides { //for each of the user's standard rides
		selected := ""
		for _, filterval := range filter.StandardRides { //test for a filter match
			if userval.Id == filterval {
				selected = "selected"
			}
		}
		selectHTML += template.HTML("<option " + selected + " value=" + strconv.Itoa(userval.Id) + ">" + userval.Label + "</option>")
	}

	p = Page{
		FfData:            ffData,
		CpData:            cpDataRev,
		HvpData:           hvpData,
		TvdData:           tvdData,
		TvdLegend:         tvdLegend,
		CpLegend1:         legends.Series1,
		CpLegend2:         legends.Series2,
		CpLegend3:         legends.Series3,
		HvpLabel:          hvp_label,
		HbzData:           hbzData,
		PbzData:           pbzData,
		Settings:          user,
		Filter:            filter,
		ZoneLabels:        zoneLabels,
		StandardRidesHTML: selectHTML,
	}
	return
}
Example #2
0
//get the week's activities
func dashboard(user types.UserSettings) (types.Tvd, types.Zones, types.ZoneLabels) {
	user_id := user.Id
	tvd_data_points := make([]types.Tvd_data_point, 0)
	tvd_data := make([]types.Tvd, 0)

	var user_data types.Metrics
	var activity_id string
	var end_summary_json []byte
	var activity_start time.Time
	var heart_json []byte
	var power_json []byte
	var cur_ftp int
	var cur_thr int
	var power_series []int
	var heart_series []int
	var has_power, has_heart bool

	var zoneData types.Zones

	cluster := gocql.NewCluster(config.DbHost)
	cluster.Keyspace = "joulepersecond"
	cluster.Consistency = gocql.Quorum
	session, _ := cluster.CreateSession()
	defer session.Close()

	//get all of the user's data (at least all for now) TODO limit these queries by date if poss. Done!
	timeNow := time.Now()

	//we can use TimeOffset to test from other dates
	timeNow = timeNow.AddDate(0, 0, user.TimeOffset)

	//timeTruncated is a time at the beginning of the day
	timeTruncated := timeNow.Truncate(time.Hour * 24)

	//we will use timeThen to refer to the beginning of the current week
	var timeThen time.Time
	dayOfWeek := int(timeTruncated.Weekday())
	if int(timeTruncated.Weekday()) != 0 { //if not equal to Sunday...
		timeThen = timeTruncated.AddDate(0, 0, -(dayOfWeek - 1)) //fetch records for the week so far (second -1 to start from Monday)
	} else {
		timeThen = timeTruncated.AddDate(0, 0, -6) //if today is Sunday, query back to Monday
	}

	iter := session.Query(`SELECT activity_id, activity_start, end_summary_json FROM joulepersecond.user_activity WHERE user_id = ? AND activity_start <=? AND activity_start >= ? `, user_id, timeNow, timeThen).Iter()
	for iter.Scan(&activity_id, &activity_start, &end_summary_json) {
		var tvd_data_point types.Tvd_data_point
		json.Unmarshal(end_summary_json, &user_data)

		tvd_data_point.Date = user_data.StartTime
		tvd_data_point.Dur = user_data.Dur
		if user_data.Utss > 0 {
			tvd_data_point.Tss = user_data.Utss
		} else if user_data.Tss > 0 {
			tvd_data_point.Tss = user_data.Tss
		} else if user_data.Etss > 0 {
			tvd_data_point.Tss = user_data.Etss
		} else {
			tvd_data_point.Tss = 0
		}
		tvd_data_points = append(tvd_data_points, tvd_data_point)

		//for each activity, get the exended data
		iter := session.Query(`SELECT power_json, heart_json, end_summary_json, has_power, has_heart, cur_ftp, cur_thr FROM joulepersecond.proc_activity WHERE activity_id = ? `, activity_id).Iter()
		for iter.Scan(&power_json, &heart_json, &end_summary_json, &has_power, &has_heart, &cur_ftp, &cur_thr) {
			json.Unmarshal(end_summary_json, &user_data)
			json.Unmarshal(power_json, &power_series)
			json.Unmarshal(heart_json, &heart_series)

			var samples int

			if has_power {
				samples = len(power_series)
				has_power = true
			}
			if has_heart {
				samples = len(heart_series)
				has_heart = true
			}
			if !has_heart && !has_power {
				break
			}

			if has_power {
				zoneData.HasPower = true
				var sum int
				var average float64
				for i := user.SampleSize; i < samples; i++ {
					//reset total
					sum = 0
					//get thirty second rolling slice
					rollingPowerSlice := power_series[i-user.SampleSize : i]
					for _, val := range rollingPowerSlice {
						//sum the sliding slice values
						sum += val
					}
					average = float64(sum / user.SampleSize)

					if average < 0.55*float64(cur_ftp) {
						zoneData.Z1++
					} else if average > 0.55*float64(cur_ftp) && average <= 0.74*float64(cur_ftp) {
						zoneData.Z2++
					} else if average > 0.74*float64(cur_ftp) && average <= 0.89*float64(cur_ftp) {
						zoneData.Z3++
					} else if average > 0.89*float64(cur_ftp) && average <= 1.04*float64(cur_ftp) {
						zoneData.Z4++
					} else if average > 1.04*float64(cur_ftp) && average <= 1.2*float64(cur_ftp) {
						zoneData.Z5++
					} else if average > 1.2*float64(cur_ftp) {
						zoneData.Z6++
					}
				}
			}

			//loop through each sample and post the value into the correct pidgeon hole
			if has_heart {
				zoneData.HasHeart = true
				for i := 0; i < samples; i++ {

					if float64(heart_series[i]) < 0.81*float64(cur_thr) {
						zoneData.HR1++
					} else if float64(heart_series[i]) > 0.81*float64(cur_thr) && float64(heart_series[i]) <= 0.89*float64(cur_thr) {
						zoneData.HR2++
					} else if float64(heart_series[i]) > 0.89*float64(cur_thr) && float64(heart_series[i]) <= 0.93*float64(cur_thr) {
						zoneData.HR3++
					} else if float64(heart_series[i]) > 0.93*float64(cur_thr) && float64(heart_series[i]) <= 0.99*float64(cur_thr) {
						zoneData.HR4++
					} else if float64(heart_series[i]) > 0.99*float64(cur_thr) && float64(heart_series[i]) <= 1.02*float64(cur_thr) {
						zoneData.HR5a++
					} else if float64(heart_series[i]) > 1.02*float64(cur_thr) && float64(heart_series[i]) <= 1.06*float64(cur_thr) {
						zoneData.HR5b++
					} else if float64(heart_series[i]) > 1.06*float64(cur_thr) {
						zoneData.HR5c++
					}
				}
			}
		}
	}

	//we now have all the data... Now sort it
	sumTss := 0
	var sumDur time.Duration
	var summedWeeklyTvd types.Tvd

	//loop through each retrieved activity
	for i := 0; i < len(tvd_data_points); i++ {
		tvd_data = append(tvd_data, summedWeeklyTvd)

		//sum the values
		sumTss += tvd_data_points[i].Tss
		sumDur += tvd_data_points[i].Dur
	}
	summedWeeklyTvd.TotalTss = sumTss
	summedWeeklyTvd.TotalDur = utility.Round(sumDur.Hours(), .5, 2)

	var zoneLabels types.ZoneLabels
	zoneLabels.PowerZ1 = int(0.55 * float64(user.Ftp))
	zoneLabels.PowerZ2 = int(0.74 * float64(user.Ftp))
	zoneLabels.PowerZ3 = int(0.89 * float64(user.Ftp))
	zoneLabels.PowerZ4 = int(1.04 * float64(user.Ftp))
	zoneLabels.PowerZ5 = int(1.2 * float64(user.Ftp))
	zoneLabels.HeartZ1 = int(0.81 * float64(user.Thr))
	zoneLabels.HeartZ2 = int(0.89 * float64(user.Thr))
	zoneLabels.HeartZ3 = int(0.93 * float64(user.Thr))
	zoneLabels.HeartZ4 = int(0.99 * float64(user.Thr))
	zoneLabels.HeartZ5a = int(1.02 * float64(user.Thr))
	zoneLabels.HeartZ5b = int(1.06 * float64(user.Thr))

	//get the power and heartrate zone data
	return summedWeeklyTvd, zoneData, zoneLabels
}