Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Friday, June 20, 2008

Weird Issue with responseXML and JSON in FF3

I recently (like today) upgraded Mint to support FireFox 3. I was not expecting this to be a difficult process, because there is no drastic difference between the JavaScript engines of FF3 and FF2. However, I was surprised to find that many parts of the site did not work. Upon further studied I realized the most peculiar behavior. Upon receiving a JSON response from the server using GetXmlHttpObject(), FF3 populates the XmlHttpObject.responseXML with the following:

Example 1: Parser Error

<parsererror xmlns=”http://www.mozilla.org/newlayout/xml/parsererror.xml”>XML-Processing error: not well formed Address: URL_BEING_REQUESTED Line Number 1, Column 1:<sourcetext>JSON_OBJECT^</sourcetext></parsererror>

In all other browsers, including FF2, the responseXML value is ‘null’ when the response is a JSON object, and occasionally ‘undefined’, but never populated with a value. On Mint we have several different code paths, depending on if a response is an XML or JSON object, or just text. Because the responseXML was not NULL, the code assumed that all my JSON Objects were XML and crashed.

Obviously, this was unacceptable, so I wrote a hack that fixes FF3. If you do any responseXML detection, then the following hack might help you as well:

Example 2: Parser Error Fix

var doc = (data.responseXML); var docString = Dom.getContentAsString(doc); var isXML = $defined(doc) && 0 !== docString.indexOf(’<parsererror ‘);

First, note that the parentheses are required, otherwise FF3 (and possibly other browsers) will set the ‘doc’ to ‘undefined’, even if it has a value. The method ‘getContentAsString’ iterates through the nodes inside of the XmlHttpObject, in a browser safe way, turning everything into a String (useful with ‘innerHTML’). This was originally modeled after a method in OpenRico by the same name. If ‘doc’ is not defined, then isXML is false and everything works as before. Wowever, if ‘doc’ is defined then we look at its content and see if it starts with parsererror. When it does, we assume that the response was not suppose to be XML.

This works for almost every case, with the possible exception that your response is supposed to be XML, and does actually have an XML parser error. However, since that is another issue and I cannot think of any reason why one would intentionally return XML with a parse error, I believe this hack solves the problem.

I have also posted on the FireFox forums and am hoping to here back from somewhere there on why the behavior of ‘responseXML’ has changed (click here to see my post).

—–

I have resolved the issue. The mime-type was not being properly set to ‘text/json’ in the server-side code. However, as I read on Mozilla Docs XMLHttpRequest, responseXML should be null if you do not explicitly send ‘text/xml’ or if the XML is not well formed. So unless I’m missing something, it should still be null, and not a parser error.

Debugging this also, made me ask myself, “Why am I not using the mime-type for response detection”? Kinda of a “Doh” moment. This is a much more robust way of type detection and if you use YUI’s Connect.js, you have the mime-type readily available in the data Object passed into your AJAX callback function. Simply do the following:

var ajaxCallback = function(data) { var isMimeType = data.getResponseHeader[’Content-Type’].indexOf(mimeType); };

Where ‘mimeType’ is the type that you wish to test for, such as ‘text/json’.

posted by Matt Snider at 3:46 pm  

Tuesday, June 17, 2008

Object Subscription Pattern

I have said this before and will probably say it again, “I love CustomEvent“. This was one of the major reasons why I chose YUI as my preferred JavaScript framework. Using CustomEvent you are able to create a subscribable event for anything you might want an event for, and fire that event programmatically.

I find this most useful when leveraging the Module Pattern, as I can keep the event management and all important methods private, while allowing users to define actions at key times during the execution of the code. You can also use this process to pass private data from inside the current Module Pattern to external Object with some degree of control (if absolutely necessary). However, for this pattern to work you need a way to expose the events to the other objects, without attaching every event to ‘this’. For this purpose I use the “Object Subscription Pattern”, which uses one public method and coding conventions for subscribing to events. Here is an example of an Object, Dialog, using both the Module and “Object Subscription Pattern”.

Example 1: Subscript Pattern, Dialog Object

