@@ -34,6 +34,10 @@ document.addEventListener('DOMContentLoaded', function() {
3434 if ( currentMode === 'select' ) {
3535 updateSelectAllCheckboxState ( ) ;
3636 }
37+
38+ // Update cost bars and ticks since visible rows may have changed
39+ updateCostBars ( ) ;
40+ updateCostTicks ( ) ;
3741 }
3842
3943 function getVisibleMainRows ( ) {
@@ -89,7 +93,6 @@ document.addEventListener('DOMContentLoaded', function() {
8993 // Get the first header cell (for the toggle/checkbox column)
9094 const firstHeaderCell = document . querySelector ( 'table thead th:first-child' ) ;
9195
92-
9396 // Show/hide header checkbox based on mode
9497 selectAllCheckbox . style . display = mode === 'select' ? 'inline-block' : 'none' ;
9598
@@ -193,6 +196,10 @@ document.addEventListener('DOMContentLoaded', function() {
193196
194197 // Update the select-all checkbox state after updating the view
195198 updateSelectAllCheckboxState ( ) ;
199+
200+ // Update cost bars and ticks since visible/selected rows may have changed
201+ updateCostBars ( ) ;
202+ updateCostTicks ( ) ;
196203 }
197204
198205
@@ -209,75 +216,127 @@ document.addEventListener('DOMContentLoaded', function() {
209216 }
210217 } ) ;
211218
212- // Process cost bars
213- const costBars = document . querySelectorAll ( '.cost-bar' ) ;
214- const MAX_DISPLAY_COST = 50 ; // $50 limit for visual display
219+ // Function to calculate the appropriate max display cost based on visible/selected entries
220+ function calculateDisplayMaxCost ( ) {
221+ // Get the appropriate set of rows based on the current mode and selection state
222+ let rowsToConsider ;
223+
224+ if ( currentMode === 'view' && selectedRows . size > 0 ) {
225+ // In view mode with selections, only consider selected rows
226+ rowsToConsider = Array . from ( allMainRows ) . filter ( row => {
227+ const rowIndex = row . querySelector ( '.row-selector' ) ?. dataset . rowIndex ;
228+ return rowIndex && selectedRows . has ( rowIndex ) && ! row . classList . contains ( 'hidden-by-search' ) ;
229+ } ) ;
230+ } else {
231+ // In other modes or without selections, consider all visible rows
232+ rowsToConsider = getVisibleMainRows ( ) ;
233+ }
234+
235+ // Find the maximum cost among the rows to consider
236+ let maxCost = 0 ;
237+ rowsToConsider . forEach ( row => {
238+ const costBar = row . querySelector ( '.cost-bar' ) ;
239+ if ( costBar ) {
240+ const cost = parseFloat ( costBar . dataset . cost || '0' ) ;
241+ if ( cost > maxCost ) maxCost = cost ;
242+ }
243+ } ) ;
244+
245+ // Cap at 50 if any entries exceed that amount, otherwise use actual max
246+ return maxCost > 50 ? 50 : Math . max ( 1 , maxCost ) ; // Ensure at least 1 to avoid division by zero
247+ }
215248
216- costBars . forEach ( bar => {
217- const cost = parseFloat ( bar . dataset . cost ) ;
218- const maxCost = parseFloat ( bar . dataset . maxCost ) ;
219-
220- if ( cost > 0 && maxCost > 0 ) {
221- // Use $50 as the max for display purposes
222- const displayMaxCost = Math . min ( MAX_DISPLAY_COST , maxCost ) ;
223- // Calculate percentage based on the display max
224- const percent = Math . min ( cost , displayMaxCost ) / displayMaxCost * 100 ;
225- // Clamp percentage between 0 and 100
226- bar . style . width = Math . max ( 0 , Math . min ( 100 , percent ) ) + '%' ;
249+ // Process cost bars with dynamic scale
250+ function updateCostBars ( ) {
251+ const costBars = document . querySelectorAll ( '.cost-bar' ) ;
252+ const currentMaxDisplayCost = calculateDisplayMaxCost ( ) ;
253+
254+ // Remove existing special indicators first
255+ document . querySelectorAll ( '.dark-section, .tear-line' ) . forEach ( el => el . remove ( ) ) ;
256+
257+ costBars . forEach ( bar => {
258+ const cost = parseFloat ( bar . dataset . cost ) ;
227259
228- // Mark bars that exceed the limit
229- if ( cost > MAX_DISPLAY_COST ) {
230- // Create a darker section at the end with diagonal stripes
231- const darkSection = document . createElement ( 'div' ) ;
232- darkSection . className = 'bar-viz' ;
233- darkSection . style . width = '15%' ; // From 85% to 100%
234- darkSection . style . left = '85%' ;
235- darkSection . style . backgroundColor = 'rgba(13, 110, 253, 0.6)' ; // Darker blue
236- darkSection . style . borderRight = '1px solid rgba(13, 110, 253, 0.8)' ;
237- darkSection . style . zIndex = '1' ;
238- // Add diagonal stripes with CSS background
239- darkSection . style . backgroundImage = 'repeating-linear-gradient(45deg, rgba(255,255,255,0.3), rgba(255,255,255,0.3) 5px, transparent 5px, transparent 10px)' ;
240- bar . parentNode . appendChild ( darkSection ) ;
260+ if ( cost > 0 ) {
261+ // Calculate percentage based on the dynamic display max
262+ const percent = Math . min ( cost , currentMaxDisplayCost ) / currentMaxDisplayCost * 100 ;
263+ // Clamp percentage between 0 and 100
264+ bar . style . width = Math . max ( 0 , Math . min ( 100 , percent ) ) + '%' ;
241265
242- // Add a dashed "tear line" at the transition point
243- const tearLine = document . createElement ( 'div' ) ;
244- tearLine . style . position = 'absolute' ;
245- tearLine . style . left = '85%' ;
246- // Center the tear line vertically and make it 1.5x as tall as the bar
247- tearLine . style . top = '50%' ;
248- tearLine . style . transform = 'translateY(-50%)' ;
249- tearLine . style . height = '54px' ; // 1.5x the bar height (36px)
250- tearLine . style . width = '2px' ;
251- tearLine . style . backgroundColor = 'white' ;
252- tearLine . style . borderLeft = '2px dashed rgba(0, 0, 0, 0.3)' ;
253- tearLine . style . zIndex = '2' ; // Above the bar
254- bar . parentNode . appendChild ( tearLine ) ;
266+ // Mark bars that exceed the limit (only if our display max is capped at 50)
267+ if ( currentMaxDisplayCost === 50 && cost > 50 ) {
268+ // Create a darker section at the end with diagonal stripes
269+ const darkSection = document . createElement ( 'div' ) ;
270+ darkSection . className = 'bar-viz dark-section' ;
271+ darkSection . style . width = '15%' ; // From 85% to 100%
272+ darkSection . style . left = '85%' ;
273+ darkSection . style . backgroundColor = 'rgba(13, 110, 253, 0.6)' ; // Darker blue
274+ darkSection . style . borderRight = '1px solid rgba(13, 110, 253, 0.8)' ;
275+ darkSection . style . zIndex = '1' ;
276+ // Add diagonal stripes with CSS background
277+ darkSection . style . backgroundImage = 'repeating-linear-gradient(45deg, rgba(255,255,255,0.3), rgba(255,255,255,0.3) 5px, transparent 5px, transparent 10px)' ;
278+ bar . parentNode . appendChild ( darkSection ) ;
279+
280+ // Add a dashed "tear line" at the transition point
281+ const tearLine = document . createElement ( 'div' ) ;
282+ tearLine . className = 'tear-line' ;
283+ tearLine . style . position = 'absolute' ;
284+ tearLine . style . left = '85%' ;
285+ // Center the tear line vertically and make it 1.5x as tall as the bar
286+ tearLine . style . top = '50%' ;
287+ tearLine . style . transform = 'translateY(-50%)' ;
288+ tearLine . style . height = '54px' ; // 1.5x the bar height (36px)
289+ tearLine . style . width = '2px' ;
290+ tearLine . style . backgroundColor = 'white' ;
291+ tearLine . style . borderLeft = '2px dashed rgba(0, 0, 0, 0.3)' ;
292+ tearLine . style . zIndex = '2' ; // Above the bar
293+ bar . parentNode . appendChild ( tearLine ) ;
294+ }
295+ } else {
296+ // Set width to 0 if cost is 0 or negative
297+ bar . style . width = '0%' ;
255298 }
256- } else {
257- // Set width to 0 if cost is 0 or negative
258- bar . style . width = '0%' ;
259- }
260- } ) ;
299+ } ) ;
300+ }
301+
302+ // Call this initially to set up the bars
303+ updateCostBars ( ) ;
261304
262- // Calculate and add cost ticks dynamically
263- const costCells = document . querySelectorAll ( '.cost-bar-cell' ) ;
264- if ( costCells . length > 0 ) {
265- const MAX_DISPLAY_COST = 50 ; // $50 limit for visual display
305+ // Update cost ticks dynamically based on current max display cost
306+ function updateCostTicks ( ) {
307+ const costCells = document . querySelectorAll ( '.cost-bar-cell' ) ;
308+ if ( costCells . length === 0 ) return ;
309+
310+ const currentMaxDisplayCost = calculateDisplayMaxCost ( ) ;
266311
267- // Generate fixed tick values at $0, $10, $20, $30, $40, $50
268- const tickValues = [ 0 , 10 , 20 , 30 , 40 , 50 ] ;
312+ // Remove existing ticks first
313+ document . querySelectorAll ( '.cost-tick' ) . forEach ( tick => tick . remove ( ) ) ;
314+
315+ // Generate appropriate tick values based on current max
316+ let tickValues = [ ] ;
317+
318+ if ( currentMaxDisplayCost === 50 ) {
319+ // Fixed ticks at $0, $10, $20, $30, $40, $50 when we're at the cap
320+ tickValues = [ 0 , 10 , 20 , 30 , 40 , 50 ] ;
321+ } else {
322+ // Dynamic ticks based on actual max
323+ const tickCount = 5 ; // Create 5 segments (6 ticks including 0)
324+ for ( let i = 0 ; i <= tickCount ; i ++ ) {
325+ tickValues . push ( Math . round ( ( i / tickCount ) * currentMaxDisplayCost * 100 ) / 100 ) ;
326+ }
327+ }
269328
270- // Calculate percentage positions for each tick on the linear scale
329+ // Calculate percentage positions for each tick
271330 const tickPercentages = tickValues . map ( tickCost => {
272- return ( tickCost / MAX_DISPLAY_COST ) * 100 ;
331+ return ( tickCost / currentMaxDisplayCost ) * 100 ;
273332 } ) ;
274-
333+
275334 // Add tick divs to each cost cell
276335 costCells . forEach ( cell => {
277336 const costBar = cell . querySelector ( '.cost-bar' ) ;
278337 // Use optional chaining and provide '0' as fallback if costBar or dataset.cost is missing
279338 const cost = parseFloat ( costBar ?. dataset ?. cost || '0' ) ;
280-
339+
281340 // Only add ticks if the cost is actually greater than 0
282341 if ( cost > 0 ) {
283342 tickPercentages . forEach ( ( percent , index ) => {
@@ -286,15 +345,15 @@ document.addEventListener('DOMContentLoaded', function() {
286345 const tick = document . createElement ( 'div' ) ;
287346 tick . className = 'cost-tick' ;
288347 tick . style . left = `${ percent } %` ;
289-
290- // No dollar amount labels
291-
292348 cell . appendChild ( tick ) ;
293349 }
294350 } ) ;
295351 }
296352 } ) ;
297353 }
354+
355+ // Call this initially to set up the ticks
356+ updateCostTicks ( ) ;
298357
299358
300359 // --- New Event Listeners ---
@@ -340,6 +399,12 @@ document.addEventListener('DOMContentLoaded', function() {
340399 }
341400 // Update select-all checkbox state
342401 updateSelectAllCheckboxState ( ) ;
402+
403+ // Update cost bars and ticks if in view mode, as selection affects what's shown
404+ if ( currentMode === 'view' ) {
405+ updateCostBars ( ) ;
406+ updateCostTicks ( ) ;
407+ }
343408 }
344409 } ) ; // End of tableBody listener
345410
@@ -369,6 +434,10 @@ document.addEventListener('DOMContentLoaded', function() {
369434 } ) ;
370435 // After bulk change, ensure the selectAll checkbox state is correct (not indeterminate)
371436 updateSelectAllCheckboxState ( ) ;
437+
438+ // Update cost bars and ticks after selection changes
439+ updateCostBars ( ) ;
440+ updateCostTicks ( ) ;
372441 } ) ;
373442
374443 // Listener for search input
0 commit comments