Return key binding for Knockout.js

I’ve become a big fan of Knockout.js for building dynamic web interfaces. It’s one of the most “magical” frameworks I’ve seen since jQuery and Node.js, in that it’s great at what it does and makes building complex model/view interactions a breeze. Knockout provides a clean and quick event binding scheme, which allows you to work faster and write less code. However, making things faster and cleaner leads to… wanting even more speed and cleanliness!

So it was that I got tired of writing clunky controller scripts for managing text field input submission when the RETURN key is pressed. This seemed like an excellent opportunity to expand upon the Knockout framework to simplify this redundant task.

Here it is, just paste this into your project script somewhere after the Knockout.js include:

/**
* RETURN key binding for Knockout.js
*/
ko.bindingHandlers.returnKey = {
 init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
 ko.utils.registerEventHandler(element, 'keydown', function(evt) {
 if (evt.keyCode === 13) {
 evt.preventDefault();
 evt.target.blur();
 valueAccessor().call(viewModel);
 }
 });
 }
};

Once you’ve included that extension in your page’s JavaScript, you’ll now have a “returnKey” data binding available. You can use it like this:

<input type="text" data-bind="value:message, returnKey:send"/>
<button data-bind="click:send">Send</button>
That's it!

Thematic Maps with Polygon Overlays

I’ve been building several data visualization maps recently for a variety of clients. In each case, the client has been looking for standard thematic choropleth maps where statistics are illustrated by shades of color among the map locations (ie: countries, states, etc). A few years ago we would have done this with Flash. Now though, there are several options for building JavaScript-based thematic maps using platforms like Google Maps or MapBox.

There are generally two approaches to creating thematic maps in HTML5: either create a pre-rendered tile set with all of your location data rendered into the map tiles and load that into a lightweight tile client (such as Modest Maps), or else use a simple base map with colored polygon shapes placed on top. Now, I would strongly encourage using pre-rendered tiles if possible. They’re becoming easy to make (thanks to applications like TileMill), and the performance of the pre-rendered graphics is superb. Polygon overlays are heavy and slow by comparison, although they do offer flexibility for rendering dynamic data sets on the fly using only front-end code. This is particularly useful when your data is frequently changing, or you if have limited access to a site’s technology infrastructure. I’ve ended up going with map polygons a few times recently… and they turned out to be trickier than I would have expected. First off, have a look at some polygon-based map demos that I put together, and feel free to grab their source code for your own use. Also, consider if your requirements are simple enough to just use Google Geocharts (which are easy and free, although not the most attractive or customizable solution).

The first thing you’ll need for a shape-based map is a client that supports polygon overlays, such as Google Maps, Leaflet, or another major platform. Realistically, the platform should natively support multi-polygons (ie: groups of polygons that behave as a single shape, for circumstances such as an archipelago), otherwise you’ll have to do grunt work to track multi-shape countries. Frameworks like Bing Maps and Mapstraction currently do NOT support multi-polygons, therefore they are probably not the best fit for polygon maps. Google Maps is outstanding with its canvas-based overlay renderer, although it now includes that pesky price tag which tarnishes its appeal. Therefore, I’ve found Leaflet to be a superb open-source alternative. While Open Layers is certainly an option, I’ve found its polygon features to be a bit clunky.

Next, you’re going to need polygon point data to draw onto your map. While there are countless sources of polygon data available online, most are formatted as Esri shape files. You’ll probably want Google-encoded polylines or raw point arrays if you’re adding your own shapes to a map using JavaScript. You can find point data for countries and U.S. states here. Note that there are both low and high-res country shapes available: you’ll probably want to detect a user’s browser and provide low-res shapes to older versions of IE so that they don’t choke.

To put the polygons on the map, you’ll need to decode the Google polylines and then add the point arrays to the map. Follow along with this script, and see its working demo here. For applying colors to your map, refer to this function:

// Gets a color for a specific value.
getColorForValue: function(value) {
    if (!isNaN(parseFloat(value)) && isFinite(value)) {
        if (value <= 20) {
            return "#aed0da";
        } else if (value <= 40) {
            return "#68c2e7";
        } else if (value <= 60) {
            return "#00a9df";
        } else if (value <= 80) {
            return "#00719f";
        } else if (value <= 100) {
            return "#003060";
        }
    }
    return "#ccc";
}

You’ll see that the above receives a location’s value and returns a color based on a pre-determined set of range breaks. You can customize those breaks, or hook them into a dynamic data source tailored to a specific data set.