var Dialog = function() { var CE = YAHOO.util.CustomEvent, F = function() {}, that = null; var evt = { beforeCloseEvent: new CE(’DialogBeforeCloseEvent’, that, CE.FLAT), beforeOpenEvent: new CE(’DialogBeforeOpenEvent’, that, CE.FLAT), closeEvent: new CE(’DialogCloseEvent’, that, CE.FLAT), openEvent: new CE(’DialogOpenEvent’, that, CE.FLAT) }; /** private methods here */ F.prototype = { EVENT_BEFORE_CLOSE: ‘beforeClose’, EVENT_BEFORE_OPEN: ‘beforeOpen’, EVENT_CLOSE: ‘close’, EVENT_OPEN: ‘open’, subscribe: function(type, func, obj) { var eventName = type + ‘Event’; if (evt[eventName]) {evt[eventName].subscribe(func, obj);} else {throw(’Invalid event type (’ + type + ‘) inside of Dialog.’);} } }; that = new F(); return that; };

Lets assume that Dialog is used to manage a div-based popup system, similar to YUI Dialog. In Example 1 we assume you might care about 4 events: after the dialog opens or closes, and before those same events. For this purpose we have created 4 custom events and attached them to the internal namespace ‘evt’. I always use the FLAT CustomEvent type, because I find the default annoying; the difference is well explained in the YUI documentation. The first parameter of CustomEvent is the name of your events and is very important, because the CustomEvent manager maintains a global list of all names to know what to subscribe to and fire. For this reason, make sure you use a unique name. I prefer the convention of the String NameOfObject + NameOfEvent + ‘Event’. The second parameter will be the execution scope of the callback Functions and I generally pass in a reference to the parent Module Pattern Object. The localized event name, attached to ‘evt’, should follow a convention as well; I prefer to use the String NameOfEvent + ‘Event’ (this will be important in the public ’subscribe’ method).

Now, moving on the the public part of the Module Pattern. I have first exposed some constants that are the event names (NameOfEvent) that I used above. These constants make your public interface easier to read and use by others (and even yourself, when returning to an object you wrote some time ago), since there is no need to search the internal namespace for the available event names. The ’subscribe’ method is just a wrapper for calling the ’subscribe’ method of the internal CustomEvents with the proper parameters. We first test to make sure that the internal event exists, and throw an informative exception otherwise. The second parameter will be your callback function and the third is an optional, additional Object that will also be passed through to the callback method, when your CustomEvent is fired.

That is the gist of the pattern. You have exposed private module events through a public ’subscribe’ method. It is relatively simple to use and setup, just requiring that you use some conventions (mine or your own), with which you can apply the Subscription Pattern to any Module Pattern Object. Lastly, lets go over the actual firing of events. When a point in your code is reach and you want to fire an event, use the following syntax:

Example 2: Firing a CustomEvent

var open = function() { evt.beforeOpenEvent.fire(); /** logic to show the dialog */ evt.openEvent.fire([1, 2, 3]); };

Example 2 could be an internal method of our Dialog object that actually shows the Dialog. Notice, we first first the ‘beforeOpen’ event, followed by the opening logic, then we fire the ‘open’ event. I have also illustrated with the ‘open’ how to pass values through to the callback function. With FLAT CustomEvent types, this should always be an Array and will be the second parameter of your callback function.

posted by Matt Snider at 11:44 pm  

Saturday, June 14, 2008

Using Bitmasks to Efficiently Store Data

There are many times when programing that you need to store state, and when this state is simply on or off, one usually uses Booleans. As your projects group, there tends to be collections of similar boolean states, such as turned on features, or user hidden/displayed content. On Mint.com we are (re)adding the ability to hide/show certain account types on the Overview page. I will be using this as a test case for todays article. There are 4 account types in Mint: bank, credit card, investment, and loans; each of these accounts types has a section in the sidebar that can be hidden or displayed. When the user hides/shows these sections we want to remember it between sessions, so I am using a binary number to store the state and a bitmask to modify it.

First, lets discuss several technologies for storing the state, each of which have associated costs and benefits: cookies, session, database, or some combo thereof. In the Mint case, we are storing a visual preference for the user, so I initially want to use cookies. By using cookies, we have a light-weight solution remembers the users preferences on their main, or do we? If they use two computers, have multiple people using the same computer, or occasionally clear out there cookies, then there is no way to ensure that the state is remembered. However, for something minor, such as a visual preference, this might be acceptable, as cookies are fast and light-weight (unless you have lots of them). Alternatively, you could store the state in the database, and load it into the users session whenever they login. This is better than cookies, because it fixes all the above mentioned issues, and is still relatively light-weight, as you only need to make 1 DB call to fetch the preference. The only issue would be if the user is is using two simultaneous computers, which could have two separate sessions. That means setting and getting from the database is the only way to ensure that the users experience is the same on all computers, all the time. The drawback is making frequent database calls is rather expensive. On Mint we solve this by using a database caching layer, but if you don’t have a caching layer, then I recommend storing data in the session.

