Client - display converted speed/elevation in workout chart
This commit is contained in:
		@@ -55,12 +55,14 @@
 | 
			
		||||
  import { LineChart, useLineChart } from 'vue-chart-3'
 | 
			
		||||
  import { useI18n } from 'vue-i18n'
 | 
			
		||||
 | 
			
		||||
  import { TUnit } from '@/types/units'
 | 
			
		||||
  import { IUserProfile } from '@/types/user'
 | 
			
		||||
  import {
 | 
			
		||||
    IWorkoutChartData,
 | 
			
		||||
    IWorkoutData,
 | 
			
		||||
    TCoordinates,
 | 
			
		||||
  } from '@/types/workouts'
 | 
			
		||||
  import { units } from '@/utils/units'
 | 
			
		||||
  import { getDatasets } from '@/utils/workouts'
 | 
			
		||||
 | 
			
		||||
  interface Props {
 | 
			
		||||
@@ -76,8 +78,10 @@
 | 
			
		||||
  let displayDistance = ref(true)
 | 
			
		||||
  let beginElevationAtZero = ref(true)
 | 
			
		||||
  const datasets: ComputedRef<IWorkoutChartData> = computed(() =>
 | 
			
		||||
    getDatasets(props.workoutData.chartData, t)
 | 
			
		||||
    getDatasets(props.workoutData.chartData, t, props.authUser.imperial_units)
 | 
			
		||||
  )
 | 
			
		||||
  const fromKmUnit = getUnitTo('km')
 | 
			
		||||
  const fromMUnit = getUnitTo('m')
 | 
			
		||||
  let chartData: ComputedRef<ChartData<'line'>> = computed(() => ({
 | 
			
		||||
    labels: displayDistance.value
 | 
			
		||||
      ? datasets.value.distance_labels
 | 
			
		||||
@@ -119,7 +123,7 @@
 | 
			
		||||
        title: {
 | 
			
		||||
          display: true,
 | 
			
		||||
          text: displayDistance.value
 | 
			
		||||
            ? t('workouts.DISTANCE') + ' (km)'
 | 
			
		||||
            ? t('workouts.DISTANCE') + ` (${fromKmUnit})`
 | 
			
		||||
            : t('workouts.DURATION'),
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
@@ -130,7 +134,7 @@
 | 
			
		||||
        position: 'left',
 | 
			
		||||
        title: {
 | 
			
		||||
          display: true,
 | 
			
		||||
          text: t('workouts.SPEED') + ' (km/h)',
 | 
			
		||||
          text: t('workouts.SPEED') + ` (${fromKmUnit}/h)`,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      yElevation: {
 | 
			
		||||
@@ -141,7 +145,7 @@
 | 
			
		||||
        position: 'right',
 | 
			
		||||
        title: {
 | 
			
		||||
          display: true,
 | 
			
		||||
          text: t('workouts.ELEVATION') + ' (m)',
 | 
			
		||||
          text: t('workouts.ELEVATION') + ` (${fromMUnit})`,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
@@ -164,8 +168,8 @@
 | 
			
		||||
          label: function (context) {
 | 
			
		||||
            const label = ` ${context.dataset.label}: ${context.formattedValue}`
 | 
			
		||||
            return context.dataset.yAxisID === 'yElevation'
 | 
			
		||||
              ? label + ' m'
 | 
			
		||||
              : label + ' km/h'
 | 
			
		||||
              ? label + ` ${fromMUnit}`
 | 
			
		||||
              : label + ` ${fromKmUnit}/h`
 | 
			
		||||
          },
 | 
			
		||||
          title: function (tooltipItems) {
 | 
			
		||||
            if (tooltipItems.length > 0) {
 | 
			
		||||
@@ -174,7 +178,9 @@
 | 
			
		||||
            return tooltipItems.length === 0
 | 
			
		||||
              ? ''
 | 
			
		||||
              : displayDistance.value
 | 
			
		||||
              ? `${t('workouts.DISTANCE')}: ${tooltipItems[0].label} km`
 | 
			
		||||
              ? `${t('workouts.DISTANCE')}: ${
 | 
			
		||||
                  tooltipItems[0].label
 | 
			
		||||
                } ${fromKmUnit}`
 | 
			
		||||
              : `${t('workouts.DURATION')}: ${formatDuration(
 | 
			
		||||
                  tooltipItems[0].label.replace(',', '')
 | 
			
		||||
                )}`
 | 
			
		||||
@@ -200,6 +206,11 @@
 | 
			
		||||
  function emitEmptyCoordinates() {
 | 
			
		||||
    emitCoordinates({ latitude: null, longitude: null })
 | 
			
		||||
  }
 | 
			
		||||
  function getUnitTo(unitFrom: TUnit): TUnit {
 | 
			
		||||
    return props.authUser.imperial_units
 | 
			
		||||
      ? units[unitFrom].defaultTarget
 | 
			
		||||
      : unitFrom
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
            <Distance
 | 
			
		||||
              :distance="segment.distance"
 | 
			
		||||
              unitFrom="km"
 | 
			
		||||
              :strong="true"
 | 
			
		||||
              :useImperialUnits="useImperialUnits"
 | 
			
		||||
            />, {{ $t('workouts.DURATION') }}: {{ segment.duration }})
 | 
			
		||||
          </li>
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ import {
 | 
			
		||||
} from '@/types/statistics'
 | 
			
		||||
import { incrementDate, getStartDate } from '@/utils/dates'
 | 
			
		||||
import { sportColors } from '@/utils/sports'
 | 
			
		||||
import { convertDistance, units } from '@/utils/units'
 | 
			
		||||
import { convertStatsDistance } from '@/utils/units'
 | 
			
		||||
 | 
			
		||||
const dateFormats: Record<string, Record<string, string>> = {
 | 
			
		||||
  week: {
 | 
			
		||||
@@ -103,13 +103,12 @@ export const convertStatsValue = (
 | 
			
		||||
  switch (datasetKey) {
 | 
			
		||||
    case 'total_distance':
 | 
			
		||||
    case 'total_ascent':
 | 
			
		||||
    case 'total_descent': {
 | 
			
		||||
      const unitFrom = datasetKey === 'total_distance' ? 'km' : 'm'
 | 
			
		||||
      const unitTo = useImperialUnits ? units[unitFrom].defaultTarget : unitFrom
 | 
			
		||||
      return useImperialUnits
 | 
			
		||||
        ? convertDistance(value, unitFrom, unitTo, 2)
 | 
			
		||||
        : value
 | 
			
		||||
    }
 | 
			
		||||
    case 'total_descent':
 | 
			
		||||
      return convertStatsDistance(
 | 
			
		||||
        datasetKey === 'total_distance' ? 'km' : 'm',
 | 
			
		||||
        value,
 | 
			
		||||
        useImperialUnits
 | 
			
		||||
      )
 | 
			
		||||
    default:
 | 
			
		||||
    case 'nb_workouts':
 | 
			
		||||
    case 'total_duration':
 | 
			
		||||
 
 | 
			
		||||
@@ -54,3 +54,12 @@ export const convertDistance = (
 | 
			
		||||
  }
 | 
			
		||||
  return convertedDistance
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const convertStatsDistance = (
 | 
			
		||||
  unitFrom: TUnit,
 | 
			
		||||
  value: number,
 | 
			
		||||
  useImperialUnits: boolean
 | 
			
		||||
): number => {
 | 
			
		||||
  const unitTo = useImperialUnits ? units[unitFrom].defaultTarget : unitFrom
 | 
			
		||||
  return useImperialUnits ? convertDistance(value, unitFrom, unitTo, 2) : value
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,12 @@ import {
 | 
			
		||||
  TCoordinates,
 | 
			
		||||
  TWorkoutDatasets,
 | 
			
		||||
} from '@/types/workouts'
 | 
			
		||||
import { convertStatsDistance } from '@/utils/units'
 | 
			
		||||
 | 
			
		||||
export const getDatasets = (
 | 
			
		||||
  chartData: IWorkoutApiChartData[],
 | 
			
		||||
  t: CallableFunction
 | 
			
		||||
  t: CallableFunction,
 | 
			
		||||
  useImperialUnits: boolean
 | 
			
		||||
): IWorkoutChartData => {
 | 
			
		||||
  const datasets: TWorkoutDatasets = {
 | 
			
		||||
    speed: {
 | 
			
		||||
@@ -36,8 +38,12 @@ export const getDatasets = (
 | 
			
		||||
  chartData.map((data) => {
 | 
			
		||||
    distance_labels.push(data.distance)
 | 
			
		||||
    duration_labels.push(data.duration)
 | 
			
		||||
    datasets.speed.data.push(data.speed)
 | 
			
		||||
    datasets.elevation.data.push(data.elevation)
 | 
			
		||||
    datasets.speed.data.push(
 | 
			
		||||
      convertStatsDistance('km', data.speed, useImperialUnits)
 | 
			
		||||
    )
 | 
			
		||||
    datasets.elevation.data.push(
 | 
			
		||||
      convertStatsDistance('m', data.elevation, useImperialUnits)
 | 
			
		||||
    )
 | 
			
		||||
    coordinates.push({ latitude: data.latitude, longitude: data.longitude })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ describe('getDatasets', () => {
 | 
			
		||||
      inputParams: {
 | 
			
		||||
        charData: [],
 | 
			
		||||
        locale: 'fr',
 | 
			
		||||
        useImperialUnits: false,
 | 
			
		||||
      },
 | 
			
		||||
      expected: {
 | 
			
		||||
        distance_labels: [],
 | 
			
		||||
@@ -72,6 +73,7 @@ describe('getDatasets', () => {
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        locale: 'en',
 | 
			
		||||
        useImperialUnits: false,
 | 
			
		||||
      },
 | 
			
		||||
      expected: {
 | 
			
		||||
        distance_labels: [0, 0, 0.01],
 | 
			
		||||
@@ -102,12 +104,80 @@ describe('getDatasets', () => {
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      description: 'returns datasets w/ units conversion',
 | 
			
		||||
      inputParams: {
 | 
			
		||||
        charData: [
 | 
			
		||||
          {
 | 
			
		||||
            distance: 0,
 | 
			
		||||
            duration: 0,
 | 
			
		||||
            elevation: 83.6,
 | 
			
		||||
            latitude: 48.845574,
 | 
			
		||||
            longitude: 2.373723,
 | 
			
		||||
            speed: 2.89,
 | 
			
		||||
            time: 'Sun, 12 Sep 2021 13:29:24 GMT',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            distance: 0,
 | 
			
		||||
            duration: 1,
 | 
			
		||||
            elevation: 83.7,
 | 
			
		||||
            latitude: 48.845578,
 | 
			
		||||
            longitude: 2.373732,
 | 
			
		||||
            speed: 1.56,
 | 
			
		||||
            time: 'Sun, 12 Sep 2021 13:29:25 GMT',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            distance: 0.01,
 | 
			
		||||
            duration: 96,
 | 
			
		||||
            elevation: 84.3,
 | 
			
		||||
            latitude: 48.845591,
 | 
			
		||||
            longitude: 2.373811,
 | 
			
		||||
            speed: 14.73,
 | 
			
		||||
            time: 'Sun, 12 Sep 2021 13:31:00 GMT',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        locale: 'en',
 | 
			
		||||
        useImperialUnits: true,
 | 
			
		||||
      },
 | 
			
		||||
      expected: {
 | 
			
		||||
        distance_labels: [0, 0, 0.01],
 | 
			
		||||
        duration_labels: [0, 1, 96],
 | 
			
		||||
        datasets: {
 | 
			
		||||
          speed: {
 | 
			
		||||
            label: 'speed',
 | 
			
		||||
            backgroundColor: ['#FFFFFF'],
 | 
			
		||||
            borderColor: ['#8884d8'],
 | 
			
		||||
            borderWidth: 2,
 | 
			
		||||
            data: [1.8, 0.97, 9.15],
 | 
			
		||||
            yAxisID: 'ySpeed',
 | 
			
		||||
          },
 | 
			
		||||
          elevation: {
 | 
			
		||||
            label: 'elevation',
 | 
			
		||||
            backgroundColor: ['#e5e5e5'],
 | 
			
		||||
            borderColor: ['#cccccc'],
 | 
			
		||||
            borderWidth: 1,
 | 
			
		||||
            fill: true,
 | 
			
		||||
            data: [274.28, 274.61, 276.57],
 | 
			
		||||
            yAxisID: 'yElevation',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        coordinates: [
 | 
			
		||||
          { latitude: 48.845574, longitude: 2.373723 },
 | 
			
		||||
          { latitude: 48.845578, longitude: 2.373732 },
 | 
			
		||||
          { latitude: 48.845591, longitude: 2.373811 },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
  testparams.map((testParams) => {
 | 
			
		||||
    it(testParams.description, () => {
 | 
			
		||||
      locale.value = testParams.inputParams.locale
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        getDatasets(testParams.inputParams.charData, t),
 | 
			
		||||
        getDatasets(
 | 
			
		||||
          testParams.inputParams.charData,
 | 
			
		||||
          t,
 | 
			
		||||
          testParams.inputParams.useImperialUnits
 | 
			
		||||
        ),
 | 
			
		||||
        testParams.expected
 | 
			
		||||
      )
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user