@@ -95,7 +95,8 @@ window.addEventListener('load', async function () {
9595 canvas . style . width = video . offsetWidth + 'px' ;
9696 canvas . style . height = video . offsetHeight + 'px' ;
9797
98- startContinuousDetection ( ) ;
98+ startDrawingLoop ( ) ;
99+ startDetectionLoop ( ) ;
99100 } ) ;
100101
101102 // Add camera switch button event listener
@@ -167,6 +168,9 @@ let lastDetectionTime = 0;
167168let isDetecting = false ;
168169let lastDetectedBarcodes = [ ] ;
169170let deltaTimeMs = 0 ;
171+ let currentBarcodes = [ ] ; // Store current barcodes for drawing
172+ let displayBarcodes = new Map ( ) ; // Store barcode positions for tweening
173+ let lastDrawTime = 0 ; // For drawing throttling
170174
171175// Helper function to calculate center point from corner points
172176function calculateCenterPoint ( cornerPoints ) {
@@ -175,15 +179,31 @@ function calculateCenterPoint(cornerPoints) {
175179 return { x : centerX , y : centerY } ;
176180}
177181
178- async function startContinuousDetection ( currentTime ) {
179- if ( currentTime - lastDetectionTime >= 16 && ! isDetecting ) {
180- isDetecting = true ;
181- detectBarcodes ( ) . finally ( ( ) => {
182- isDetecting = false ;
183- } ) ;
184- lastDetectionTime = currentTime ;
182+ // Separate drawing loop throttled to 40 FPS
183+ function startDrawingLoop ( ) {
184+ function draw ( currentTime ) {
185+ if ( currentTime - lastDrawTime >= 25 ) { // 40 FPS = 25ms intervals
186+ drawBarcodes ( ) ;
187+ lastDrawTime = currentTime ;
188+ }
189+ requestAnimationFrame ( draw ) ;
190+ }
191+ requestAnimationFrame ( draw ) ;
192+ }
193+
194+ // Separate detection loop that's throttled
195+ function startDetectionLoop ( ) {
196+ function detect ( currentTime ) {
197+ if ( currentTime - lastDetectionTime >= 700 && ! isDetecting ) {
198+ isDetecting = true ;
199+ detectBarcodes ( ) . finally ( ( ) => {
200+ isDetecting = false ;
201+ } ) ;
202+ lastDetectionTime = currentTime ;
203+ }
204+ requestAnimationFrame ( detect ) ;
185205 }
186- requestAnimationFrame ( startContinuousDetection ) ;
206+ requestAnimationFrame ( detect ) ;
187207}
188208
189209function areStableEnough ( barcodes , previous ) {
@@ -223,6 +243,7 @@ function sameBarcodesDetected(currentBarcodeValues, lastBarcodeValues) {
223243}
224244
225245
246+ // Barcode detection function (no drawing)
226247async function detectBarcodes ( ) {
227248 try {
228249 if ( video . readyState === video . HAVE_ENOUGH_DATA ) {
@@ -242,80 +263,116 @@ async function detectBarcodes() {
242263 }
243264 }
244265
245- // Remember current barcodes for next comparison
266+ // Remember current barcodes for next comparison and for drawing
246267 lastDetectedBarcodes = barcodes ;
268+ currentBarcodes = barcodes ;
247269
248- // Clear canvas
249- ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
250-
251- // Display FPS on bottom left
252- ctx . font = '16px Arial' ;
253- const fpsText = `barcode detection took ${ deltaTimeMs . toFixed ( 0 ) } ms` ;
254- const textMetrics = ctx . measureText ( fpsText ) ;
255- const textWidth = textMetrics . width ;
256- const textHeight = 16 ; // Font size
257-
258- // Draw background rectangle based on measured text dimensions
259- ctx . fillStyle = 'rgba(0, 0, 0, 0.8)' ;
260- ctx . clearRect ( 10 , canvas . height - textHeight - 15 , textWidth + 20 , textHeight + 10 ) ;
261- ctx . fillRect ( 10 , canvas . height - textHeight - 15 , textWidth + 20 , textHeight + 10 ) ;
262-
263- // Draw text
264- ctx . fillStyle = '#ffffff' ;
265- ctx . fillText ( fpsText , 20 , canvas . height - 10 ) ;
266-
267- if ( barcodes . length > 0 ) {
268-
269- // Draw center points and text
270- ctx . fillStyle = '#28a745' ;
271- ctx . font = '24px Arial' ;
272-
273- barcodes . forEach ( barcode => {
274- const { cornerPoints} = barcode ;
275-
276- // Add barcode to list if not already present
277- if ( ! scannedBarcodes . has ( barcode . rawValue ) ) {
278- scannedBarcodes . add ( barcode . rawValue ) ;
279- addBarcodeToList ( barcode . rawValue ) ;
280- }
281-
282- // Calculate center point from corner points
283- const center = calculateCenterPoint ( cornerPoints ) ;
284-
285- // Draw center circle with radius 3
286- ctx . beginPath ( ) ;
287- ctx . arc ( center . x , center . y , 3 , 0 , 2 * Math . PI ) ;
288- ctx . fill ( ) ;
289-
290- // Measure text width for proper centering
291- const textMetrics = ctx . measureText ( barcode . rawValue ) ;
292- const textWidth = textMetrics . width ;
293- const textHeight = 24 ; // Font size
294-
295- // Draw black background with 70% opacity
296- ctx . fillStyle = 'rgba(0, 0, 0, 0.7)' ;
297- ctx . fillRect (
298- center . x - textWidth / 2 - 5 ,
299- center . y + 30 - textHeight ,
300- textWidth + 10 ,
301- textHeight + 5
302- ) ;
303-
304- // Draw barcode value text centered below the center point
305- ctx . fillStyle = '#28a745' ;
306- ctx . fillText (
307- barcode . rawValue ,
308- center . x - textWidth / 2 ,
309- center . y + 30
310- ) ;
311- } ) ;
312- }
270+ // Add new barcodes to list
271+ barcodes . forEach ( barcode => {
272+ if ( ! scannedBarcodes . has ( barcode . rawValue ) ) {
273+ scannedBarcodes . add ( barcode . rawValue ) ;
274+ addBarcodeToList ( barcode . rawValue ) ;
275+ }
276+ } ) ;
313277 }
314278 } catch ( error ) {
315279 console . error ( 'Barcode detection error:' , error ) ;
316280 }
317281}
318282
283+ // Separate drawing function that runs at high frequency
284+ function drawBarcodes ( ) {
285+ // Update display positions with tweening
286+ updateDisplayPositions ( ) ;
287+
288+ // Clear canvas
289+ ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
290+
291+ // Display detection timing on bottom left
292+ ctx . font = '16px Arial' ;
293+ const fpsText = `barcode detection took ${ deltaTimeMs . toFixed ( 0 ) } ms` ;
294+ const textMetrics = ctx . measureText ( fpsText ) ;
295+ const textWidth = textMetrics . width ;
296+ const textHeight = 16 ; // Font size
297+
298+ // Draw background rectangle based on measured text dimensions
299+ ctx . fillStyle = 'rgba(0, 0, 0, 0.8)' ;
300+ ctx . fillRect ( 10 , canvas . height - textHeight - 15 , textWidth + 20 , textHeight + 10 ) ;
301+
302+ // Draw text
303+ ctx . fillStyle = '#ffffff' ;
304+ ctx . fillText ( fpsText , 20 , canvas . height - 10 ) ;
305+
306+ if ( displayBarcodes . size > 0 ) {
307+ // Draw center points and text
308+ ctx . fillStyle = '#28a745' ;
309+ ctx . font = '24px Arial' ;
310+
311+ displayBarcodes . forEach ( ( displayData , barcodeValue ) => {
312+ const { displayX, displayY } = displayData ;
313+
314+ // Draw center circle with radius 3
315+ ctx . beginPath ( ) ;
316+ ctx . arc ( displayX , displayY , 3 , 0 , 2 * Math . PI ) ;
317+ ctx . fill ( ) ;
318+
319+ // Measure text width for proper centering
320+ const textMetrics = ctx . measureText ( barcodeValue ) ;
321+ const textWidth = textMetrics . width ;
322+ const textHeight = 24 ; // Font size
323+
324+ // Draw black background with 70% opacity
325+ ctx . fillStyle = 'rgba(0, 0, 0, 0.7)' ;
326+ ctx . fillRect (
327+ displayX - textWidth / 2 - 5 ,
328+ displayY + 30 - textHeight ,
329+ textWidth + 10 ,
330+ textHeight + 5
331+ ) ;
332+
333+ // Draw barcode value text centered below the center point
334+ ctx . fillStyle = '#28a745' ;
335+ ctx . fillText (
336+ barcodeValue ,
337+ displayX - textWidth / 2 ,
338+ displayY + 30
339+ ) ;
340+ } ) ;
341+ }
342+ }
343+
344+ // Update display positions with 50% tweening
345+ function updateDisplayPositions ( ) {
346+ // Get current barcode values for cleanup
347+ const currentBarcodeValues = new Set ( currentBarcodes . map ( b => b . rawValue ) ) ;
348+
349+ // Remove barcodes that are no longer detected
350+ for ( const [ barcodeValue ] of displayBarcodes ) {
351+ if ( ! currentBarcodeValues . has ( barcodeValue ) ) {
352+ displayBarcodes . delete ( barcodeValue ) ;
353+ }
354+ }
355+
356+ // Update positions for current barcodes
357+ currentBarcodes . forEach ( barcode => {
358+ const center = calculateCenterPoint ( barcode . cornerPoints ) ;
359+ const barcodeValue = barcode . rawValue ;
360+
361+ if ( displayBarcodes . has ( barcodeValue ) ) {
362+ // Tween existing position by 50%
363+ const displayData = displayBarcodes . get ( barcodeValue ) ;
364+ displayData . displayX += ( center . x - displayData . displayX ) * 0.2 ;
365+ displayData . displayY += ( center . y - displayData . displayY ) * 0.2 ;
366+ } else {
367+ // New barcode - start at actual position
368+ displayBarcodes . set ( barcodeValue , {
369+ displayX : center . x ,
370+ displayY : center . y
371+ } ) ;
372+ }
373+ } ) ;
374+ }
375+
319376// Barcode list management functions
320377function addBarcodeToList ( barcodeValue ) {
321378 const template = document . querySelector ( '.js-barcode-item-template' ) ;
0 commit comments