Now, I’ve written a JavaScript BitWriter Object that manages writing/reading bitmasks on a binary number, so I will be doing a simple cookie example. For more information on the methods I use to write/read cookies, see the post Cookies.

Lets define 4 constants to be our bitmasks, where the bitmask is the 2^n value, and n represents the binary position we are masking. So, 4 values would be represented by the binary number 2^4 (or ‘1111′). Having a ZERO in any position, indicates that the value is not set (false), and having a 1 indicates that the value is set (true). The bitmask is the value of 2 to the power of the position you are masking. Here is an example:

Example 1: Defining Bitmask

var BITMASK = { BANK: 1, // 2^0 CREDIT: 2, // 2^1 INVESTMENT: 4, // 2^2 LOAN: 8 // 2^3 };

So in our example, we use these constants to update the binary value stored in the cookie anytime the state changes. One simply fetches the binary value that is stores in the cookie, and updates it by removing, or adding the desired bitmask:

Example 2: Updating the Cookies

var COOKIE_ACCOUNT_STATE = ‘accountPreferences’; var update = function(name, b) { var n = parseInt(Core.Client.readCookie(COOKIE_ACCOUNT_STATE), 10); var bw = Core.Widget.BitWriter(n); bw[b ? ‘addBitmask’ : ‘removeBitmask’](BITMASK[name]); Core.Client.createCookie(COOKIE_ACCOUNT_STATE, bw.getValue(), 365); };

Here we read the cookie called ‘accountPreferences’ and create a new BitWriter from the value. The sample method requires two parameters: the constant name of the bitamsk, and the boolean value of the state (true = on, false = off). Then we use the add/remove bitmask methods of BitWriter to update the value, before updating the cookie value.

The BitWriter Object has the following methods: ‘addBitmask’, ‘getValue’, ‘hasBitmask’, ‘removeBitmask’. Each method ensures that bitmask is valid (a value of 2^n), before attempting the operation. The ‘addBitmask’ method tests to see if the state of the bitmask is ‘0′, and adds the bitmask from value (this is like the binary operator ‘|’ in other languages). The ‘removeBitmask’ method tests to see if the state of the bitmask is ‘1′, and removes the bitmask from value (this is like the binary operator ‘^’ in other languages). The ‘hasBitmask’ method tests to see if the state of the bitmask is ‘1′, and returns the mask in that case or 0 otherwise (this is like the binary operator ‘&’ in other languages). The ‘getValue’ method just returns the current value of the binary number managed by BitWriter.

The logic that runs BitWriter is not anything fancy, just a lot of basic binary math (see the source code here). I have also thrown together a simple test page, so that you can experiment with values and validate the logic of BitWriter.

Following a user comment, I took another look at binary operations in JavaScript only to learn that it does properly support it. I have since upgraded BitWriter to properly use binary operators instead of manually doing it. Needless to say it is much faster, regardless of the size of your binary value and about 1k smaller.

posted by Matt Snider at 12:32 pm  

Saturday, June 7, 2008

RegExp Escape

If you use regular expressions on your site, then I am sure you have encountered situations where you use a String value, possibly returned from the some user input, as part of your regular expressions. The syntax you might use:

Example 1: Typical Syntax

var haystack = ‘Hello World, my name is NAME!’; var needle = ‘NAME’; var rx = new RegExp(needle); alert(haystack.replace(rx, ‘Matt Snider’));

This very simple example shows how you create a RegExp Object from a String, and use that regex to find and replace a substring of the haystack String. This works great, as long as the needle String does not contain any regex special characters, such as: ‘/’, ‘.’, ‘*’, ‘+’, ‘?’, ‘|’, ‘(’, ‘)’, ‘[’, ‘]’, ‘{’, ‘}’, ‘\’. If the needle contains any of these characters, your regex will return unexpected results or possibly throw an error.

Suppose we have the following situation: you have a large page of text, at the top of which there is an input Element tied to a JavaScript Function that search the pages text, counting the number of times the provided String occurs. The user then wonders how many sentences are in your text, so they do a search for ‘.’. The ‘rx’ variable of the JavaScript Function, actually becomes the regular expression, ‘/./’, which matches all characters in the text, instead of just the periods. What we need is a method to escape the text before creating a regular expression:

Example 2: RegExp Escape

var RegExp.esc = function(text) { if (! arguments.callee.sRE) { var specials = [’/', ‘.’, ‘*’, ‘+’, ‘?’, ‘|’, ‘(’, ‘)’, ‘[’, ‘]’, ‘{’, ‘}’, ‘\’ ]; arguments.callee.sRE = new RegExp(’(\’ + specials.join(’|\’) + ‘)’, ‘g’); } return text.replace(arguments.callee.sRE, ‘\$1′); };

Example 2 searches the text and properly escapes all regular expressions. I did not write this method and am not sure where it came from, but it is effective and fast. Lastly, we need a count method extending the prototype of a RegExp Object to return the number of times the current regular expression matches a haystack String:

Example 3: SubString Count

RegExp.prototype.count = function(haystack) { return (haystack || ”).match(this).length; };

Now using these last two methods in conjunction we can search the text and properly count the number of times that period or other special characters occur, see Test Page for a full text count example.

posted by Matt Snider at 2:14 pm  

Wednesday, June 4, 2008

Intro to HTML Canvas Tag

I remember hearing about the Canvas tag some time ago, but until recently I had not given it much thought. However, now we have John Resig using JavaScript and the Canvas tag to compile and render the Processing language (Processing.js), and Jacob Seidelin emulating Mario Kart. I have even read opinion articles claiming that Canvas could replace Flash. Although, that is unlikely, all this buzz portends that Canvas is here to stay and may be a big player in the future of the web. Todays article will address: what the Canvas tag is, who supports it, and a basic example of how you can use it.

What is the Canvas Tag?

The Canvas tag was first introduced by Apple for the Mac OS X Dashboard and later implemented into Safari. Other browsers would follow Safari’s lead and eventually WHATWG standardized it for the HTML5 specification, which was recently adopted by the W3C HTML Working Group. At its core Canvas is an HTML Element, inheriting the same DOM attributes as other HTML Elements: class, id, style, etc. It has two optional attributes: width and height; it will default to 300 pixels wide and 150 pixels high, if optional attributes are not included. Canvas was introduced to support 2-dimensional graphic rendering on the web, driven by a scripting language with access to the context of the desired Canvas Element.

Why Should I Care?

Canvas is important because it provides a standard, non-proprietary rendering platform that has been strangely absent on the web. In fact, it is the absence of such a standard technology that spawned proprietary frameworks, such as Flash. In the future, we will probably be able to do full 3-dimensional rendering using OpenGL ES, and I would be surprised if someone does not attempt to write a complete Flash-like engine.

Who Supports Canvas

Unfortunately, not all browsers support Canvas (most notably IE), but most do: FireFox v1.5+, Opera 9+, Safari, and even Konquerer (Bug 108069). As far as I can tell, IE 8 still does not have native support for the Canvas Element, which is sad. Fortunately, Google came to the rescue and has created CanvasExplorer which emulates Canvas in IE using one 50kb JavaScript file. Therefore, after a fashion, all major browsers support Canvas.

However, not each browser supports it in exactly the same way. Safari does not require the closing “</canvas>” tag, where Mozilla does. Mozilla made this decision to be more backwards compatible with browsers that do not support the Canvas tag, allowing for fallback content. For example if you take the following example:

Example 1: Fallback Content

<canvas id=”stockGraph” width=”150″ height=”150″> <p>current stock price: $3.15 +0.15</p> </canvas>

The text inside the HTML block will render in any browser not supporting Canvas (FireFox 1.0 or IE without CanvasExplorer). Generally, Safari simply drops the closing tag and ignores it, causing no problems, but if you desire to use fallback content, then you need to target Safari in your CSS to not show the fallback content:

Example 2: CSS Targeting Safari

canvas * {display: none;} canvas * {display: block; #} /** Safari will ignore this */

This hack initially applies a style that displays all sub-elements of a Canvas Element as ‘none’, then it tells the browsers to display the sub-elements as ‘block’. However, by putting an extra ‘#’ after the semicolon, we cause Safari to stop rendering the styles and simply drop all declarations inside that bracket. Other browsers just ignore the ‘#’ and apply the ‘block’ display style. Lastly, for the ‘*’ selector to work, all fallback content must be contained inside of another HTML tag (I used the ‘p’ tag in Example 1). Remember, this is a hack and won’t validate, and/or may not always work. However it has continued to work since Nicholas Gagne’s first blogged about it in 2004.

Basic Example

The Test Page contains 3 Canvas Elements, each with alternative fallback content: 1) does nothing, just shows that the alternative content works correctly, 2) draws two rectangles, the second of which overlays part of the first and demonstrates transparency, and 3) draws a heart shape using a more advanced transformation. These examples were found at Mozilla Developer Center: Canvas Tutorial, which provides a much more indepth explanation about the various Canvas rendering options. That article and the Wikipedia Canvas HTML Element Article provided the majority of todays content. I recommend reading both articles if you have additional interest in exploring Canvas.

posted by Matt Snider at 11:01 pm  

Tuesday, May 27, 2008

Dom.Activate to Focus on Form Elements

One of the methods that I missed when switching from Prototype to YUI, was a generic method to use to focus on a form element and/or selecting its text. Each browser supports focus in a slightly different way and until recently most did not support the ’select’ Function on an Input Element. In addition, you should never attempt to focus on a hidden or non-displayed Element, nor should you focus on an Input Element of type ‘hidden’. Because of all this trickiness, it is rather handy to have one method that manages all this for you.

Example 1: Dom.Activate

Dom.activate = function(elem, noSelect) { var node = Dom.get(elem), dim = Dom.getRegion(node); if (’hidden’ !== node.type && (dim.top || dim.left || dim.bottom || dim.right)) { setTimeout(function() {node.focus();}, 1); if (isType(node.select, ‘function’) && ! noSelect) {setTimeout(function() {node.select();}, 1);} return true; } return false; };

As usual, I am assuming that you have created a shortcut for “YAHOO.util.Dom” as “Dom”. The parameters are: 1) the string Id of the element or JavaScript pointer thereto, 2) optional parameter that prevents text selection when true. We first verify that the Element is not the ‘hidden’ type and that it is visible by checking that the Element has dimensions. Simply checking the ‘display’ style isn’t enough, because styles applied by classes do not set the style property of the Element. Next we call “node.focus()” and “node.select()”, if the method exists and ‘noSelect’ is falsy. Now the trickiest issue this method solves is an event timing problem with FireFox on the Mac, Bug 53579, which causes the focus to not work properly. We solve the bug by calling the ‘focus’ and ’select’ methods inside a one millisecond timeout. Lastly, we return whether the focus was successful or not.

