0
//image sequence functions
//preload array
/**
 * Preload images in a directory.
 * @param {string} baseurl 
 * @param {string} extension
 * @return {Promise} resolve an Array<Image>.
 */
function preloadImages(baseurl, extension, starter) {
    return new Promise(function (res) {
        var i = starter;
        var images = [];
        // Inner promise handler
        var handler = function (resolve, reject) {
            var img = new Image;
            var source = baseurl + i + '.' + extension;
            img.onload = function () {
                i++;
                resolve(img);
            }
            img.onerror = function () {
                reject('Rejected after ' + i + 'frames.');
            }
            img.src = source;
        }
        // Once you catch the inner promise you resolve the outer one.
        var _catch = function () {
            res(images)
        }
        var operate = function (value) {
            if (value) images.push(value);
            // Inner recursive promises chain.
            // Stop with the catch resolving the outer promise.
            new Promise(handler).then(operate).catch(_catch);
        }
        operate();
    })
}

/**
 * Draw an Array of images on a canvas.
 * @param {Canvas} canvas 
 * @param {Array<Image>} imagelist 
 * @param {number} refreshRate 
 */
function play(canvas, imagelist, refreshRate, frameWidth, frameHeight, percentage) {
    // Since we're using promises, let's promisify the animation too.
    return new Promise(function (resolve) {
        // May need to adjust the framerate
        // requestAnimationFrame is about 60/120 fps depending on the browser
        // and the refresh rate of the display devices.
        var ctx = canvas.getContext('2d');
        var ts, i = 0,
            delay = 1000 / refreshRate;
        var roll = function (timestamp) {
            if (!ts || timestamp - ts >= delay) {
                // Since the image was prefetched you need to specify the rect.
                ctx.drawImage(imagelist[i], 0, 0, frameWidth, frameHeight);
                i++;
                ts = timestamp;
            }
            if (i < imagelist.length * percentage)
                requestAnimationFrame(roll);
            else
                resolve(i);
        }
        roll();
    })
}
//combine preload and play into one
function preloadAndPlay(ID, actor, event, percentage) {
    var preload = preloadImages('/static/videos/' + actor + '/Clip_' + event + '/', 'png', 1);
    preload.then(function (value) {
        //console.log('starting play');
        //canvas html5 object with ID
        var canvas = document.getElementById(ID);
        play(canvas, value, 30, 960, 540, percentage) // ~30fps
            .then(function (frame) {
                console.log('roll finished after ' + frame + ' frames.')
            })
    });
}   



$.when(preloadAndPlay('myImage', actor, event, percentage)).done(function(){
        $('.data').click(function () {
            if ($(this).is(':checked')) {
                $(this).removeClass('hidden');
                $(that).addClass('hidden');
            }
            that = this;
        });
        $('.data').change(function () {
            if (('input[name=b]:checked').length) {
                $('#trial_next').prop('disabled', false);
                cbChecked = document.querySelector('[name="b"]:checked').value;
                debug(cbChecked);
            }
        });
    });

I would like the .change and .click jquery to be only enabled after preloadAndPlay javascript function is COMPLETELY done executing. Jquery is are suppose to be allow radio buttons that can be selected. preloadAndPlay is a function that loads a series of images then displays them with html5 canvas so it seems like a video/animation. See above for the preloadAndPlay function that uses promise and recursion. The code works it's just I don't want people to make selection before the video ends. Above is the code I tried.

Alex Ker
  • 55
  • 2
  • 10
  • 1
    Please show the `preloadAndPlay()` function. I take it that it triggers some asynchronous process? If you want to use it with `$.when()` then it should return a promise that you fulfill when the async process completes. (Note that if the function is all synchronous then you don't need `$.when()`, and its being recursive would be irrelevant.) – nnnnnn Aug 18 '17 at 03:47
  • _"I would like the .change and .click jquery to be only enabled after preloadAndLoad javascript function is COMPLETELY done executing."_ , _"Note that preloadAndPlay is a recursive function"_ What is the return value of `preloadAndLoad` function call? See https://stackoverflow.com/help/mcve – guest271314 Aug 18 '17 at 03:50
  • @nnnnnn done. I added more details and explanations. Thanks for helping me again. – Alex Ker Aug 18 '17 at 03:52
  • @guest271314 sorry about that. I added more code and explanations. – Alex Ker Aug 18 '17 at 03:55
  • What is purpose of `operate` function within `Promise` executor function? Note, no value is `return`ed from `operate()` call – guest271314 Aug 18 '17 at 03:56
  • It is for the recursive calls guest271314. that's why it is wrapped in a function. Personally I did not write that proportion. – Alex Ker Aug 18 '17 at 03:58
  • _"Personally I did not write that proportion"_ ? – guest271314 Aug 18 '17 at 03:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152209/discussion-between-alex-ker-and-guest271314). – Alex Ker Aug 18 '17 at 03:59

1 Answers1

0

There are several issue at code at Question. At preloadImages function the parameter at function passed to Promise constructor is named res, though resolve() is called within function at <img> load event, though resolve is undefined within the function. handler is not called, not reaching call to undefined resolve(). operate function within Promise constructor is not necessary. No value is returned from operate, see Why is value undefined at .then() chained to Promise?.

You can use Promise.all() to pass an iterable object where chained .then() should be called when all of the values or Promise values passed are fulfilled.

Not certain what the expected effect of play() call is, nor is that portion of code mentioned as being a part of the original inquiry. Adjusted code at staccksnippets to call requestAnimationFrame for each image.

const baseurl = "https://lorempixel.com/50/50/";

const data = ["cats", "nature", "city"];

const canvas = document.querySelector("canvas");

function preloadImages(image) {
  return new Promise(function(resolve) {
    var img = new Image;
    var source = baseurl + image;
    img.onload = function() {
      resolve(img);
    }
    img.onerror = function() {
      reject('Rejected after ' + i + 'frames.');
    }
    img.src = source;
  })
}

function play(canvas, imagelist, refreshRate, frameWidth, frameHeight, percentage) {
  // Since we're using promises, let's promisify the animation too.
  return new Promise(function(resolve) {
    // May need to adjust the framerate
    // requestAnimationFrame is about 60/120 fps depending on the browser
    // and the refresh rate of the display devices.
    var ctx = canvas.getContext('2d');
    var ts, i = 0,
      delay = 1000 / refreshRate;
    var roll = function(timestamp) {
      if (!ts || timestamp - ts >= delay) {
        // Since the image was prefetched you need to specify the rect.
        ctx.drawImage(imagelist[i], 0, 0, frameWidth, frameHeight);
        i++;
        ts = timestamp;
      }
      if (i < imagelist.length /* * percentage */ )
        requestAnimationFrame(roll);
      else
        resolve(i);
    }
    roll();
  })
}

function preloadAndPlay(percentage) {
  var preload = Promise.all(data.map(preloadImages))
    .then(function(images) {
      console.log("preloadImages complete, images:", images);
      images.forEach(function(img) {
        document.body.appendChild(img)
      });
      return images
    })
    .catch(function(err) {
      console.error(err);
      throw err;
    });
  return preload.then(function(value) {
    console.log("preload complete, value:", value);
    return play(canvas, value, 30, 960, 540, percentage) // ~30fps
      .then(function(frame) {
        console.log('roll finished after ' + frame + ' frames.');
        return "done";
      })
  });
}

preloadAndPlay()
.then(function(data) {
  console.log(data);
})
  .catch(function(err) {
    console.error(err)
  })
<canvas></canvas>
guest271314
  • 1
  • 15
  • 104
  • 177