Reactive Extensions for Javascript – Wikipedia lookup demo

Matthew Podwysocki posted a couple of very good articles on RxJS on codebetter.com and amongst them was a simple demo to do a look up on wikipedia using their open API:

Introduction to the Reactive Extensions for JavaScript – Wikipedia Lookup

Unfortunately, there wasn’t a live demo you can play around with and see it work, and since the article was posted things might have changed and doing cross-domain HTTP requests are no longer a straightforward affair (at least not when it comes to Chrome and Firefox). If you had tried to piece together all the bits of code snippets from the article you might find that it only works in IE but not in Chrome or Firefox.

So I decided to put together a working demo, and with that, let’s start with the HTML from the original example:

   1: <body>

   2:     <div id="wrapper">

   3:         <input id="search-input" size="100" type="text" placeholder="Enter Search Phrase" />

   4:         <ul id="results" />

   5:         <p id="error" />

   6:     </div>

   7: </body>

And the Javascript which had been slightly modified from those shown in the article:

   1: <script type="text/javascript">

   2:     function searchWiki(term) {

   3:         // note the callback=? clause at the end, which is required to make 

   4:         // cross-domain request possible in chrome and firefox

   5:         var url = "http://en.wikipedia.org/w/api.php?action=opensearch&search=" + 

   6:                     term + "&format=json&callback=?";

   7:  

   8:         // note that I'm using getJSONAsObservable instead of XMLHttpRequest

   9:         return $.getJSONAsObservable(url)

  10:                 .Select(function (result) {

  11:                     if (result.data && result.data.length == 2) {

  12:                         return result.data[1];

  13:                     }

  14:                     else {

  15:                         return [];

  16:                     }

  17:                 });

  18:     }

  19:  

  20:     $(function () {

  21:         var searcher = $("#search-input");

  22:  

  23:         var searchTerms = 

  24:             searcher.toObservable("keyup")     // hook up the keyup event on the search box

  25:                     .Throttle(250)             // ignore values entered within 250ms of each other

  26:                     .Select(function () {      // return what's in the search box

  27:                         return searcher.val();

  28:                     });

  29:  

  30:         var searchResults = searchTerms.Select(function (term) { return searchWiki(term); }).Switch();

  31:  

  32:         searchResults.Subscribe(function (data) {

  33:             $("#results").empty();

  34:             $.each(data, function (_, value) {

  35:                 $("#results").append("<li>" + value + "</li>");

  36:             })

  37:         }, function (errr) {

  38:             $("#error").html(error);

  39:         });

  40:     });

  41: </script>

Key things to note here:

  • line 6, at the end of the url I added &callback=? which is the standard way to specify a JSONP callback with jQuery‘s getJSON function.
  • line 9, I used getJSONAsObservable, which is the same as getJSON but returns the values as an observable sequence

Demo

Reactive Extensions for Javascript – Multiple observers for multiple observables

One of the great things about the Reactive Extensions for Javascript is that you can easily create a many-to-many relationship between observable sequences of values and observers who handles the arrival of new values.

You should have a read of these couple of posts first:

To take it a step further from the brief code snippets shown in the blog posts by Matthew Podwysocki above, here’s a quick demo on how you can create multiple observable sequences of values and have multiple observers observe them.

So first, a simple set of HTML to create a couple of spans:

   1: <body>

   2:     <div id="wrapper">

   3:         <span id="message" class="block"></span>

   4:         <span id="error" class="block"></span>

   5:         <span id="complete" class="block"></span>

   6:  

   7:         <span id="message-2" class="block"></span>

   8:     </div>

   9: </body>

And the Javascript:

   1: <script type="text/javascript" src="js/jquery/jquery-1.4.4.min.js"></script>

   2: <script type="text/javascript" src="js/rxjs/rx.js"></script>

   3: <script type="text/javascript" src="js/rxjs/rx.jQuery.js"></script>

   4:  

   5: <script type="text/javascript">

   6:     $(function () {

   7:         var wrapperElement = $("#wrapper"),

   8:             messageElement = $("#message"),

   9:             messageElement2 = $("#message-2"),

  10:             errorElement = $("#error"),

  11:             completeEelement = $("#complete");

  12:  

  13:         /********** 1ST OBSERVER (EXPLICIT) ************/

  14:         var observer = Rx.Observer.Create(

  15:             function (next) { // when next value is fired

  16:                 messageElement.html("Next: " + next);

  17:             },

  18:             function (err) { // on error

  19:                 errorElement.html("Error: " + err);

  20:             },

  21:             function () { // on complete

  22:                 completeEelement.html("Complete!");

  23:             });

  24:  

  25:         // an observable that starts from 0 and increments by 1 per second

  26:         var counter = Rx.Observable.GenerateWithTime(

  27:             0,                                  // initial state

  28:             function (x) { return true; },      // condition

  29:             function (x) { return x + 1; },     // iterator

  30:             function (x) { return x },          // select

  31:             function (x) { return x === 0 ? 0 : 1000 }); // time (1s) between each value

  32:  

  33:         // an observable sequence which just throws an exception

  34:         var except = Rx.Observable.Throw("FAIL!");

  35:  

  36:         // an observable sequence which completes straight away

  37:         var complete = Rx.Observable.Return();

  38:  

  39:         // get reference to the disposable objects to unsubscribe later

  40:         var counterSub = counter.Subscribe(observer);

  41:         var exceptSub = except.Subscribe(observer);

  42:         var completeSub = complete.Subscribe(observer);

  43:  

  44:         /********** 2ND OBSERVER (IMPLICIT) ************/

  45:         var counterSub2 = counter.Subscribe(function (next) {

  46:             messageElement2.html(next);

  47:         });

  48:  

  49:         // unsubscribe the first observer's counter subscription after 10 seconds

  50:         setTimeout(function () { counterSub.Dispose() }, 10000);

  51:     });

  52: </script>