Now that we understand the method, but what is a good application of it? How about focusing on the first Input inside of a Form? Here is a method does just that:

Example 2: Dom.focusOnFirstElement

Dom.focusOnFirstElement: function(form) { var node = null; Core.batch(form.getElementsByTagName(’input’), function(npt) { if (Dom.activate(npt)) { node = npt; return; } }); return node; };

Using the Batch Function we iterate on the Input Elements of a Form Element and then attempt to active each one in order. The first time we are successful, we stop the iterate and then return the newly focused Input, just in case you want to use it. I use the “Dom.activate” method most frequently with this type of operation, with tab key management being a distant second.

The biggest failure of this method, is that, as it is right now, it does not support TextArea and Select Elements. If you don’t care about those Elements, then you are good to go. If you do, then the best method, I know of, is to use ‘getElementsByTagName’ for each type and join them together, before iterating. However, then you have to deal with figuring out the actual order of the Elements in the DOM, and it is rather slow. Basically, it’s a mess and probably not worth your time, unless you know something of something slick. If you know of a good method for fetching multiple element, in the proper order (as they appear in the DOM), please post it in the comments.

posted by Matt Snider at 5:55 pm  

Saturday, May 24, 2008

Reserved Words in JavaScript

I ran into an issue this week while running some old code, where I was using a reserved word in JavaScript, or more accurately a reserved word in a specific browser. Almost two years ago, I thought I was rather smart using ’self’ as the variable name to store the Function scope for the Module Pattern, however, several browsers use this internally and can cause surprising conflicts. Later I learned from Douglas Crockford that I should be using ‘that’ as my keyword, because it is yet to be reserved by the EMCAScript standard, any browsers, or server-side JavaScript technologies. However, it did take me a while to realize my mistake, and I felt it about time to revisit the reserved word list. This post is the amalgamation of what I have learned.

