skip to Main Content

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: 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>

2

Answers


  1. If you give your <script> tag the defer keyword (<script defer></script>), it will be run after all of the elements on the DOM have been loaded.

    Login or Signup to reply.
  2. To change the document.addEventListener('DOMContentLoaded', () => {}) in the JavaScript code you provided, you can use the following code:

    const ready = () => {
      // Code that needs to be executed when the DOM is loaded
    };
    
    window.addEventListener('load', ready);
    

    The load event is fired when the entire page has loaded, including all images, scripts, and CSS files. This is a good event to use to initialize your JavaScript code, as it ensures that the DOM is fully loaded and ready to be manipulated.

    Here is an example of how to use the load event to initialize the myvideo code:

    const myvideo = (function (window) {
      // ...
    })();
    
    const ready = () => {
      myvideo.init('/path/to/folder/with/images/and/mp4/');
    };
    
    window.addEventListener('load', ready);
    

    This code will ensure that the myvideo code is not initialized until the entire page has loaded.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search