The key things to note here are the two ways you can create an observer, either explicitly using the Rx.Observer.Create function or creating one dynamically using one of the overloaded Subscribe functions on an observable sequence.

When you call Subscribe on an observable, you get back a disposable object which can then be used to unsubscribe an observer from an ongoing observable sequence (see line 50 in the code above and the demo below).

Demo

Drag and Drop using Reactive Extensions for Javascript

Been a while since I’ve been meaning to check out Reactive Extensions for Javascript, I have been using the .Net version for a while now and blogged about some of the cool things you can do with the .Net version.

Although there are many sources where you can learn about it from they don’t have a structured guide to help you get started and some of the info/demo I found were pretty out-dated and not in line with the latest API. Among the articles I’ve read so far I found the series of articles by Matthew Podwysocki on codebetter.com to be most useful and definitely worth reading through if you want get up to speed with RXJS.

Anyways, back to the point of the post, I just wanted to show you how to achieve a simple drag and drop effect using RX, with support for clipping so you can’t drag the outside the parent container.

Here’s the basic HTML for the demo and with some simple CSS how it looks:

   1: <body>

   2:     <div id="wrapper">

   3:         <div id="draggable"></div>

   4:     </div>

   5: </body>

image

The javascript code for the demo is simple:

   1: <script type="text/javascript" src="js/jquery/jquery-1.4.4.min.js"></script>

   2: <script type="text/javascript" src="js/rxjs/rx.js"></script>

   3: <script type="text/javascript" src="js/rxjs/rx.jQuery.js"></script>

   4:

   5: <script type="text/javascript">

   6:     $(function () {

   7:         var _doc = $(document), _draggable = $("#draggable"), _wrapper = $("#wrapper");

   8:

   9:         // boundary so that the draggable content can't move outside of the its container

  10:         var _parent = _draggable.parent(),

  11:             _parentOffset = _parent.offset(),

  12:             _minLeft = _parentOffset.left,

  13:             _minTop = _parentOffset.top,

  14:             _maxLeft = _minLeft + _parent.width() - _draggable.outerWidth(),

  15:             _maxTop = _minTop + _parent.height() - _draggable.outerHeight();

  16:

  17:         // get the stream of events from the mousedown, mousemove and mouseup events

  18:         var mouseDown = _draggable.toObservable("mousedown"),

  19:             mouseMove = _doc.toObservable("mousemove"),

  20:             mouseUp = _doc.toObservable("mouseup");

  21:

  22:         // get the changes in the X and Y direction as the mouse moves

  23:         var mouseMoves = mouseMove.Skip(1).Zip(mouseMove, function (left, right) {

  24:             return {

  25:                 xChange: left.clientX - right.clientX,

  26:                 yChange: left.clientY - right.clientY

  27:             };

  28:         });

  29:

  30:         // for each mouse down event, get all the subsequent changes in the clientX and

  31:         // clientY values resulting from the mouse move events until mouse up event occurs

  32:         var mouseDrags = mouseDown.SelectMany(function (md) {

  33:             return mouseMoves.TakeUntil(mouseUp);

  34:         });

  35:

  36:         mouseDrags.Subscribe(function (mouseEvent) {

  37:             var oldOffset = _draggable.offset();

  38:

  39:             // change the left and top

  40:             _draggable.css({

  41:                 left: Math.min(Math.max(oldOffset.left + mouseEvent.xChange, _minLeft), _maxLeft),

  42:                 top: Math.min(Math.max(oldOffset.top + mouseEvent.yChange, _minTop), _maxTop)

  43:             });

  44:         });

  45:     });

  46: </script>

As you can see, this example uses jQuery and included in the RXJS package is a rx.jQuery.js file which contains a number of extension methods to use with jQuery such as the toObservable function which returns a stream of observable values. If this sounds unfamiliar to you I strongly recommend you to read through the first couple of articles by Matthew Podwysocki I linked above.

On line 23, I’m created a composite event stream by pairing mouse move events with their subsequent mouse move event to work out the change in the X and Y direction. To visualise the two event streams and the resultant mouseMoves stream:

image

Then on line 36, I’ve subscribed an event handler for values pushed down to us through the mouseMoves stream. This event handler applies the X and Y changes to the <div> element’s left and top offset but caps them so that it can only be moved inside its container.