First there are the words that are strictly reserved by the current EMCAScript specification. The following are reserved words and may not be used as variables, functions, methods, or object identifiers:

* These links are provided by the Mozilla Developer Center.

Once we taken care of the existing keywords, we want our code to be forward thinking, so we must look out for planned reserved words as well. The following are reserved as possible future keywords by the ECMAScript specification:

* These links are from About.com.

Next we consider JavaScript 2.0 and additional keywords that are in that specification. The following is a list of keywords for JavaScript 2.0 that have not been previously mentioned:

  • as
  • const
  • export
  • import
  • is
  • use

Mozilla has already reserved the following three JavaScript 2.0 words:

* These links are provided by the Mozilla Developer Center.

Next is the large list of predefined Classes and Objects found in all or most browsers:

* These links are from About.com.

And if that wasn’t enough, the following is a large and growing list of global properties and methods:

Global Properties

Global Method

* These links are from About.com.

The Window Object

The Window Object is the global namespace and can be referenced directly within any scope. Also, any variable that is not scoped with the ‘var’ keyword will be attached to the Window Object.
Properties

* These links are from About.com.

Methods

* These links are from About.com.

Events

* These links are from About.com.

And if all that wasn’t enough to worry about, the following are collection of keywords that are reserved by or used by certain browsers:

  • all
  • assign
  • clientInformation
  • element
  • embed
  • embeds
  • event
  • frameRate
  • getClass
  • java
  • JavaArray
  • JavaClass
  • JavaObject
  • JavaPackage
  • layer
  • layers
  • netscape
  • offscreenBuffering
  • opener
  • packages
  • secure
  • status
  • sun
  • taint
  • toSource
  • toString
  • untaint
  • valueOf