This should get you up and running with a quick-and-dirty thematic map. Good luck and happy visualizing! You can see an implementation of a thematic map built using Google Maps at the Nuclear Materials Security Index. The custom map tooltip seen there is also available within the maps repo.

Snapping a Point to a Line Segment

Following up yesterday’s post on hit-testing a point within a polygon, there’s one other key geometric function that the Lassie engine’s motion grid would required in order to support polygonal motion areas: that’s the ability to snap stray (out-of-grid) clicks onto grid lines.

This took a bit of digging around to get working correctly… specifically, I wanted the point to snap to a line segment, therefore the snapped point’s position needs to be limited by the extent of the segment’s two end points. Ultimately, the operation turned out to be pretty compact:

// Snaps point P to the nearest position along line segment AB.
// @param p: The point to snap.
// @param a: First point of the line segment.
// @param b: Second point of the line segment.
// @return: A new point object with "x" and "y" coordinates.
function snapPointToLine(p, a, b) {
    var ap1 = p.x-a.x,
        ap2 = p.y-a.y,
        ab1 = b.x-a.x,
        ab2 = b.y-a.y,
        mag = ab1*ab1 + ab2*ab2,
        dot = ap1*ab1 + ap2*ab2,
        t = dot/mag;

    if (t < 0) {
        return {x: a.x, y: a.y};
    } else if (t > 1) {
        return {x: b.x, y: b.y};
    } else {
        return {x: a.x+ab1*t, y: a.y+ab2*t};
    }
}

Give it a try:

var a = {x:0, y:0};
var b = {x:50, y:50};
snapPointToLine({x:0, y:50}, a, b); // {x: 25, y: 25}
snapPointToLine({x:100, y:100}, a, b); // {x: 50, y: 50}

Polygon Hit Test with Ray Casting

Another old project that I’ve been digging back into with JavaScript recently has been the Lassie engine’s geometry system. Now, first and foremost, that’s NOT to say that the Lassie engine is in production for HTML5 (coding in my free time is not among my current priorities!). However, I’ve always found Lassie’s point-and-rectangle grid system to be archaic, and in all honesty, the only reason for that is because I’ve never taken the time to figure out polygon math. So, I’ve been tinkering with this…

The first thing that Lassie’s grid system would need to support polygons is a way to hit-test points against a polygonal area. A quick Google search on this led to an old (and shockingly simple) technique called ray casting.

The premise of ray casting involves extending a ray in one direction from the target point, and then counting how many times that ray intersects sides of the polygon in question. If the intersection count is an even number, then we can assume that the ray has both entered and exited the polygon’s boundaries an equal number of times, therefore placing the point outside of the polygon. However, if the intersection count is an odd number, then the point has entered but never left the bounds of the polygon and is therefore inside. Amazing that such a simple test holds up.

In JavaScript:

// Tests for counter-clockwise winding among three points.
// Specifically written for an intersection test:
// Uses ">=" (rather than ">") to cast equal points as valid CCW components.
function ccw(x, y, z) {
    return (z.y-x.y) * (y.x-x.x) >= (y.y-x.y) * (z.x-x.x);
}

// Tests for intersection between line segments AB and CD.
function intersection(a, b, c, d) {
    return ccw(a, c, d) !== ccw(b, c, d) && ccw(a, b, c) !== ccw(a, b, d);
}

// Performs ray casting, testing if point P falls within a polygonal region.
// @param p: The point to test.
// @param poly: An array of points forming a polygonal shape.
// @return: true if point falls within polygon.
function hitTestPolygon(p, poly) {
    var sides = poly.length,
        origin = {x:0, y:p.y},
        hits = 0,
        s1,
        s2,
        i;

    // Test intersection of an external ray against each polygon side.
    for (i = 0; i < sides; i++) {
        s1 = poly[i];
        s2 = poly[(i+1) % sides];
        origin.x = Math.min(origin.x, Math.min(s1.x, s2.x)-1);
        hits += (intersection(origin, p, s1, s2) ? 1 : 0);
    }

    // Return true if an odd number of hits were found.
    return hits % 2 > 0;
}

You’ll see our test uses three methods. First, ccw() tests for counter-clockwise winding among three points. Using that, we can test intersection() between two line segments by testing if the points of either segment wind into one another. Finally, we can perform ray casting by testing a target point’s line to an exterior point against each line segment in the polygon, and counting the number of intersections that are registered. Keep in mind that point order of your polygon array does matter (although the hit test still seems to work for oddly-wound polygons with intersecting sides). To see the hit test in action, try this:

var poly = [
    {x:10, y:10},
    {x:100, y:25},
    {x:125, y:125},
    {x:25, y:100}
];
hitTestPolygon({x:50, y:50}, poly); // true
hitTestPolygon({x:15, y:50}, poly); // false

Color Transform for HTML5 Canvas

Interest in more information on applying color transformations with HTML5 Canvas came from my last post. If you’re coming from Flash, the concept of color transforms should be pretty familiar. The canvas method works pretty much the same way that Flash’s ColorTransform object worked (or what the color tint interface configured within the Flash IDE). All code needed is below; this snippit is largely based on the operation from easel.js.

// Apply color transform.
var r = 115, // Red tint (0-255)
    g = 208, // Green tint (0-255)
    b = 189, // Blue tint (0-255)
    t = 0.6, // Tint strength (0-1)
    i,
    ctx = document.getElementById('myCanvas').getContext('2d'), // Get the drawing context of your canvas element.
    img = ctx.getImageData(0, 0, 100, 100), // Pull a rectangle of image data from context
    data = img.data, // Image image data array.
    len = data.length; // Length of data array.

// Loop through image data array.
// Apply color trasform to each block of RGBA values.
// Applied as: c = c * cmodifier + coffset.
for (i = 0; i < len;) {
    data[i] = data[i++] * (1-t) + (r*t);
    data[i] = data[i++] * (1-t) + (g*t);
    data[i] = data[i++] * (1-t) + (b*t);
    i++; //data[i] = data[i++] * 1 + 0; << skip alpha component. Adjust as needed.
}

// Restore image data within the canvas.
ctx.putImageData(img, 0, 0);

Once Flash, Now JavaScript

The fishing mini-game featured in “What Makes You Tick: A Stitch in Time” is back, and this time it’s not running in Flash. It’s running in HTML5 using the canvas tag… and it was a pretty easy migration. First, have a look at the Flash and HTML versions of the game; they’re at:

Flash: http://www.lassiegames.com/games/stitch_fishing/play_1024.php
HTML5 Canvas: http://www.lassiegames.com/tests/fishing/

Pretty cool, right? There’s no two ways about it, the canvas tag is quite capable with fast image compositing. So, let’s have a look at how this Flash game turned Canvas.

Interface graphics

There are several big graphics used in the game’s interface. The background image and the intro screen are both just big image plates applied to HTML elements. All interface elements (buttons, text displays) are just HTML. When the actual game starts running, a full-screen Canvas element is placed on top of the background image, and the game starts drawing itself at 30 frames a second. Once the game ends, the canvas is pulled from the DOM and we go back to simple HTML/CSS layout for the replay options.

Basic game graphics

The game graphics all draw from a single sprite sheet, which you can see here. You’ll see that there’s one of each of the fish (green and yellow), multi-frame animation states for the animating jellyfish and the fishing net, and then some assorted interface elements. In most cases, rectangular regions are pulled from this sprite sheet and composited directly to the canvas on the fly. The big exception here are the green fish…

As the game runs, notice that the green fish have an implied visual depth: they get smaller and tinted with a pale shade of green further down in the layer stack. This effect is achieved with scale and pixel color transformations, both of which are expensive operations to be running every frame. However, these effects can be pre-rendered. Scroll down and look below the fishing game on the page. You should see a line of 15 green fish images, each getting slightly bigger and darker from left-to-right. These are the actual fish images being used within the game. As the game launches, the original green fish image is pulled from the sprite sheet and rendered with transformations onto these 15 individual canvas elements which are created on the fly. Then as the game runs, the pre-rendered fish images can be quickly composited into the game canvas without re-processing these additional transformations. Keep in mind that those individual fish images technically do NOT need to be displayed within the DOM for this to work (they’re just being displayed for demonstration purposes). Normally, you’d just store these pre-rendered elements within memory.

As for the fishing line, that’s just a simple vector arc drawn from a fixed point at the top down to the dynamically plotted mouse position. A fixed control point for the line’s arc is set a few hundred pixels below the origin to create a curve.

Animations