Demo

Parting thoughts

I used jQuery to demonstrate RXJS’s extension functions for jQuery but you don’t need jQuery in order to use RXJS, in the rx.html.js script file there is a very useful Rx.Observable.FromHTMLEvent function which lets you get an observable stream of events from any HTML events including IE-specific events such as ‘oncut‘.

Test your maths skills at the MathDOJO!

Another productive weekend bares fruit for another mini game! This time I’ve put together a dojo-themed mini game whose sole purpose is to test your ability to do simple (well, mostly) arithmetic calculations in your head and your tolerance for my sense of humour (which is not so bad I hope ;-) ).

Screenshots

Here’s some screenshots taken from the game:

image

image

image

image

image

image

image

As you can see, the main game loop is simple: see some dialogue from your opponent, he asks a question, you answer, if you answer correctly within time then your opponent loses health point, when the opponent’s HP is depleted then you’ve defeated him and move onto the next opponent.

So far there’re 7 opponents in the game, each with his own set of dialogues and questions become progressively harder, your score is tracked and you can get a big bonus in score if you answer the questions quickly (and correctly of course!) and manage to string together a succession of correct answers! As the opponents become tougher, their questions will yield greater scores too, and not to mention they’ll be harder to beat as they have a higher HP value which means you have more chance to better your all-time top score!

Game Flow

Without going through all the steps of making the game (maybe I’ll do that at a later date), the basic flow of the game goes something like this:

image

The tricky thing is then how do you control this flow easily so that depending on the state you’re in the right action is triggered when the play presses the ENTER key.

In the end I settled for a mechanism where the DOM‘s onkeydown event is handled by this bit of code:

   1: // hook up the onkeydown event to execute the 'next' action whatever it might be

   2: document.onkeydown = function(event) {

   3:     if (event.keyCode == 13) {

   4:         nextAction();

   5:     }

   6: };

The nextAction variable is updated at each step of the game loop so that when the player presses the ENTER key the game does the right thing. The only deviation from this pattern is when I try to get the answer from a player, because there’s a time restriction on answering the questions I needed to set up a timer so that when it times out it’ll trigger the state transition as well.

Play

You can play the game at:

http://mathdojo.theburningmonk.com

or via the shortened link:

http://LNK.by/fgzcu

Enjoy! Do let me know if you have any suggestions, difficulty level, etc. etc.

Creating a count down meter with CSS3 and JQuery

Whilst working on the MathDOJO mini game one of the neat little things I tried to do was implement a time meter which steadily counts down and changes colour (from green to yellow to glowing red) as it approaches 0:

image

image

image

First, you need something to represent the meter, a simple <span> element will do:

   1: <body>

   2:     <span id="count-down-meter"></span>

   3: </body>

Then you need CSS to define its colour (and glow effect using CSS3 animation which for now, is only supported by webkit browser unfortunately) at different stages

   1: /* define the animation (webkit-only) */

   2: @-webkit-keyframes redPulse

   3: {

   4:     from { -webkit-box-shadow: 0 0 9px #f00; }

   5:     50% { -webkit-box-shadow: 0 0 18px #f00; }

   6:     to { -webkit-box-shadow: 0 0 9px #f00; }

   7: }

   8:

   9: /* initial state of the meter */

  10: #count-down-meter

  11: {

  12:     display: block;

  13:     width: 100%;

  14:     height: 15px;

  15:     margin-top: 10px;

  16:     background-color: #0f0;

  17: }

  18:

  19: /* change color at midway */

  20: #count-down-meter.middle

  21: {

  22:     background-color: #ff0;

  23: }

  24:

  25: /* change colour and play animation when it's on its last leg */

  26: #count-down-meter.lastleg

  27: {

  28:     background-color: #f00;

  29:     -webkit-animation-name: redPulse;

  30:     -webkit-animation-duration: 2s;

  31:     -webkit-animation-iteration-count: infinite;

  32: }

The animation itself is handled by Javascript, using JQuery’s animate method:

   1: function start() {

   2:         // change to yellow when 40% way through

   3:     var midWidth = meter.width() * 0.6,

   4:         // change to glowing red when 70% way through

   5:         lastlegWidth = meter.width() * 0.3;

   6:

   7:     meter.animate({

   8:         width: 0 + "px",

   9:     }, {

  10:         duration: 5000,

  11:         easing: "linear",

  12:         step: function(now, fx) {

  13:             if (now <= midWidth) {

  14:                 meter.addClass("middle");

  15:

  16:                 if (now <= lastlegWidth) {

  17:                     meter.addClass("lastleg");

  18:                 }

  19:             }

  20:         }

  21:     });

  22: };

To reset the state changes to the meter afterwards, it’s easiest to remove the “style” attribute as JQuery applies the changes through the “style” attribute, which can be a problem if you had manually inserted style in your HTML:

   1: function reset() {

   2:     meter.stop()

   3:          .removeAttr("style")

   4:          .removeClass("middle")

   5:          .removeClass("lastleg");

   6: };

Here’s a live demo:

So that’s it, nice and easy! Enjoy! Hope you find some good use for it.