11import Plotly from 'plotly.js-basic-dist-min'
22import { getItem , saveItem } from './storage.js' ;
3+ import * as Units from './units.js' ;
34
45// Helper function for formatting seconds
56function formatTime ( secs , prec = 2 ) {
@@ -67,6 +68,8 @@ export async function renderSummary() {
6768 strokeData . avg_spm = ( strokeData . totalLengths > 0 ) ? ( strokeData . avg_spm / strokeData . totalLengths ) : 0 ;
6869 }
6970
71+ const poolUnit = Units . getUnitLabel ( sessionData ) ;
72+
7073 // Initialize table with headers
7174 let tableHTML = `
7275 <table>
@@ -86,7 +89,7 @@ export async function renderSummary() {
8689
8790 // Variables to accumulate subtotal values
8891 let totalLengths = 0 ;
89- let totalDistance = 0 ;
92+ let totalDistanceMeters = 0 ;
9093 let totalTime = 0 ;
9194 let totalSPM = 0 ;
9295 let totalSPL = 0 ;
@@ -97,13 +100,15 @@ export async function renderSummary() {
97100 if ( grouped_data . hasOwnProperty ( stroke ) ) {
98101
99102 const strokeData = grouped_data [ stroke ] ;
100- const poolLength = sessionData . poolLength ;
101- const distance = strokeData . totalLengths * poolLength ;
102- const pace = ( strokeData . totalTime / distance ) * 100 ;
103+ const poolLengthInternal = sessionData . poolLength ;
104+ const distanceInternal = strokeData . totalLengths * poolLengthInternal ;
105+
106+ const displayDistance = Units . toDisplayDistance ( distanceInternal , sessionData ) ;
107+ const paceSeconds = Units . getPaceSeconds ( distanceInternal / strokeData . totalTime , sessionData ) ;
103108
104109 // Accumulate totals
105110 totalLengths += strokeData . totalLengths ;
106- totalDistance += distance ;
111+ totalDistanceMeters += distanceInternal ;
107112 totalTime += strokeData . totalTime ;
108113 totalSPM += strokeData . avg_spm ;
109114 totalSPL += strokeData . avg_spl ;
@@ -114,9 +119,9 @@ export async function renderSummary() {
114119 <tr class="${ stroke } ">
115120 <td>${ stroke . charAt ( 0 ) . toUpperCase ( ) + stroke . slice ( 1 ) } </td>
116121 <td>${ strokeData . totalLengths } </td>
117- <td>${ distance } m </td>
122+ <td>${ Math . round ( displayDistance ) } ${ poolUnit } </td>
118123 <td>${ formatTime ( strokeData . totalTime , 0 ) } </td>
119- <td>${ formatTime ( pace , 0 ) } </td>
124+ <td>${ formatTime ( paceSeconds , 0 ) } </td>
120125 <td>${ strokeData . avg_spm . toFixed ( 2 ) } </td>
121126 <td>${ strokeData . avg_spl . toFixed ( 2 ) } </td>
122127 </tr>
@@ -129,7 +134,8 @@ export async function renderSummary() {
129134 . filter ( d => d . lengthType === 'idle' ) // Filter the data for 'idle' lengths
130135 . reduce ( ( acc , curr ) => acc + curr . totalElapsedTime , 0 ) ; // Sum the values
131136
132- const totalPace = ( totalTime / totalDistance ) * 100 ;
137+ const displayTotalDistance = Units . toDisplayDistance ( totalDistanceMeters , sessionData ) ;
138+ const totalPaceSeconds = Units . getPaceSeconds ( totalTime > 0 ? totalDistanceMeters / totalTime : 0 , sessionData ) ;
133139
134140 // Add subtotal row
135141 tableHTML += `
@@ -158,9 +164,9 @@ export async function renderSummary() {
158164 <tr class="interval">
159165 <td>Total</td>
160166 <td>${ totalLengths } </td>
161- <td>${ totalDistance } m </td>
167+ <td>${ Math . round ( displayTotalDistance ) } ${ poolUnit } </td>
162168 <td>${ formatTime ( totalTime + totalRest , 0 ) } </td>
163- <td>${ formatTime ( totalPace , 0 ) } </td>
169+ <td>${ formatTime ( totalPaceSeconds , 0 ) } </td>
164170 <td>${ ( strokeCount > 0 ) ? ( totalSPM / strokeCount ) . toFixed ( 2 ) : '0.00' } </td>
165171 <td>${ ( strokeCount > 0 ) ? ( totalSPL / strokeCount ) . toFixed ( 2 ) : '0.00' } </td>
166172 </tr>
@@ -313,7 +319,10 @@ export async function renderBestTimes() {
313319 ...l
314320 } ) ) ;
315321
316- const poolLen = data . sessionMesgs [ 0 ] . poolLength ;
322+ const sessionData = data . sessionMesgs [ 0 ] ;
323+ const poolLenInternal = sessionData . poolLength ;
324+ const poolUnit = Units . getUnitLabel ( sessionData ) ;
325+
317326 const allowedDistances = new Set ( [ 50 , 100 , 200 , 400 , 800 , 1500 , 3000 , 5000 , 10000 ] ) ;
318327
319328 const best = { } ; // best[stroke][distance] = { time, count, lengths[] }
@@ -335,17 +344,19 @@ export async function renderBestTimes() {
335344 sum += curLengths [ end ] . totalElapsedTime ;
336345
337346 const count = end - start + 1 ;
338- const distance = count * poolLen ;
347+ const distanceInternal = count * poolLenInternal ;
348+ const displayDistance = Math . round ( Units . toDisplayDistance ( distanceInternal , sessionData ) ) ;
339349
340- if ( ! allowedDistances . has ( distance ) ) continue ;
350+ if ( ! allowedDistances . has ( displayDistance ) ) continue ;
341351
342- const existing = best [ curStroke ] [ distance ] ;
352+ const existing = best [ curStroke ] [ displayDistance ] ;
343353
344354 if ( ! existing || sum < existing . time ) {
345- best [ curStroke ] [ distance ] = {
355+ best [ curStroke ] [ displayDistance ] = {
346356 time : sum ,
347357 count,
348- lengths : curLengths . slice ( start , end + 1 )
358+ lengths : curLengths . slice ( start , end + 1 ) ,
359+ distanceInternal
349360 } ;
350361 }
351362 }
@@ -364,10 +375,11 @@ export async function renderBestTimes() {
364375 flushStreak ( ) ;
365376
366377 if ( Object . keys ( best ) . length === 0 ) {
378+ const displayPoolLen = Math . round ( Units . toDisplayDistance ( poolLenInternal , sessionData ) * 100 ) / 100 ;
367379 document . getElementById ( 'bestTimesTable' ) . innerHTML = `
368380 <div class="no-best-times-message" style="text-align:center; font-style:italic; color:#555; padding:1em;">
369- <p>No valid intervals found for a pool length of ${ poolLen } m .</p>
370- <p>The pool length must divide evenly into one of: 50, 100, 200, 400, 800, 1500, 3000, 5000, or 10000 m .</p>
381+ <p>No valid intervals found for a pool length of ${ displayPoolLen } ${ poolUnit } .</p>
382+ <p>The pool length must divide evenly into one of: 50, 100, 200, 400, 800, 1500, 3000, 5000, or 10000 ${ poolUnit } .</p>
371383 </div>` ;
372384 return ;
373385 }
@@ -377,25 +389,26 @@ export async function renderBestTimes() {
377389 Object . keys ( best ) . sort ( ) . forEach ( stroke => {
378390 const entries = Object . entries ( best [ stroke ] )
379391 . map ( ( [ dist , info ] ) => ( {
380- distance : Number ( dist ) ,
392+ displayDistance : Number ( dist ) ,
381393 stroke,
382394 time : info . time ,
383395 count : info . count ,
384- lengths : info . lengths
396+ lengths : info . lengths ,
397+ distanceInternal : info . distanceInternal
385398 } ) )
386- . sort ( ( a , b ) => a . distance - b . distance ) ;
399+ . sort ( ( a , b ) => a . displayDistance - b . displayDistance ) ;
387400
388401 entries . forEach ( e => {
389- const pace = ( e . time / e . distance ) * 100 ;
402+ const paceSeconds = Units . getPaceSeconds ( e . distanceInternal / e . time , sessionData ) ;
390403 const spm = e . lengths . reduce ( ( s , l ) => s + ( l . avgSwimmingCadence || 0 ) , 0 ) / e . count ;
391404 const spl = e . lengths . reduce ( ( s , l ) => s + ( l . totalStrokes || 0 ) , 0 ) / e . count ;
392405
393406 rows += `
394407 <tr class="${ e . stroke } ">
395- <td>${ e . distance } </td>
408+ <td>${ e . displayDistance } ${ poolUnit } </td>
396409 <td>${ e . stroke . charAt ( 0 ) . toUpperCase ( ) + e . stroke . slice ( 1 ) } </td>
397410 <td>${ formatTime ( e . time , 1 ) } </td>
398- <td>${ formatTime ( pace , 0 ) } </td>
411+ <td>${ formatTime ( paceSeconds , 0 ) } </td>
399412 <td>${ spm . toFixed ( 2 ) } </td>
400413 <td>${ spl . toFixed ( 2 ) } </td>
401414 <td>${ e . lengths [ 0 ] . index } -${ e . lengths [ e . lengths . length - 1 ] . index } </td>
@@ -428,7 +441,9 @@ export function renderPacePlot(data) {
428441
429442 // Filter data to include only entries where event is 'length' and lengthType is 'active'
430443 const lengthData = data . lengthMesgs . filter ( d => d . event === 'length' && d . lengthType === 'active' ) ;
431- const poolLength = data . sessionMesgs [ 0 ] . poolLength ;
444+ const sessionData = data . sessionMesgs [ 0 ] ;
445+ const poolLengthInternal = sessionData . poolLength ;
446+ const poolUnit = Units . getUnitLabel ( sessionData ) ;
432447
433448 // Define a fixed Viridis color map for swim strokes
434449 const fixedStrokeColors = {
@@ -443,11 +458,11 @@ export function renderPacePlot(data) {
443458 // Create paceData with stroke-based colors for the bars
444459 const paceData = {
445460 x : lengthData . map ( ( d , index ) => index + 1 ) , // X-axis as the length index
446- y : lengthData . map ( d => ( d . totalElapsedTime / poolLength ) * 100 || 0 ) , // Pace in minutes per 100m
461+ y : lengthData . map ( d => Units . getPaceSeconds ( poolLengthInternal / d . totalElapsedTime , sessionData ) || 0 ) , // Pace in seconds per 100 units
447462 name : '' ,
448463 type : 'bar' ,
449464 text : lengthData . map ( d => `Stroke: ${ d . swimStroke || 'Unknown' } <br>Pace:
450- ${ formatTime ( ( d . totalElapsedTime / poolLength ) * 100 ) } <br>SPM:
465+ ${ formatTime ( Units . getPaceSeconds ( poolLengthInternal / d . totalElapsedTime , sessionData ) ) } /100 ${ poolUnit } <br>SPM:
451466${ d . avgSwimmingCadence } <br>SPL: ${ d . totalStrokes } `) , // Hover text
452467 hoverinfo : 'text' ,
453468 textposition : 'none' , // Prevent the text from being shown on the bars
@@ -537,7 +552,9 @@ export function renderStrokeRateStrokeCountPlot(data) {
537552 ...d
538553 } ) ) ;
539554 const filteredData = activeData . filter ( d => d . swimStroke === stroke ) ;
540- const poolLength = data . sessionMesgs [ 0 ] . poolLength ;
555+ const sessionData = data . sessionMesgs [ 0 ] ;
556+ const poolLengthInternal = sessionData . poolLength ;
557+ const poolUnit = Units . getUnitLabel ( sessionData ) ;
541558
542559 // Reverse the color scale to align with faster times being darker colors and slower times being lighter
543560 const paceColorScale = [
@@ -548,8 +565,8 @@ export function renderStrokeRateStrokeCountPlot(data) {
548565 [ 1 , '#B9E1EC' ]
549566 ] ;
550567
551- // Calculate the pace values (min/100m) for the color bar
552- const paceValues = filteredData . map ( d => ( d . totalElapsedTime / poolLength ) * 100 || 0 ) ;
568+ // Calculate the pace values for the color bar
569+ const paceValues = filteredData . map ( d => Units . getPaceSeconds ( poolLengthInternal / d . totalElapsedTime , sessionData ) || 0 ) ;
553570 const paceMin = Math . min ( ...paceValues ) ;
554571 const paceMax = Math . max ( ...paceValues ) ;
555572
@@ -558,18 +575,17 @@ export function renderStrokeRateStrokeCountPlot(data) {
558575 x : filteredData . map ( d => d . avgSwimmingCadence || 0 ) , // X-axis: Stroke Rate (SPM)
559576 y : filteredData . map ( d => d . totalStrokes || 0 ) , // Y-axis: Stroke Count (SPL)
560577 mode : 'markers' ,
561- text : filteredData . map ( d => `Length: ${ d . index } <br>Pace: ${ formatTime ( ( d . totalElapsedTime /
562- poolLength ) * 100 ) } min/100m<br>SPM: ${ d . avgSwimmingCadence } <br>SPL:
578+ text : filteredData . map ( d => `Length: ${ d . index } <br>Pace: ${ formatTime ( Units . getPaceSeconds ( poolLengthInternal / d . totalElapsedTime , sessionData ) ) } /100${ poolUnit } <br>SPM: ${ d . avgSwimmingCadence } <br>SPL:
563579${ d . totalStrokes } `) , // Hover text
564580 hoverinfo : 'text' ,
565581 marker : {
566582 size : 12 , // Size of the points
567- color : paceValues , // Color: Pace (min/100m)
583+ color : paceValues , // Color: Pace
568584 colorscale : paceColorScale ,
569585 cmin : paceMin ,
570586 cmax : paceMax ,
571587 colorbar : {
572- title : ' Pace (min/100m)' ,
588+ title : ` Pace (min/100 ${ poolUnit } )` ,
573589 titleside : 'right' ,
574590 tickmode : 'array' ,
575591 tickvals : [ paceMin , paceMax ] ,
@@ -610,7 +626,8 @@ export async function renderIntervalSummaryTable() {
610626 const activeLengths = lengthData . filter ( d => d . event === 'length' && d . lengthType === 'active' ) ;
611627 const activeLapsData = data . lapMesgs . filter ( d => d . numActiveLengths > 0 ) ;
612628 const sessionData = data . sessionMesgs [ 0 ] ;
613- const poolLength = sessionData . poolLength ;
629+ const poolLengthInternal = sessionData . poolLength ;
630+ const poolUnit = Units . getUnitLabel ( sessionData ) ;
614631
615632 // Define the intervals
616633 const intervals = activeLapsData . map ( ( lap , index ) => {
@@ -655,19 +672,19 @@ export async function renderIntervalSummaryTable() {
655672
656673 // Loop through each length within the interval
657674 intervalLengths . forEach ( length => {
658- const distance = poolLength ; // Assuming each length is one pool length
675+ const displayDistance = Units . toDisplayDistance ( poolLengthInternal , sessionData ) ;
659676 const time = length . totalElapsedTime ;
660- const pace = ( time / distance ) * 100 ;
677+ const paceSeconds = Units . getPaceSeconds ( poolLengthInternal / time , sessionData ) ;
661678 const spm = length . avgSwimmingCadence || 0 ;
662679 const spl = ( length . totalStrokes || 0 ) ;
663680
664681 tableHTML += `
665682 <tr class="length ${ length . swimStroke } ">
666683 <td>${ lengthCounter } </td>
667- <td>${ distance } </td>
684+ <td>${ Math . round ( displayDistance ) } ${ poolUnit } </td>
668685 <td>${ length . swimStroke . charAt ( 0 ) . toUpperCase ( ) + length . swimStroke . slice ( 1 ) } </td>
669686 <td>${ formatTime ( time , 1 ) } </td>
670- <td>${ formatTime ( pace , 0 ) } </td>
687+ <td>${ formatTime ( paceSeconds , 0 ) } </td>
671688 <td>${ spm } </td>
672689 <td>${ spl } </td>
673690 </tr>
@@ -699,11 +716,12 @@ export async function renderIntervalSummaryTable() {
699716
700717 // Calculate interval summary
701718 const totalLengths = intervalLengths . length ;
702- const intervalDistance = totalLengths * poolLength ;
719+ const intervalDistanceInternal = totalLengths * poolLengthInternal ;
720+ const intervalDistanceDisplay = Units . toDisplayDistance ( intervalDistanceInternal , sessionData ) ;
703721 const intervalTime = intervalLengths . reduce ( ( sum , length ) => sum + length . totalElapsedTime , 0 ) ;
704722 const intervalSPM = intervalLengths . reduce ( ( sum , length ) => sum + ( length . avgSwimmingCadence || 0 ) , 0 ) / totalLengths ;
705723 const intervalSPL = intervalLengths . reduce ( ( sum , length ) => sum + ( length . totalStrokes || 0 ) , 0 ) / totalLengths ;
706- const intervalPace = ( intervalTime / intervalDistance ) * 100 ;
724+ const intervalPaceSeconds = Units . getPaceSeconds ( intervalDistanceInternal / intervalTime , sessionData ) ;
707725
708726 // Calculate interval stroke
709727 const strokesInInterval = intervalLengths . map ( length => length . swimStroke ) ;
@@ -714,10 +732,10 @@ export async function renderIntervalSummaryTable() {
714732 tableHTML += `
715733 <tr class="interval">
716734 <td>${ ordinalSuffixOf ( intervalIndex + 1 ) } Interval</td>
717- <td>${ intervalDistance } </td>
735+ <td>${ Math . round ( intervalDistanceDisplay ) } ${ poolUnit } </td>
718736 <td>${ intervalStroke } </td>
719737 <td>${ formatTime ( intervalTime , 1 ) } </td>
720- <td>${ formatTime ( intervalPace , 0 ) } </td>
738+ <td>${ formatTime ( intervalPaceSeconds , 0 ) } </td>
721739 <td>${ intervalSPM . toFixed ( 2 ) } </td>
722740 <td>${ intervalSPL . toFixed ( 2 ) } </td>
723741 </tr>
0 commit comments