Although this is probably not everything, this is the most complete list I have seen of reserved words for JavaScript. I have collected these words here, so each of you can reference it when creating future projects and try to avoid using these words when writing JavaScript.

posted by Matt Snider at 10:12 pm  

Wednesday, May 21, 2008

Applications of Random

I do not find myself needing random numbers very often in my projects, so I thought it would be good to talk about a few useful applications of Random Integers.

The easily to implement without any additional programming would be a dice roller. You need only call ‘Math.RandomInteger(n)’, where n is the number of sides of the die you wish to roll. So a six-sided Function might look like:

Example 1: Six-Sided Die

var d6 = function(mod) { if (! mod) {mod = 0;} return Math.RandomInteger(6) + mod; }

I made a slight modification to the Function, so that you can modify the result if you desire. Another example are casino games. Most likely they will use a stronger Random Function than the one I have provided, but the concept is the same. Here is a simple shuffle Function for a deck of cards:

Example 2: Card Shuffle

var deck = [ ‘H1′, ‘H2′, ‘H3′, ‘H4′, ‘H5′, ‘H6′, ‘H7′, ‘H8′, ‘H9′, ‘H10′, ‘H11′, ‘H12′, ‘H13′, ‘D1′, ‘D2′, ‘D3′, ‘D4′, ‘D5′, ‘D6′, ‘D7′, ‘D8′, ‘D9′, ‘D10′, ‘D11′, ‘D12′, ‘D13′, ‘S1′, ‘S2′, ‘S3′, ‘S4′, ‘S5′, ‘S6′, ‘S7′, ‘S8′, ‘S9′, ‘S10′, ‘S11′, ‘S12′, ‘S13′, ‘C1′, ‘C2′, ‘C3′, ‘C4′, ‘C5′, ‘C6′, ‘C7′, ‘C8′, ‘C9′, ‘C10′, ‘C11′, ‘C12′, ‘C13′ ]; var shuffle = function(n) { for (var i = n - 1; 0 <= i; i -= 1) { var r1 = Math.RandomInteger(deck.length) - 1; var r2 = Math.RandomInteger(deck.length) - 1; var temp = deck[r1]; deck[r1] = deck[r2]; deck[r2] = temp; } }

First we create a deck of cards, where each card is represented by a string containing the first letter of the suit and the face-value of the cards, so: H = hearts, D = diamonds, S = spades, C = clubs, 1 = ace, 11 = jack, 12 = queen, and 13 = king. To randomize the order of these cards, the shuffle Function will randomly swap the position of two cards ‘n’ number of times. The higher ‘n’ is the more random the cards in the deck will be organized.

The last example for today is a hexadecimal number generator, which will be used to generate random colors. I used this on the Graph Beta Test Page to change the colors of the lines and legends when adding additional lines to the graph.

Example 3: Random Hexadecimal

Number.prototype.toHexadecimal = function() { return this.toString(16); } String.prototype.todecimal = function() { return parseInt(this.replace(/[^0-9A-Fa-f]/g, ”), 16); } var getRandomHex = function(n) { if (! n) {n = 16;} var m = Math.RandomInteger(n) - 1; return m.toHexadecimal(); };

