1


For teaching myself javascript (and for getting/giving more insight in the field of astronomy :) ), I am setting up a page that displays relative positions of sun and moon. Right now, the speed of the sun and moon movement is still fixed, but I would really like to make this dynamically user-definable via an input field. So, the initial speed is '30', and a user can speed this up or slow this down. Obviously, the ratio between sun and moon must stay fixed. I tried a lot of things (see some relics in the code, but I can't get it to work.

Anyone with more experience with javascript can assist me in doing this? Also, I notice CPU usage gets very high during this animation. Are there simple steps in making this script more efficient?

var dagen = 0;
function speed($this){
 var speedSetting = $this.value;
    //alert(speedSetting);
 //return per;
}
function periode(bolletje, multiplier=30){
 if (bolletje == 'zon'){var per = (multiplier*24/2);}
    if (bolletje == 'maan'){var per = (multiplier*24*29.5/2);}
    return per;
}
function step(delta) {
  elem.style.height = 100*delta + '%'
}
function animate(opts) {
  var start = new Date 
  var id = setInterval(function() {
    var timePassed = new Date - start
    var progress = timePassed / opts.duration
    if (progress > 1) progress = 1
    var delta = opts.delta(progress)
    opts.step(delta)
    if (progress == 1) {
      clearInterval(id)
    }
  }, opts.delay || 10)
   
}
function terugweg(element, delta, duration) {
    var to = -300;
    var bolletje = element.getAttribute('id');
    per = periode(bolletje);
 document.getElementById(bolletje).style.background='transparent';
 animate({
  delay: 0,
  duration: duration || per,
  //1 sec by default
  delta: delta,
  step: function(delta) {
    element.style.left = ((to*delta)+300) + "px"   
  }
 });
    if(bolletje == 'zon'){
     dagen ++;
    }
    bolletje = element;
    document.getElementById('dagen').innerHTML = dagen;
    //setInterval(function (element) {
    setTimeout(function (element) {
  move(bolletje, function(p) {return p})
 }, per);
}
function move(element, delta, duration) {
 var to = 300;
 var bolletje = element.getAttribute('id');
    per = periode(bolletje);
    document.getElementById(bolletje).style.background='yellow';
 animate({
  delay: 0,
  duration: duration || per, 
  //1 sec by default
  delta: delta,
  step: function(delta) {
    element.style.left = to*delta + "px"   
  }
 });
    bolletje = element;
 //setInterval(function (element) {
    setTimeout(function (element) {
  terugweg(bolletje, function(p) {return p})
 }, per);
}
hr{clear: both;}
form{display: block;}
form label{width: 300px; float: left; clear: both;}
form input{float: right;}
.aarde{width: 300px; height: 300px; border-radius: 150px; background: url('https://domain.com/img/aarde.png');}
#zon{width: 40px; height: 40px; background: yellow; border: 2px solid yellow; border-radius: 20px; position: relative; margin-left: -20px; top: 120px;}
#maan{width: 30px; height: 30px; background: yellow; border: 2px solid yellow; border-radius: 16px; position: relative; margin-left: -15px; top: 115px;}
<form>

<div onclick="move(this.children[0], function(p) {return p}), move(this.children[1], function(p) {return p})" class="aarde">
<div id="zon"></div>
<div id="maan"></div>

</div>

Dagen: <span id="dagen">0</span>

</form>


<form>

<label><input id="snelheid" type="range" min="10" max="300" value="30" oninput="speed(this)">Snelheid: <span id="snelheidDisplay">30</span></label>

</form>
SJDS
  • 312
  • 7
  • 19
  • Use `setTimeout()` rather than `setInterval()` to allow speed changes mid-animation - instead of testing whether to call `clearInterval()` you would reverse the test condition and call `setTimeout()` again. `var speedSetting` should be declared outside of the functions, and then used by your calls to `setTimeout()`. – nnnnnn Feb 10 '17 at 02:46
  • I'm sorry, currently I'm not using setTimeout. Using setInterval though, but could you be a little more specific? – SJDS Feb 10 '17 at 02:54

1 Answers1

1

First, change onlick to oninput in speed input tag.

<input id="snelheid" type="number"  value="30" oninput="speed(this)">

And in your speed() function set multiplier = $this.value. multiplier should be global:

var multiplier = 30;
function speed($this){
  console.log($this.value);
    multiplier = $this.value;
    //alert(speedSetting);
    //return per;
}
function periode(bolletje){
    if (bolletje == 'zon'){var per = (multiplier*24/2);}
    if (bolletje == 'maan'){var per = (multiplier*24*29.5/2);}
    return per;
}

Here is an example: https://jsfiddle.net/do4n9L03/2/

Note: multiplier is not speed, it is delay. If you increase it it become slower

mudin
  • 2,672
  • 2
  • 17
  • 45
  • That works very well indeed, thank you! To make the user experience more sensible I changed the speed selector type to "range". Problem now is that the speed only changes when one of the objects 'hits' the wall. With that, actually only the speed of the object that just hit the wall changes, so they are out of sync. – SJDS Feb 10 '17 at 03:46
  • How did you change it? Please show me your updated version – mudin Feb 10 '17 at 04:41
  • Thanks for your reply, I [updated it](https://jsfiddle.net/do4n9L03/4/) with the current code – SJDS Feb 10 '17 at 05:00
  • I recommend you to use `window.requestAnimationFrame();` instead of `setInterval()`. – mudin Feb 10 '17 at 05:08
  • Based on the [documentation here](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) I updated it: [https://jsfiddle.net/do4n9L03/5/]. The frame rate drops to 10-15% (saves CPU, gets jerky though), the problem of failing synchronization is not solved with this. Is this what you meant? – SJDS Feb 10 '17 at 05:17
  • Check this post http://stackoverflow.com/questions/1280263/changing-the-interval-of-setinterval-while-its-running – mudin Feb 10 '17 at 05:23
  • This will help you to change interval synchronously – mudin Feb 10 '17 at 05:24
  • Sorry, I don't get your meaning. Is your link commenting on the question how to change the speed of the two elements moving at the same time? That's what I'm looking for – SJDS Feb 10 '17 at 05:30
  • what you are looking for is changing interval dynamically according to use input, follow the link and it explains how to make it using setTimeout – mudin Feb 10 '17 at 05:45