@@ -169,6 +169,11 @@ type AccY = NESeq (Tuple2 Timestamp Double)
169169-- | Accumulator for chart with two Y axes.
170170type AccY1 = NESeq (Tuple3 Timestamp Double Double )
171171
172+ hasPace :: ChartData -> Bool
173+ hasPace (ChartDataY y) = y ^. # yType == YAxisPace
174+ hasPace (ChartDataY1 y) =
175+ (y ^. # yType == YAxisPace ) || (y ^. # y1Type == YAxisPace )
176+
172177-- | Turns a sequence of activities and a chart request into a chart.
173178mkChartData ::
174179 forall es a .
@@ -197,7 +202,7 @@ mkChartData finalDistUnit globalFilters as request = do
197202 Empty -> pure $ Err $ CreateChartFilterEmpty $ request ^. # title
198203 r :<| rs -> do
199204 activities <- handleChartType (request ^. # chartType) (r :<|| rs)
200- pure $ Ok $ mkChartDataSets finalDistUnit request activities
205+ Ok <$> mkChartDataSets finalDistUnit request activities
201206 where
202207 (MkSomeActivities (SetToSeqNE someActivities)) = as
203208 filteredActivities =
@@ -295,8 +300,9 @@ handleChartType @es @a mChartType someActivities = case mChartType of
295300 toDatetime = view # datetime
296301
297302mkChartDataSets ::
298- forall a .
303+ forall a es .
299304 ( Fromℤ a ,
305+ Logger :> es ,
300306 Ord a ,
301307 Semifield a ,
302308 Show a ,
@@ -305,17 +311,29 @@ mkChartDataSets ::
305311 DistanceUnit ->
306312 ChartRequest a ->
307313 NESeq (SomeActivity a ) ->
308- ChartData
309- mkChartDataSets @ a finalDistUnit request activities@ (MkSomeActivity sd _ :<|| _) =
310- case request ^. # y1Axis of
311- Nothing ->
312- let vals = withSingI sd $ foldMap1 toAccY activities
313- yType = request ^. # yAxis
314- in ChartDataY (MkChartY vals yType finalDistUnit)
315- Just y1Type ->
316- let vals = withSingI sd $ foldMap1 (toAccY1 y1Type) activities
317- yType = request ^. # yAxis
318- in ChartDataY1 (MkChartY1 vals yType y1Type finalDistUnit)
314+ Eff es ChartData
315+ mkChartDataSets @ a finalDistUnit request activities@ (MkSomeActivity sd _ :<|| _) = do
316+ let chartData = case request ^. # y1Axis of
317+ Nothing ->
318+ let vals = withSingI sd $ foldMap1 toAccY activities
319+ yType = request ^. # yAxis
320+ in ChartDataY (MkChartY vals yType finalDistUnit)
321+ Just y1Type ->
322+ let vals = withSingI sd $ foldMap1 (toAccY1 y1Type) activities
323+ yType = request ^. # yAxis
324+ in ChartDataY1 (MkChartY1 vals yType y1Type finalDistUnit)
325+
326+ -- Log a message if meters and pace were requested.
327+ when (hasPace chartData && finalDistUnit == Meter ) $ do
328+ let msg =
329+ mconcat
330+ [ " Requested meters for chart '" ,
331+ request ^. # title,
332+ " ', converting pace to km."
333+ ]
334+ $ (Logger. logInfo) msg
335+
336+ pure chartData
319337 where
320338 toAccY :: SomeActivity a -> AccY
321339 toAccY sr@ (MkSomeActivity _ r) = NESeq. singleton (r ^. # datetime, toY sr)
@@ -331,18 +349,14 @@ mkChartDataSets @a finalDistUnit request activities@(MkSomeActivity sd _ :<|| _)
331349 toYHelper axisType (MkSomeActivity s r) = case axisType of
332350 YAxisDistance ->
333351 withSingI s $ case finalDistUnit of
334- -- REVIEW: Should this be (DistU.convertDistance Meter)? Or do we
335- -- only allow km/mi in charts?
336- Meter -> toDistRaw (DistU. convertToKilometers r)
352+ -- See NOTE: [Chart Units]
353+ Meter -> toDistRaw (DistU. convertDistance Meter r)
337354 Kilometer -> toDistRaw (DistU. convertToKilometers r)
338355 Mile -> toDistRaw (DistU. convertDistance Mile r)
339356 YAxisDuration -> toDurRaw r
340357 YAxisPace ->
341358 withSingI s $ case finalDistUnit of
342- -- REVIEW: Ideally this would error, not convert. But probably we
343- -- already throw errors somewhere, and the Meters are only here
344- -- because we haven't proven to GHC that it is impossible. It would
345- -- be nice to come up with something more robust.
359+ -- See NOTE: [Chart Units]
346360 Meter -> toPaceRaw (DistU. convertToKilometers r)
347361 Kilometer -> toPaceRaw (DistU. convertToKilometers r)
348362 Mile -> toPaceRaw (DistU. convertDistance Mile r)
@@ -356,6 +370,39 @@ mkChartDataSets @a finalDistUnit request activities@(MkSomeActivity sd _ :<|| _)
356370 toDurRaw :: Activity d a -> Double
357371 toDurRaw = toℝ . view (# duration % # unDuration)
358372
373+ -- NOTE: [Chart Units]
374+ --
375+ -- In general, the frontend supports all units as the y-axis:
376+ --
377+ -- distance: m, km, mi
378+ -- duration: <time>
379+ -- pace: m, km, mi
380+ --
381+ -- However, we explicitly do not allow pace to be used with meters, so the
382+ -- question of what to do if the user specifies 'meters' in a chart request
383+ -- (charts[i].unit = "m") arises.
384+ --
385+ -- Previously, we converted both YAxisDistance and YAxisPace to km, so no
386+ -- warnings/errors, but only km was allowed. We now decide to let distance
387+ -- respect meters, though pace is still converted. We do this for several
388+ -- reasons:
389+ --
390+ -- - In general, we should respect the user's choice when we can, and meters
391+ -- are perfectly sensible for some distances (e.g. track events).
392+ --
393+ -- - We should allow graphing distance by meters and pace by km, but there is
394+ -- only one distance unit in chart-requests at the moment, so pace cannot
395+ -- then error.
396+ --
397+ -- - If we ever add something like elevation, meters makes sense there as
398+ -- well.
399+ --
400+ -- Hence we log a message for conversions, but otherwise respect the choice.
401+ -- This raises the possibility of specifying multiple units e.g.
402+ -- distance_unit and pace_unit, because as of now we cannot have
403+ -- distance in meters and pace in miles, which is also reasonable. But that
404+ -- is a low priority.
405+
359406-- | A moving window has the group representative be the median element.
360407smoothWindow ::
361408 ( Fromℤ a ,
0 commit comments