Skip to content

Commit 045e640

Browse files
committed
tweening because we can xD
1 parent 0bee03c commit 045e640

File tree

1 file changed

+132
-75
lines changed

1 file changed

+132
-75
lines changed

list-codes-native/index.js

Lines changed: 132 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
167168
let isDetecting = false;
168169
let lastDetectedBarcodes = [];
169170
let 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
172176
function 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

189209
function areStableEnough(barcodes, previous) {
@@ -223,6 +243,7 @@ function sameBarcodesDetected(currentBarcodeValues, lastBarcodeValues) {
223243
}
224244

225245

246+
// Barcode detection function (no drawing)
226247
async 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
320377
function addBarcodeToList(barcodeValue) {
321378
const template = document.querySelector('.js-barcode-item-template');

0 commit comments

Comments
 (0)