Skip to content

Instantly share code, notes, and snippets.

@subhaze
Last active April 18, 2016 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save subhaze/27a6098b8fb3bc277ec092e67e9cd5a8 to your computer and use it in GitHub Desktop.
Save subhaze/27a6098b8fb3bc277ec092e67e9cd5a8 to your computer and use it in GitHub Desktop.
RxJS Sequence Memory
<div class="wrapper">
<!-- buttons generated by js -->
</div>
<script>
console.log('from html')
</script>
console.clear() // clear out the console on each save/update in codepen
var percussion = new Percussion();
percussion.setAutoScroll(false);
percussion.stop();
// ------------
// DOM Helpers
// ------------
function childIndexOf(element){
return [].indexOf.call(element.parentNode.children, element);
}
const createAndAddButton = (function(){
let wrapper = $('.wrapper');
return () => {
let btn = $('<button/>');
let indx = wrapper.children().length;
btn.attr('data-indx', indx);
btn.css({opacity: 0});
btn.html(indx);
wrapper.append(btn);
return btn;
};
}());
// ------------
// RxJS Helpers
// ------------
function delegate(wrapper, selector, eventName){
return Rx.Observable.fromEvent(
$(wrapper),
eventName,
e => ({ event:e, delegate:e.target.closest(selector) })
).filter(x => x.delegate !== null);
}
// Generate a stream of numbers from an array and then randomize them.
const correctSequence$ = Rx.Observable
.fromArray(_.shuffle(_.range(0, 6)));
percussion.addStream(correctSequence$);
// Hold streams within array to retrieve length later on
const correctSequenceArray$ = correctSequence$.toArray();
// log sequence as array to console (to get answer...)
correctSequenceArray$
.subscribe(n => console.log(n));
// build out button UI
correctSequence$.forEach(createAndAddButton);
const animation$ = correctSequence$
.flatMap( (itemIndx, indx) => {
let elm = $('.wrapper').children().eq(itemIndx);
return Rx.Observable.fromPromise(
$.when(elm.delay(indx * 750).fadeTo(500, 1))
);
}).share();
percussion.addStream(animation$);
// On the last animation trigger the done.
animation$.last()
.subscribe(()=>console.log('Animation Stream Completed'));
// create a stream of button clicks
const buttonClicks$ = delegate('.wrapper', 'button', 'click');
buttonClicks$.subscribe(e => e.delegate.disabled = true);
percussion.addStream(buttonClicks$);
// map the stream of button clicks to their child index
const buttonClicksIndex$ = buttonClicks$
.map(e => childIndexOf(e.delegate));
// buffer the clicks into sets of the array length
// then check if the sequence of clicks match the
// sequence from array (mapping to a list of true/false values)
const buttonSequence$ = correctSequenceArray$.flatMap(arr => {
return buttonClicksIndex$
.windowWithCount(arr.length)
.flatMap(btnClick => btnClick.sequenceEqual(correctSequence$))
});
percussion.addStream(buttonSequence$);
// Track the number of clicks the user has made and group
// them into a set based on length of sequence
const buttonsClickCount$ = correctSequenceArray$
.flatMap(arr => buttonClicks$.bufferWithCount(arr.length));
percussion.addStream(buttonsClickCount$);
// filter the buffered squence of clicks based on
// whether the sequece was successfully entered (filter for 'true')
const buttonSequenceCorrect$ = buttonSequence$
.takeUntil(buttonsClickCount$)
.filter(equal => equal);
percussion.addStream(buttonSequenceCorrect$);
// Naming is hard...
const sequenceCorrectAndClicks$ =
// ZIP!!!!
Rx.Observable.zip(buttonSequence$, buttonsClickCount$);
percussion.addStream(sequenceCorrectAndClicks$);
// array of results
// 0: is boolean if squence was correct
// 1: is list of the clicks made
sequenceCorrectAndClicks$
.subscribe( (results) => {
alert(`Sequence correct: ${results[0]}`);
results[1].forEach(e => e.delegate.disabled = false);
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://rawgit.com/grisendo/Percussion/master/dist/Percussion.min.js"></script>
*{
box-sizing: border-box;
}
html,body{
width: 100%;
height: 100%;
}
body{
padding: 20px;
}
.wrapper{
height: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
flex-flow: row wrap;
align-content: center;
button{
width: 33.333333333%;
box-sizing: border-box;
padding: 20px 0;
display: inline-block;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment