FRP-inspired JavaScript

by Kim Maida

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.3/Rx.js"></script>

JavaScript

// create a time observable that adds an item every 1 second
// map so resulting stream contains event values
const time$ = 
  Rx.Observable
    .timer(0, 1000)
    .timeInterval()
    .map(e => e.value);

// create a mouse movement observable
// throttle to every 350ms
// map so resulting stream pushes objects with x and y coordinates
const move$ = 
  Rx.Observable
    .fromEvent(document, 'mousemove')
    .throttleTime(350)
    .map(e => { return {x: e.clientX, y: e.clientY} });

// merge time + mouse movement streams
// complete after 10 seconds
const source$ = 
  Rx.Observable
    .merge(time$, move$)
    .takeUntil(Rx.Observable.timer(10000));

// subscribe to merged source$ observable
// if value is a number, createTimeset()
// if value is a coordinates object, addPoint()
const subscription = 
  source$.subscribe(
    // onNext
    (x) => { 
      if (typeof x === 'number') {
        createTimeset(x);
      } else {
        addPoint(x);
      }
    },
    // onError
    (err) => { console.warn('Error:', err); },
    // onCompleted
    () => { console.info('Completed'); }
  );

// add element to DOM to list out points touched in a particular second
function createTimeset(n) {
  const elem = document.createElement('div');
  const num = n + 1;
  elem.id = 't' + num;
  elem.innerHTML = `<strong>${num}</strong>: `;
  document.body.appendChild(elem);
}

// add points touched to latest time in stream
function addPoint(pointObj) {
  // add point to last appended element
  const numberElem = document.getElementsByTagName('body')[0].lastChild;
  numberElem.innerHTML += ` (${pointObj.x}, ${pointObj.y}) `;
}