The first method appends to the Number prototype a method that converts a Number into a hexadecimal String, using native JavaScript method ‘toString’. Unfortunately, native ‘toString’ method does not preserve significant figures and a call like “(256).toHexadecimal()” can return ‘A’ or ‘1′, instead of ‘0A’ or ‘01′. The second method does the reverse, converting a hexadecimal String into a Number, using the native ‘parseInt’ method with a base 16. We also strip out any characters that aren’t valid hexadecimal characters before we attempt to parse the integer. Lastly, we can leverage the ‘toHexadecimal’ method to convert a random integer (0, 15) into a hexadecimal in the ‘getRandomHex’ method. That method also accepts a Number ‘n’ in case you want to generate a random hexadecimal that is larger than 16.

Using ‘getRandomHex’ we can now generate random colors:

Example 4: Random Colors

var getRandomColor = function() { return ‘#’ + getRandomHex() + getRandomHex() + getRandomHex() + getRandomHex() + getRandomHex() + getRandomHex(); };

To give these examples a try, I have created a simple Random Applications Test Page.

posted by Matt Snider at 10:07 am  

Saturday, May 17, 2008

Random Integers

If you have ever tried to get a random integer in JavaScript, you have probably been frustrated with converting the method ‘Math.random’ results (values between 0 and slightly less than 1) to integers. There are several gotchas when converting the floating points from ‘Math.random’, in JavaScript, to integers. Todays article will walk through how to build a proper random integer generator and each gotcha you might run into.

On a first pass, one would probably come up with a method like the following:

Example 1: Math.RadomInteger() Version 1

Math.RandomInteger = function(n) { var i = Math.random(); var num = Math.round(i * n); return num; };

For all RandomInteger methods that we discuss today, the parameter ‘n’ is the upper range of the random number, so if you want number 1 through 4, then ‘n’ would equal 4. There are two issues with this version of the method: 1) the ’round’ method will sometimes round down to 0 causing a distribution of 0 through 4, and 2) the numbers will distribute themselves more frequently to integers 1 through 9. Here is the distribution you can expect from this method (for 1000 tries and digits 1 through 10):

Example 2: Math.RadomInteger() Version 1 Distribution

0 = 36 1 = 118 2 = 93 3 = 100 4 = 108 5 = 99 6 = 99 7 = 109 8 = 98 9 = 96 10 = 44 11 = 0

A random integer generator should have an equal distribution between all desired integers (so values 1 through 10 should each have occurred about 100 times). As you can see, ZERO has been returned and ten has too low of a distribution. We fix that by adding 1 to the number returned by multiplication of the random value and ‘n’:

Example 3: Math.RadomInteger() Version 2

Math.RandomInteger = function(n) { var i = Math.random(); var num = Math.round(i * (n - 1) + 1); return num; };

Example 4: Math.RadomInteger() Version 2 Distribution

0 = 0 1 = 52 2 = 97 3 = 116 4 = 95 5 = 128 6 = 111 7 = 113 8 = 114 9 = 122 10 = 52 11 = 0

Now we are returning the correct integers (only 1 through 10), but both ten and one have the wrong distribution (about half of what they should). The problem is using ‘Math.round’ causes ten and one to loose about 50% of their values, because half rounds down for 9 < x < 9.5 and up for 1.5 <= x < 2. Instead we should use 'Math.floor' or 'Math.ceil', which will consider all values between two integers to round to only 1 integer, fixing the distribution:

Example 5: Math.RadomInteger() Version 3

Math.RandomInteger = function(n) { var i = Math.random(); var num = Math.ceil(i * n); return num; };

Example 6: Math.RadomInteger() Version 3 Distribution

0 = 0 1 = 91 2 = 112 3 = 103 4 = 82 5 = 105 6 = 99 7 = 112 8 = 110 9 = 99 10 = 87 11 = 0

This distribution looks great, so we are done, right? Well, no, because as I mentioned above, ‘Math.random’ returns ZERO through slightly less than 1. There is a very, very small chance that ZERO will be returned (although, out of several thousand tries, I was never able to get ZERO, you still want to prevent it). So, instead of using the ‘Math.ceil’, we should use ‘Math.floor’ on the value we rounded in Example 3. Here is the final method:

Example 7: Math.RadomInteger() Final Version

Math.RandomInteger = function(n) { var i = Math.random(); var num = Math.floor(i * n + 1); return num; };

Example 8: Math.RadomInteger() Final Version Distribution

0 = 0 1 = 96 2 = 114 3 = 83 4 = 108 5 = 105 6 = 98 7 = 97 8 = 106 9 = 93 10 = 100 11 = 0

