Tuesday, 31 October 2023

How can I resolve this DOMContentLoaded or addEventListener issue?

This is a finicky issue and may be difficult to figure out.

This JavaScript controls the intro, play and stop/start of an mp4 video. Most of the code has to do with the video playback and position of the navigation images and links, and isn't really relevant to this question.

The problem that I need to track down is that on initial page load, sometimes the canvas div is hidden by the display:none in the <video> tag and the video start and canvas div is blank. This doesn't happen all the time; it happens less often in Firefox, but most of the time in Chrome. A mouse click in the blank canvas div will show the video and introstill.png. A hard refresh will sometimes bring up the video start image in the canvas div.

I'm thinking it has something to do with the way the function at the end of the script is constructed with myvideo.init and maybe breaks addEventListener, but I don't know.

I see the issue in both an .html file in localhost and on the live server. I've tried wrapping the whole function in jQuery('document').ready(function() with no luck. I've tried disabling caching of the mp4 at the webhost. There are no browser console errors, and no browser add-ons conflicting.

As per @titus' comment: how would I change document.addEventListener('DOMContentLoaded', () => { ?

And, I don't know enough JavaScript to strip out the irrelevant code to make a minimal reproducible example of addEventListener or DOMContentLoaded.

<script>

    var myvideo = (function (window) {
        var app = {};
    
        var buttonBg_out = new Image();
        var buttonBg_over = new Image();
        var nextText = new Image();
        var beginText = new Image();
        var startAgain = new Image();
        var introStill = new Image();
        var pauseOverlay = new Image();
        
        var REAL_WIDTH = 656;
        var REAL_HEIGHT = 386;
        var ASPECT_RATIO = REAL_WIDTH / REAL_HEIGHT;
        var SCALE = 1.0;
    
        app.init = function (root) {
        buttonBg_out.src = root + 'button-out.png';
        buttonBg_over.src = root + 'button-over.png';
        nextText.src = root + 'next.png';
        beginText.src = root + 'begin.png';
        startAgain.src = root + 'startagain.png';
        introStill.src = root + 'introstill.png';   
        pauseOverlay.src = root + 'pauseoverlay.png';
    
        var document = window.document;
    
        document.addEventListener('DOMContentLoaded', () => {          // addEventListener
            var video = document.getElementById('myvid');
            var canvas = document.getElementById('playbackcontainer');
    
            var ctx = canvas.getContext('2d');
                
            introStill.onload = () => {
            ctx.drawImage(introStill,0,31,introStill.width,introStill.height);
            };
    
            var rescaling = function () {
            SCALE = canvas.clientWidth / REAL_WIDTH;
            setTimeout(rescaling, 10);
            };
            rescaling();
            
            var drawVideo = function () {
            if (video.paused || video.ended) return;
    
            ctx.drawImage(video,0,0,canvas.width,canvas.height);
            drawButton();
            setTimeout(drawVideo,1); // might fiddle with this timeout;
            };
            
            var button = {x:0,y:0,
                  w:127,
                  h:66,
                  state: buttonBg_out,
                  text: beginText,
                  visible: false
                 };
            
            var localXY = function (e) {
            var rect = canvas.getBoundingClientRect();
            var x = e.clientX - rect.left;
            var y = e.clientY - rect.top;
            return {x:x,y:y};
            };
            
            var isOverButton = function (e) {
            var xy = localXY(e);
            var x = xy.x;
            var y = xy.y;
    
            return (x >= (button.x * SCALE) && y >= (button.y * SCALE) &&
                x <= ((button.x + button.w)*SCALE) &&
                y <= ((button.y + button.h)*SCALE));
            };
            
            var drawButton = function () {
            if (button.visible) {
                ctx.drawImage(button.state,
                      button.x ,button.y ,
                      button.w ,button.h );
                
                ctx.drawImage(button.text,
                      (button.x + 14) ,
                      (button.y + 23) ,
                      button.text.width ,
                      button.text.height );
            }
            };
            
            var isOverStartOver = function (e) {
            var xy = localXY(e);
            return xy.x >= 9*SCALE && xy.x <= 92*SCALE && xy.y >= 367*SCALE && xy.y <= 379*SCALE;
            };
            
            var isOverReplayScene = function (e) {
            var xy = localXY(e);
            return xy.x >= 102*SCALE && xy.x <= 186*SCALE && xy.y >= 367*SCALE && xy.y <= 379*SCALE;
            };
            
            var permissionGiven = false;
            
            var currentScene = 0;
            var sceneBounds = [{start:4.583, showButton:13.849,
                    loopStart:15.116, loopEnd:22.183,
                    afterPress:23.416},
                       
                       {start:25.649, showButton:53.416,
                    afterPress: 55.983},
                       
                       {start:58.216, showButton:99.0,
                    afterPress:100.483},
                       
                       {start:103.649, showButton:156.149,
                    afterPress:156.816},
                       
                       {start:159.049, showButton:229.883,
                    loopStart:230.5, loopEnd:236.383,
                    afterPress:242.00}];
            
            video.addEventListener('play', drawVideo, false);
            video.addEventListener('timeupdate', () => {
            var bounds = sceneBounds[currentScene];
            
            if (video.currentTime >= bounds.showButton) {
                button.visible = true;
                drawButton();
            }
            
            if (bounds.loopEnd != null) { // keep playing
                if (video.currentTime >= bounds.loopEnd) {
                video.currentTime = bounds.loopStart;
                }
            } else if (video.currentTime >= bounds.showButton) {        // pause
                video.pause();
            }
            });
            
            canvas.addEventListener('mousemove', (e) => {
            if (isOverButton(e)) {
                button.state=buttonBg_over;
                drawButton();
            } else {
                button.state=buttonBg_out;
                drawButton();
            }
            });
            
            canvas.addEventListener('mousedown', (e) => {
            if (!permissionGiven)
            {
                permissionGiven = true;
                video.currentTime = sceneBounds[0].start;
                video.play();
                button.x = 322;
                button.y = 244;
    
            } else {
    
                if (video.paused && currentScene > 0 && currentScene < 4 && !isOverButton(e)) {
                if (isOverStartOver(e)) {
                    video.currentTime = sceneBounds[0].start;
                    button.visible = false;
                    button.x = 322;
                    button.y = 244;
                    button.text = beginText;
                    currentScene = 0;
                    video.play();
                } else if (isOverReplayScene(e)) {
                    button.visible = false;
                    video.currentTime = sceneBounds[currentScene].start;
                    video.play();
                } else {
                    video.play();
                }
    
                } else if (currentScene == 4 && !isOverButton(e)) {
    
                if (isOverStartOver(e)) {
                    button.visible = false;
                    video.currentTime = sceneBounds[currentScene].start;
                    video.play();
                }
    
                } else if (button.visible && isOverButton(e)) { // button was presssed
                
                currentScene = (currentScene +  1) % sceneBounds.length;
                
                if (currentScene == 0)
                {
                    button.text = beginText;
                    video.currentTime = sceneBounds[currentScene].start;
                    button.x = 322;
                    button.y = 244;
                } else {
                    button.text = nextText;
                    button.x = 515;
                    button.y = 304;
                    video.currentTime = sceneBounds[currentScene-1].afterPress;
                }
                
                if (currentScene == 4)
                    button.text = startAgain;
                
                button.visible = false;
                
                video.play();
    
                } else if (video.paused) {
                video.play();
                } else {
                video.pause();
                ctx.drawImage(pauseOverlay,0,0,canvas.width,canvas.height);
                }
            }
            });
        });
        };
        return app;
    })(window);
    
    (function(){
    var thevid = document.getElementById("myvid");
    myvideo.init("/path/to/folder/with/images/and/mp4/");
    })();
    
    </script>
    
    <div class="flex-video">
    <video id="myvid" style="display:none;" playsinline>
    <source src="/path/to/folder/with/images/and/mp4/the_video.mp4" type="video/mp4"/></video>
    <canvas id="playbackcontainer" width="656" height="386"></canvas>
    </div>


from How can I resolve this DOMContentLoaded or addEventListener issue?

No comments:

Post a Comment