Animations are certainly the trickiest part of post-Flash graphics. Again, if you refer to the game’s sprite sheet you’ll see multiple graphical states drawn for the undulating jellyfish and the lifting net. The concept of animation is pretty simple: we’re just going to change the rectangular region pulled from the sprite sheet every few frames. The implementation is a bit trickier though. Animations generally require an independent interval which runs at a fraction of the main framerate; this allows objects to move around the screen at 30fps while only changing visual state, say, every three frames (10fps). One trick here is to use a modulus (division remainder) of the main clock to maintain a subset interval. Mind you, I was experimenting with some home brew animation techniques while building the Fishing game so reinvented a few wheels. There are plenty of JavaScript-based animation frameworks (like Cocos 2D) which will take care of this grunt work for you.

Sound

Now, I will admit that I cheated on the audio. I was underwhelmed by the capabilities of the HTML5 audio tag for playing sound effects in rapid succession, so I just set up a Flash player that plays effects at the command of JavaScript.

Program

All told, I ended up keeping the JavaScript architecture very similar to the original Flash architecture. In Flash, there’s a HookableObject abstract that extends into several implementations (Fish, Jellyfish, Boot, etc). In JavaScript, this same mapping was used with HookableObject serving as the prototype for Fish and Jellyfish. Beyond that, most object relationships between, say, Hook > Fish > Net didn’t really need to change. In fact, the single biggest change required involved the display list. In Flash, it was easy to reconfigure/reorder the pond as needed during an update pass, and then see all graphics magically update in accordance during Flash’s next render pass. This was useful when a fish swam off screen… anytime a fish left play and was ready for reset, there was a small probability offered for it to upgrade itself to “gold” status and swim the next pass as a bonus fish at the top of the stack. Unfortunately, this was a lot more complicated in JavaScript where I was trying to perform application update and rendering in a single pass, and therefore update order and rendering order were dependent upon one another. Rather than splitting rendering into a second pass, I opted to just change the delegation of bonus fish so that only fish at the top of the stack were eligible for upgrade to gold status.

So, that’s the gist of the HTML5 fishing game. Fun stuff. Enjoy the game, and feel free to download the complete project code from its GitHub repo.

Replacing Flash

As you may notice, it’s been a while since my last post on here… as in, a LONG while. Aside from having been busy at work and busy in life, my single biggest motivation killer for writing to a blog called “Flash Makes Games” has been the fact that I don’t really work with Flash anymore.

Two years ago I had a full-time job building Flash media by day, and a side project by night of building a Flash game of epic proportions (see “What Makes You Tick: A Stitch in Time“). Two years later, I’m still at the same job but now working almost exclusively with HTML5 multimedia as a data visualization graphics specialist. And quite frankly, I’m as happy as I ever have been at my job.

I guess I’m one of the long-time Flash supporters who’s okay with it going the way of the dodo as web browsers mature. To be honest, the Adobe AIR platform fell far short of my expectation while releasing Stitch, and since then I’ve been disappointed to see the Flash IDE getting clunkier and Flash Player pushing updates with invasive messaging. All gripes aside though, developing in a web browser also eliminates many of Flash’s traditional inconveniences without introducing a significant quantity of new ones. Gone are the fixed frame size limitations, the tedious pixel-pushing of static layouts, and the inconvenience of UI components. While cross-browser compatibility is arguably trickier without Flash, that’s getting continually easier as we phase out support for older browsers. In the past year, I’ve been finding and using increasingly more HTML5 replacements for traditional Flash features… some noteworthy swaps:

  • Canvas tag: everything you could want out of a dynamic graphics package. It provides awesome capabilities for dynamic drawing and image compositing.
  • SVG/VML: almost a direct replacement for the Flash drawing API when interfaced through a library like Raphael, and works back to IE6!
  • HTML/CSS: these are often overlooked as a graphics platform. You can render surprisingly complex graphics just using lines, boxes, and images.
  • Video tag: REALLY good. Flash video will likely be remembered as an overcomplicated solution to a very simple problem.
  • Audio tag: Good theory, but has a ways to go for rapidly-instanced audio clips in my opinion. I still miss Flash here. Hopefully Google Chrome’s audio API will knock browser audio capabilities up a few more notches.
  • JavaScript/jQuery: aside from jQuery being generally slick and easy to use, it also solves the cross-browser consistency issue that Flash has long been a crutch for.

So that’s my two cents on the migration away from Flash. Overall, this feels like another natural step in the on-going evolution of multimedia: there was Hypercard, then Director, then Flash, and now HTML5. If you look at the timeline, each technology had about a decade before its predecessor matured to the point of being a viable replacement. Why resist the progression? That said, I hope to be posting some JavaScript-focused articles in the coming months relating to some of the work I’ve been doing recently (for a sneak peek, you can find me on GitHub).

