11<template  lang="html">
22  <div  class =" wrapper" 
3-     <div  class =" inside" 
4-       <!-- 
5-       All DOM elements here are stacked upon each other. 
6-       Order matters! The last element is on top. 
7-       Therefore we don't need `z-index`. 
8-       -->  
9-       <video 
10-         ref =" video" 
11-         v-show =" shouldScan" 
12-         class =" camera" 
13-         autoplay 
14-         muted 
15-         playsinline 
16-       ></video>
17- 
18-       <canvas
19-         ref="pauseFrame"
20-         v-show="!shouldScan"
21-         class="pause-frame"
22-       ></canvas>
23- 
24-       <canvas ref="trackingLayer" class="tracking-layer"></canvas>
25- 
26-       <div class="overlay">
27-         <slot ></slot>
28-       </div>
3+     <!-- 
4+     Note that the order of DOM elements matters. 
5+     It defines the stacking order. 
6+     The first element is at the very bottom, the last element is on top. 
7+     This eliminates the need for `z-index`. 
8+     -->  
9+     <video 
10+       ref =" video" 
11+       v-show =" shouldScan" 
12+       class =" camera" 
13+       autoplay 
14+       muted 
15+       playsinline 
16+     ></video>
17+ 
18+     <canvas ref="pauseFrame" v-show="!shouldScan" class="pause-frame"></canvas>
19+ 
20+     <canvas ref="trackingLayer" class="tracking-layer"></canvas>
21+ 
22+     <div class="overlay">
23+       <slot ></slot>
2924    </div>
3025  </div>
3126</template >
@@ -212,44 +207,51 @@ export default {
212207      } 
213208    }, 
214209
215-     /**  
216-      * The coordinates are based on the original camera resolution but the 
217-      * video element is responsive and scales with space available. Therefore 
218-      * the coordinates are re-calculated to be relative to the video element. 
219-      */  
220-     normalizeLocation (widthRatio , heightRatio , location ) { 
221-       const  normalized  =  {}; 
222- 
223-       for  (const  key  in  location) { 
224-         normalized[key] =  { 
225-           x:  Math .floor (location[key].x  *  widthRatio), 
226-           y:  Math .floor (location[key].y  *  heightRatio) 
227-         }; 
228-       } 
229- 
230-       return  normalized; 
231-     }, 
232- 
233210    repaintTrackingLayer (location ) { 
234211      const  video  =  this .$refs .video ; 
235212      const  canvas  =  this .$refs .trackingLayer ; 
236213      const  ctx  =  canvas .getContext (" 2d"  
237214
215+       //  The visually occupied area of the video element. 
216+       //  Because the component is responsive and fills the available space, 
217+       //  this can be more or less than the actual resolution of the camera. 
238218      const  displayWidth  =  video .offsetWidth ; 
239219      const  displayHeight  =  video .offsetHeight ; 
220+ 
221+       //  The actual resolution of the camera. 
222+       //  These values are fixed no matter the screen size. 
240223      const  resolutionWidth  =  video .videoWidth ; 
241224      const  resolutionHeight  =  video .videoHeight ; 
242225
226+       //  Dimensions of the video element as if there would be no 
227+       //    object-fit: cover; 
228+       //  Thus, the ratio is the same as the cameras resolution but it's 
229+       //  scaled down to the size of the visually occupied area. 
230+       const  largerRatio  =  Math .max ( 
231+         displayWidth /  resolutionWidth, 
232+         displayHeight /  resolutionHeight 
233+       ); 
234+       const  uncutWidth  =  resolutionWidth *  largerRatio; 
235+       const  uncutHeight  =  resolutionHeight *  largerRatio; 
236+ 
237+       const  xScalar  =  uncutWidth /  resolutionWidth; 
238+       const  yScalar  =  uncutHeight /  resolutionHeight; 
239+       const  xOffset  =  (displayWidth -  uncutWidth) /  2 ; 
240+       const  yOffset  =  (displayHeight -  uncutHeight) /  2 ; 
241+ 
242+       const  coordinatesAdjusted  =  {}; 
243+       for  (const  key  in  location) { 
244+         coordinatesAdjusted[key] =  { 
245+           x:  Math .floor (location[key].x  *  xScalar +  xOffset), 
246+           y:  Math .floor (location[key].y  *  yScalar +  yOffset) 
247+         }; 
248+       } 
249+ 
243250      window .requestAnimationFrame (() =>  { 
244251        canvas .width  =  displayWidth; 
245252        canvas .height  =  displayHeight; 
246253
247-         const  widthRatio  =  displayWidth /  resolutionWidth; 
248-         const  heightRatio  =  displayHeight /  resolutionHeight; 
249- 
250-         location =  this .normalizeLocation (widthRatio, heightRatio, location); 
251- 
252-         this .trackRepaintFunction (location, ctx); 
254+         this .trackRepaintFunction (coordinatesAdjusted, ctx); 
253255      }); 
254256    }, 
255257
@@ -288,17 +290,10 @@ export default {
288290
289291<style  lang="css" scoped>
290292.wrapper  {
291-   display flex ; 
292-   flex-flow row  nowrap ; 
293-   justify-content space-around ; 
294-   align-items center ; 
295- } 
296- 
297- .inside  {
298293  position relative ; 
299-   max-width 100%  ; 
300-   max-height 100%  ; 
301294  z-index 0 ; 
295+   width 100%  ; 
296+   height 100%  ; 
302297} 
303298
304299.overlay , .tracking-layer  {
@@ -311,8 +306,8 @@ export default {
311306
312307.camera , .pause-frame  {
313308  display block ; 
314-   object-fit contain ; 
315-   max- width100%  ; 
316-   max- height100%  ; 
309+   object-fit cover ; 
310+   width 100%  ; 
311+   height 100%  ; 
317312} 
318313style >
0 commit comments