This is a pretty good distribution, and there is no chance of getting either ZERO or 11. So, this is the correct function. However, lets make one final improvement, allowing you to pass both a maximum and minimum value, returning a random integer in that range, inclusive of the end points.

Example 9: Math.RadomInteger() Max & Min Version

Math.RandomInteger = function(n, m) { if (! m) {m = 1;} // default range starts at 1 var max = n > m ? n : m; // doesn’t matter which value is min or max var min = n === max ? m : n; // min is value that is not max var d = max - min + 1; // distribution range return Math.floor(Math.random() * d + min); };

Example 10: Math.RadomInteger() Max & Min Version (range 6-10)

0 = 0 1 = 0 2 = 0 3 = 0 4 = 0 5 = 0 6 = 197 7 = 203 8 = 204 9 = 215 10 = 181 11 = 0

Note that the 1000 values are nearly evenly distributed through six and ten. This method also supports passing just a single value (the maximum) and working as the Example 8, ranging between 1 and the maximum. I have also created a Math.RandomInteger test page, if you want to see the distributions yourself. Reload the page to have it compute the values again.

I have also included a new Math.js which I will use to augment the JavaScript native ‘Math’ Object in the future.

————–

A commenter pointed out that this method isn’t the most efficient/effective random number generator available. He is correct, this is just the simplest and most easy to understand version. If you want a better random number generator then check out Mersenne Twister (MT), which has already been converted to JavaScript.

posted by Matt Snider at 3:49 pm  

Wednesday, May 14, 2008

JavaScript Graphing Version 2 and News

John Resig released his project, Processing.js, earlier this week. This project aims to bring Flash like graphics and visual effects to JavaScript using the Canvas tag and a JavaScript compiler for Processing Language. The demos are amazing and causing quite a lot of buzz. Processing.js also provides an opportunity to improve the JavaScript Graphing system that I have been working on. However, that is a project for another day.

For today, lets take a look at the improvements I have made on the code for Visual Graphing in JavaScript. You can play with the new code at the Grapher Beta Test Page. You will immediately notice that there is now a title and legend for the graph, and extra buttons beneath the graph. The legend and title can be controlled by setting additional configuration properties:

Example 1: New Configuration Properties

config.title = config.title || ”; config.defaultColor = config.defaultColor || ‘#000′; config.defaultLabel = config.defaultLabel || ‘Line 1′; config.hasLegend |= false;

If you want your graph to have a title, you simply need to set the ‘title’ property, and it will be automatically rendered. You can update the title, by calling the new global method, ‘updateTitle’ on an instance of the Grapher object. I have also introduce line coloring and labeling; set the defaultColor and defaultLabel to override the initial values. For the legend and line labels to appear, you need to set the ‘hasLegend’ property to true, automatically rendering the legend.

The Grapher object now also allows one to draw any number of lines on the same graph. The internal ‘points’ Array has been converted to a ‘pointSet’ Array, which is a collection of Objects containing the configuration and collection of points for each line. The public ‘exec’ method has been updated to support the legend, line coloring, and multiple lines:

Example 2: Changes to ‘exec’

exec: function(eq, isNew, color, label) { if (! isNew) { clearPoints(); clearLegend(); } var o = {color: color || config.defaultColor, equation:eq, label: label || ‘Line ‘ + (pointSet.length + 1), points: []}; pointSet[pointSet.length] = o; drawLine(eq, o.points, color); if (config.hasLegend) { addLegendLabel(o.label, o.color); } },

In addition to the ‘eq’ parameter, there is now 3 others: ‘isNew’ should be set to true when this should be added to the existing graph, otherwise the existing graph will be replaced with the provided equation and only that equation; ‘color’ is the color you would like the new line to be set to; and ‘label’ is the label to add to the legend for the line, assuming the configuration ‘hasLegend’ is true.

The new Grapher Beta Test Page has 3 new buttons in order to test some of the new features. The first button, now ‘Draw 1 Line’, behaves as the old demo page did. The second button, ‘Add new Line’, adds a new line to the current graph (I have set it to generate a random color). The third button, ‘Redraw’, calls the public ‘redraw’ method, and is used to test that the graph is properly redrawn. The last button, ‘Reset’, returns the graph to its initialized state.

As I see it, there are three improvements still required before I can call this project complete: 1) validating the equation before ‘eval’ to prevent hacking attempts and broken logic, 2) additional configuration properties so that one has greater control over graph, and 3) experiment with using Processing.js to handle the graph rendering.

posted by Matt Snider at 2:55 pm  
« Previous PageNext Page »

Powered by WordPress