brightcove / videojs-thumbnails

A video.js plugin that displays thumbnail images over the scrubber.
Other
168 stars 97 forks source link

Multiple Sprite Sheet Sources #10

Open losmescaleros opened 10 years ago

losmescaleros commented 10 years ago

I had originally tried to use the Video.js Thumbnails plugin with multiple sprite sheets (for example, I had a video that was 3 minutes long, and each sprite sheet contained say 60 seconds worth of thumbnsil.) But it seemed to have a problem switching between img src's propertly. I made the following to solve this problem. It assumes that the sprite sheets are in a 1xn fashion (one row and n columns), and it just checks that the necessary sprite (according to the designated time) is equal to the sprite going to be shown.

videojs.plugin('thumbnails_SpriteSheet', function (options, timeInterval, spritesPerSheet) {
    var div, settings, img, player, progressControl, duration;
    settings = extend({}, defaults, options);
    player = this;                

    // create the thumbnail
    div = document.createElement('div');
    div.className = 'vjs-thumbnail-holder';
    img = document.createElement('img');
    div.appendChild(img);
    img.src = settings['0'].src;
    img.className = 'vjs-thumbnail';
    extend(img.style, settings['0'].style);

    // center the thumbnail over the cursor if an offset wasn't provided
    if (!img.style.left && !img.style.right) {
        img.onload = function () {
            img.style.left = -(img.naturalWidth / 2) + 'px';
        }
    };

    // keep track of the duration to calculate correct thumbnail to display
    duration = player.duration();
    player.on('durationchange', function (event) {
        duration = player.duration();
    });

    // add the thumbnail to the player
    progressControl = player.controlBar.progressControl;
    progressControl.el().appendChild(div);

    // update the thumbnail while hovering
    progressControl.el().addEventListener('mousemove', function (event) {
        var mouseTime, time, active, left, setting;

        active = 0;

        // find the page offset of the mouse
        left = event.pageX || (event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft);
        // subtract the page offset of the progress control
        left -= progressControl.el().getBoundingClientRect().left + window.scrollX;
        div.style.left = left + 'px';

        // apply updated styles to the thumbnail if necessary
        // The following fixes bug where hovering over progress slider resets offset to 0:
        // https://github.com/brightcove/videojs-thumbnails/issues/3
        // start fix
        var relativeX = (event.pageX - $(this).parent().offset().left);
        mouseTime = Math.floor(relativeX / progressControl.width() * duration);
        // end fix

        //mouseTime = Math.floor(event.offsetX / progressControl.width() * duration);            

        for (time in settings) {
            if (mouseTime > time) {
                active = Math.max(active, time);
            }
        }
        setting = settings[active];
        // This is not part of the original video.thumbnails.js code. It was added to work around multiple
        // thumbnail sprite sheets. 300 is the number of seconds in one sprite sheet and is hard-coded. The 
        // following code checks the current img.src against the required src, which should be mouseTime / 300
        // (integer division) multiplied by 300 again.
        var secondsPerSheet = timeInterval * spritesPerSheet;
        var x = Math.floor(mouseTime / secondsPerSheet);
        x = x * secondsPerSheet;
        var sourceNeeded = settings[x];

        if (setting.src && (img.src != setting.src)) {

            img.src = setting.src;
        }
        // This check has been added to make sure that img src being used is the one that is needed.
        if (sourceNeeded.src && (img.src != sourceNeeded.src)) {

            img.src = sourceNeeded.src;
        }
        if (setting.style && img.style != setting.style) {
            extend(img.style, setting.style);
        }
    }, false);
});

I just threw this above the original 'thumbnails' function call and use 'thumbnails_SpriteSheet(...)' instead if that is what I need. timeInterval is the time between sprite sheets (it assumes the interval between sprites is the same), and spritesPerSheet is the number of sprites per sprite sheet. These are used to find how many seconds of video each sprite sheet should contain.

Not very complicated, but hopefully it helps someone.

xbgmsharp commented 10 years ago

Thanks a mix of your solution a+ the original make it work on all browser. See code https://github.com/xbgmsharp/piwigo-videojs/commit/c0bc724a214731496c03d0947d32f3c7b73a3b1a

dmlap commented 10 years ago

Can you provide any details on what exactly was going wrong with switching the img src attributes? There's an example of using a sprited img src in the project itself and I haven't seen any issues there.

losmescaleros commented 10 years ago

It seemed to work fine as long as there was only one source file. However, when I created an object to pass into the thumbnails plugin, I set it up so that different time indices would change src attributes. Scrubbing forward and backward on the seek bar, the src attribute would sometimes get mixed up, so that a sprite from the wrong source would sometimes be shown.