And I guess I’ll have to think up a new name for the blog…

Em-Dash in Flash HTML Text

It’s been a LONG time since my last post, and that is mostly because I haven’t been doing much Flash development recently. As Apple shuts out Flash, I’ve been forced to throw in the towel and say, “if you can’t beat em, join em”. Yep, so I’ve been building iPhone apps.

Anyway, fortune has thrown some Flash work my again, and it’s been great fun getting back into. However, here in the debugging phase I’m coming back to some of the weird old quirks of Flash content that I always had to keep a cheat-sheet handy for. One of those points being: how the heck do you put em-dash characters into Flash HTML text?! It seems so simple… after embedding the em-dash font character, you should just be able to put the character into UTF8 text, right? Or at the very least, you should be able to use the &mdash; entity, right? Wrong. You have to use the ASCII entity. Okay, that’s simple enough; except that when I look up the em-dash ASCII code most conversion tables list &#151;–which does NOT work. Gar! So, I’m not sure why em-dash has multiple ASCII values, but the one that works in Flash is &#8212;. Please post in comments if you can elaborate on the difference between those two ASCII codes, I’d be curious to know the difference!

And for those just skimming the article, here’s the bottom line… to make an em-dash in Flash HTML text, just embed the font character and then use this ASCII code in your text: &#8212;

“What Makes You Tick: A Stitch in Time” Released!

After two years of continuous development, Matt and I have finally put Stitch out to pasture for purchase. All told, we’re really happy with the final game and think it’s particularly neat that a story we dreamed up in a Swiss pub back in 2007 is now a real game. It’s been a long haul building it, but it’s also been really rewarding to see it all come together.

Stitch is a commercial release – we financed the project so that we could designate fulltime human resource to the project (otherwise it never would have been built!). The game is selling for $15 USD, and we’d really appreciate all the help we can get in making the game a success! You can check out the new game website at http://www.lassiegames.com/stitch.

Enjoy!

Cross-domain import loading

I hit a wall while trying to get the “WMYT: A Stitch in Time” game demo setup online. I had (correctly) anticipated that the demo would get heavy traffic upon release, so I wanted to host the game’s 9Mb worth of media out on the Amazon cloud, then just load the game’s 100Kb shell application from my server. Great… all I needed to do was get all the cross-domain restrictions worked out.

I started by adding lots of Security.allowDomain() calls into all my SWF media. No luck. The Lassie engine relies on library sharing between SWFs, and try as I might – I could not get the SWFs to authorize that level of access using just allowDomain() (maybe I was missing something…). Either way, I moved on and found a cross-domain loading feature that I’d never used before: import loading. Wow, it’s really handy.

The premise of import loading is very simple: you’re loading media from another domain into the current security sandbox, at which time the loaded media can be accessed as though it were available on the local file system. No symmetrical Security.allowDomain() calls are required between media files, so this is super clean and easy to set up. Just have a Flash Loader object perform an import load, and you’re off to the races. Here’s how to do it:

First, let’s assume that we’ll be working with the following servers:
http://www.mymediaserver.com – this server hosts all of the external media that we’ll be loading.
http://www.myappserver.com – this is where our application will be running at.

1) Set up a cross-domain policy file on your media server.

This policy file must be called “crossdomain.xml” and must reside in the media server’s web root (ie: the policy file URL would need to be “http://www.mymediaserver.com/crossdomain.xml&#8221;). This policy file specifies what domains may access files on this server. The content of the cross-domain XML should be this:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
 <site-control permitted-cross-domain-policies="master-only"/>
 <allow-access-from domain="www.myappserver.com"/>
 <allow-access-from domain="myappserver.com"/>
</cross-domain-policy>

2) Configure an import load

Now that you have a cross domain policy file that will allow your application to access files on the media server, you can import load from the media server by doing this:

var $loader:Loader = new Loader();
var $context:LoaderContext = new LoaderContext(true, null, SecurityDomain.currentDomain);
var $request:URLRequest = new URLRequest("http://www.mymediaserver.com/media/myfile.swf");
$loader.load($request, $context);

The trick here is to use a LoaderContext object that specifies the current security domain as the sandbox to load the external media into. Specifying “SecurityDomain.currentDomain” brings the external media into the local sandbox. Once you’ve done that, neither the loader nor the loadee file need any further security scripting to work together (such as allowDomain() calls).

Follow

Get every new post delivered to your Inbox.