Search code examples
javascriptjqueryanimationjquery-ui-slider

Programmatically animating a JQuery Slider


I'm trying to programmatically change/animate a JQuery slider. In this example there are two arrays: one for the value to be changed and one for the duration between changes. If you look at the console you will see the values changing along with the corresponding duration. However, the slider doesn't move until it reaches the final value. I'm also trying to update the sliderValue span element as well. Again, it only changes with the last value. See the JSFiddle example (console log) for a demonstration. The slider should start at 100 and slide up to 105 using the duration array.

let valueArray = [101, 102, 103, 104, 105]
let durationArray = [800, 600, 550, 700, 300]
$("#sliderValue").html(100)
$("#slider").slider({
  value: 100,
  min: 0,
  max: 200,
  step: 1,
  slide: function(event, ui) {
    $("#sliderValue").html(ui.value);
  }
});

function pausecomp(millis, value) {
  var date = new Date();
  var curDate = null;
  do {
    curDate = new Date();
  }
  while (curDate - date < millis);
  console.log(value)
  $('#sliderValue').html(value)
  $("#slider").slider("option", "value", value);
}

function startSlider() {
  $("#sliderValue").html(100);
  $("#slider").slider("option", "value", 100);
  for (var i = 0; i < valueArray.length; i++) {
    pausecomp(durationArray[i], valueArray[i]);
  }
}

HTML:

  <h1>Setting Slider Programmatically</h1>
  <div id="slider"></div>
  <p>Slider Value<span id="sliderValue"></span></p>
  <input type="button" value="Start Slider Animation" onclick="startSlider()">

Jsfiddle example


Solution

  • The do..while loop constantly runs while 'waiting', utilizing the CPU (one core) to a hundred percent. jQuery apparently uses asynchronous logic internally, but the while loop doesn't permit the JS event loop to trigger it, only after it has finished.

    So you have to use asynchronous logic, too. For example with the classic setTimeout to the more modern async/await using a little 'sleep' helper function.

    let valueArray = [101, 102, 103, 104, 105]
    let durationArray = [800, 600, 550, 700, 300]
    $("#sliderValue").html(100)
    $("#slider").slider({
      value: 100,
      min: 0,
      max: 200,
      step: 1,
      slide: function(event, ui) {
        $("#sliderValue").html(ui.value);
      }
    });
    
    waitUntil = 0;
    
    function pausecomp(millis, value) {
      setTimeout(function() {
        console.log(value)
        $('#sliderValue').html(value)
        $("#slider").slider("option", "value", value);
      }, waitUntil += millis)
    }
    
    function startSlider() {
      console.clear()
      $("#sliderValue").html(100);
      $("#slider").slider("option", "value", 100);
      waitUntil = 0;
      for (var i = 0; i < valueArray.length; i++) {
        pausecomp(durationArray[i], valueArray[i]);
      }
    }
    
    function sleep(millis) {
      console.log('Sleep ' + millis)
      return new Promise(resolve => setTimeout(resolve, millis));
    }
    
    async function pausecompAsync(millis, value) {
      await sleep(millis);
      console.log(value)
      $('#sliderValue').html(value)
      $("#slider").slider("option", "value", value);
    }
    
    async function startSliderAsync() {
      console.clear()
      $("#sliderValue").html(100);
      $("#slider").slider("option", "value", 100);
      for (var i = 0; i < valueArray.length; i++) {
        await pausecompAsync(durationArray[i], valueArray[i]);
      }
      console.clear()
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.min.js"></script>
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css" />
    
    <div id="slider"></div>
    
    <p>Slider Value<span id="sliderValue"></span></p>
    
    <input type="button" value="Start Slider Animation" onclick="startSlider()">
    <input type="button" value="Start Slider Animation using async/await/Promise" onclick="startSliderAsync()">