mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-07 23:13:57 -05:00
Merge branch 'pr/442' into pre-release
This commit is contained in:
@@ -369,7 +369,7 @@ def transform_activity_streams_hr(activity_stream, activity, db):
|
||||
activity: The activity object associated with the stream, used to retrieve the user ID.
|
||||
db: The database session or connection used to fetch user details.
|
||||
Returns:
|
||||
The activity stream object with an added 'hr_zone_percentages' attribute, which contains the percentage of time spent in each heart rate zone and their respective HR boundaries. If waypoints or user details are missing, returns the original activity stream unchanged.
|
||||
The activity stream object with an added 'hr_zone_percentages' attribute, which contains the percentage of time spent in each heart rate zone and their respective HR boundaries. If waypoi[...]
|
||||
Notes:
|
||||
- Heart rate zones are calculated using the formula: max_heart_rate = 220 - age.
|
||||
- The function expects waypoints to be a list of dicts with an "hr" key.
|
||||
@@ -423,7 +423,25 @@ def transform_activity_streams_hr(activity_stream, activity, db):
|
||||
np.sum((hr_values >= zone_3) & (hr_values < zone_4)),
|
||||
np.sum(hr_values >= zone_4),
|
||||
]
|
||||
zone_percentages = [round((count / total) * 100, 2) for count in zone_counts]
|
||||
zone_percentages = [
|
||||
round((count / total) * 100, 2) for count in zone_counts
|
||||
]
|
||||
|
||||
# Calculate time in seconds for each zone using the percentage
|
||||
# of total_timer_time
|
||||
has_timer_time = (
|
||||
hasattr(activity, "total_timer_time")
|
||||
and activity.total_timer_time
|
||||
)
|
||||
if has_timer_time:
|
||||
total_time_seconds = activity.total_timer_time
|
||||
zone_time_seconds = [
|
||||
int((percent / 100) * total_time_seconds)
|
||||
for percent in zone_percentages
|
||||
]
|
||||
else:
|
||||
# Fallback: no time calculation possible
|
||||
zone_time_seconds = [0, 0, 0, 0, 0]
|
||||
|
||||
# Calculate zone HR boundaries for display
|
||||
zone_hr = {
|
||||
@@ -434,11 +452,31 @@ def transform_activity_streams_hr(activity_stream, activity, db):
|
||||
"zone_5": f">= {int(zone_4)}",
|
||||
}
|
||||
activity_stream.hr_zone_percentages = {
|
||||
"zone_1": {"percent": zone_percentages[0], "hr": zone_hr["zone_1"]},
|
||||
"zone_2": {"percent": zone_percentages[1], "hr": zone_hr["zone_2"]},
|
||||
"zone_3": {"percent": zone_percentages[2], "hr": zone_hr["zone_3"]},
|
||||
"zone_4": {"percent": zone_percentages[3], "hr": zone_hr["zone_4"]},
|
||||
"zone_5": {"percent": zone_percentages[4], "hr": zone_hr["zone_5"]},
|
||||
"zone_1": {
|
||||
"percent": zone_percentages[0],
|
||||
"hr": zone_hr["zone_1"],
|
||||
"time_seconds": zone_time_seconds[0],
|
||||
},
|
||||
"zone_2": {
|
||||
"percent": zone_percentages[1],
|
||||
"hr": zone_hr["zone_2"],
|
||||
"time_seconds": zone_time_seconds[1],
|
||||
},
|
||||
"zone_3": {
|
||||
"percent": zone_percentages[2],
|
||||
"hr": zone_hr["zone_3"],
|
||||
"time_seconds": zone_time_seconds[2],
|
||||
},
|
||||
"zone_4": {
|
||||
"percent": zone_percentages[3],
|
||||
"hr": zone_hr["zone_4"],
|
||||
"time_seconds": zone_time_seconds[3],
|
||||
},
|
||||
"zone_5": {
|
||||
"percent": zone_percentages[4],
|
||||
"hr": zone_hr["zone_5"],
|
||||
"time_seconds": zone_time_seconds[4],
|
||||
},
|
||||
}
|
||||
|
||||
return activity_stream
|
||||
|
||||
@@ -138,10 +138,13 @@
|
||||
</div>
|
||||
<BarChartComponent
|
||||
v-if="Object.values(hrZones).length > 0 && hrPresent"
|
||||
:labels="getHrBarChartData(hrZones, t).labels"
|
||||
:values="getHrBarChartData(hrZones, t).values"
|
||||
:barColors="getHrBarChartData(hrZones, t).barColors"
|
||||
:datalabelsFormatter="(value) => `${Math.round(value)}%`"
|
||||
:labels="hrChartData.labels"
|
||||
:values="hrChartData.values"
|
||||
:barColors="hrChartData.barColors"
|
||||
:timeSeconds="hrChartData.timeSeconds"
|
||||
:datalabelsFormatter="
|
||||
(value, context) => formatHrZoneLabel(value, hrChartData.timeSeconds[context.dataIndex])
|
||||
"
|
||||
:title="$t('activityMandAbovePillsComponent.labelHRZones')"
|
||||
/>
|
||||
<hr />
|
||||
@@ -346,6 +349,9 @@ const pacePresent = ref(false)
|
||||
const formattedPace = ref(null)
|
||||
const hrZones = ref({})
|
||||
|
||||
// Computed properties
|
||||
const hrChartData = computed(() => getHrBarChartData(hrZones.value, t))
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
if (props.activityActivityStreams && props.activityActivityStreams.length > 0) {
|
||||
|
||||
@@ -120,10 +120,13 @@
|
||||
/>
|
||||
<BarChartComponent
|
||||
v-if="Object.values(hrZones).length > 0 && graphSelection === 'hrZones' && hrPresent"
|
||||
:labels="getHrBarChartData(hrZones, t).labels"
|
||||
:values="getHrBarChartData(hrZones, t).values"
|
||||
:barColors="getHrBarChartData(hrZones, t).barColors"
|
||||
:datalabelsFormatter="(value) => `${Math.round(value)}%`"
|
||||
:labels="hrChartData.labels"
|
||||
:values="hrChartData.values"
|
||||
:barColors="hrChartData.barColors"
|
||||
:timeSeconds="hrChartData.timeSeconds"
|
||||
:datalabelsFormatter="
|
||||
(value, context) => formatHrZoneLabel(value, hrChartData.timeSeconds[context.dataIndex])
|
||||
"
|
||||
:title="$t('activityMandAbovePillsComponent.labelHRZones')"
|
||||
/>
|
||||
</div>
|
||||
@@ -167,7 +170,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
// Importing the components
|
||||
import ActivityLapsComponent from '@/components/Activities/ActivityLapsComponent.vue'
|
||||
@@ -186,7 +189,7 @@ import {
|
||||
// Import Notivue push
|
||||
import { push } from 'notivue'
|
||||
// Import the utils
|
||||
import { getHrBarChartData } from '@/utils/chartUtils'
|
||||
import { getHrBarChartData, formatHrZoneLabel } from '@/utils/chartUtils'
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
@@ -234,6 +237,9 @@ const velPresent = ref(false)
|
||||
const pacePresent = ref(false)
|
||||
const hrZones = ref({})
|
||||
|
||||
// Computed properties
|
||||
const hrChartData = computed(() => getHrBarChartData(hrZones.value, t))
|
||||
|
||||
// Methods
|
||||
function selectGraph(type) {
|
||||
graphSelection.value = type
|
||||
|
||||
@@ -31,6 +31,10 @@ const props = defineProps({
|
||||
datalabelsFormatter: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
timeSeconds: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
/**
|
||||
* Formats seconds into a human-readable duration string.
|
||||
* @param {number} seconds - The total number of seconds to format.
|
||||
* @returns {string} Formatted duration string (e.g., "2h 30m" or "45m").
|
||||
*/
|
||||
export function formatDuration(seconds) {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
const minutes = Math.floor((seconds % 3600) / 60)
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`
|
||||
}
|
||||
return `${minutes}m`
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats HR zone label with percentage and optional time duration.
|
||||
* @param {number} value - Percentage value
|
||||
* @param {number|null} timeSeconds - Time in seconds (0 or null means no time)
|
||||
* @returns {string} Formatted label (e.g., "25%" or "25% (15m)")
|
||||
*/
|
||||
export function formatHrZoneLabel(value, timeSeconds) {
|
||||
const percentage = `${Math.round(value)}%`
|
||||
if (!timeSeconds || timeSeconds === 0) {
|
||||
return percentage
|
||||
}
|
||||
const timeStr = formatDuration(timeSeconds)
|
||||
return `${percentage} (${timeStr})`
|
||||
}
|
||||
|
||||
export function getZoneColor(index) {
|
||||
// Example colors for 5 HR zones
|
||||
const colors = [
|
||||
@@ -18,6 +47,7 @@ export function getHrBarChartData(hrZones, t) {
|
||||
),
|
||||
// values: zones.map(z => `${z.percent ?? 0}%`),
|
||||
values: zones.map((z) => z.percent ?? 0),
|
||||
barColors: zones.map((_, i) => getZoneColor(i))
|
||||
barColors: zones.map((_, i) => getZoneColor(i)),
|
||||
timeSeconds: zones.map((z) => z.time_seconds ?? 0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user