PicNet Custom Software Development

.Net and Javascript Development

Annotated, Google Closure Javascript Compiler - Visual Studio Snippets

Posted on clock June 3, 2010 09:12 by author guido

I have spoken in the past about my great respect for the closure project.  This project brings some semblance of order to the chaotic and dangerous world of large application javascript development.  However it also has some problems, the biggest of this being the fact that it is very verbose.  This small set of Visual Studio 2010 snippets aims to aliviate that issue when developing in VS2010.  I have been using a similar set of these snippets in production for many months (in the Mouse Eye Tracking service) and whilst not being industrial strength they are ready for you to get some efficiencies from.

Why Visual Studio?

At PicNet most of our server side code is .Net so when developing html and javascript we also use Visual Studio (saves opening up a new IDE).  However the snippet template language is just XML so if you are interested in doing an XSLT into another language please get in contact with me and we can bring that into the project also.

How to install

 

  • Download the vsi file
  • Run (double click - will be recognized by Visual Studio) and install
  • Ready to use (by typing the shortcut name followed by TAB)

 

Note: The VSI file is just a zip file with the extension renamed so if you are worried about running strange files just rename to .zip and import the snippets manually into the IDE.

Current Snippets

ShortcutContentDeclarations
jsclass
/**
 * @fileoverview $classcomments$
 *
 */
goog.provide('$namespace$.$classname$');
goog.require('$require$');
/**
 * @constructor
 * @param {string} $param1$ A sample parameter.
 */
$namespace$.$classname$ = function($param1$) {
	$contents$
};
  • classcomments: Comments describing this class
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • require: Classes to import
  • param1: The name of the first constructor parameter.
  • contents: The contents of the class.
jsconst
/**
 * @const
 * @type {$typename$}
 */
$namespace$.$constname$ = $constvalue$;
  • typename: The type of this constant.
  • namespace: The namespace that this constant resides in.
  • constname: The name of this constant.
  • constvalue: The value of this constant.
jsconstructor
/**
 * @constructor
 * @param {string} $param1$ A sample parameter.
 */
$namespace$.$classname$ = function($param1$) {
	$contents$
};
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • param1: The name of the first constructor parameter.
  • contents: The contents of the class.
jsenum
/**
 * $enumcomments$
 * @enum {string}
 */
$namespace$.$enumname$ = {
  ON: 'on',
  OFF: 'off'
};
  • enumcomments: Comments describing this enumeration
  • namespace: The name of this class' namespace
  • enumname: The name of this enumeration
jsextends
* @extends {$namespace$.$inherits$}
  • namespace: The name of this class' namespace
  • inherits: The name of the inherited class
jsimpclass
/**
 * @fileoverview $classcomments$
 *
 */
goog.provide('$namespace$.$classname$');
goog.require('$require$');
/**
 * @constructor
 * @implements {$namespace$.$implements$}
 * @param {string} $param1$ A sample parameter.
 */
$namespace$.$classname$ = function($param1$) {
	$contents$
};
  • classcomments: Comments describing this class
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • implements: The name of the implemented interface
  • require: Classes to import
  • param1: The name of the first constructor parameter.
  • contents: The contents of the class.
jsimplements
* @implements {$namespace$.$implements$}
  • namespace: The name of this class' namespace
  • implements: The name of the implemented interface
jsinherits
goog.inherits($namespace$.$classname$, $namespace$.$inherits$);
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • inherits: The name of the inherited class
jsinterface
/**
 * @fileoverview $interfacecomments$
 *
 */
goog.provide('$namespace$.$interfacename$');
goog.require('$require$');
/**
 * @interface
 */
$namespace$.$interfacename$ = function() {};
$namespace$.$interfacename$.prototype.$methodname$ = function() {};
  • interfacecomments:
  • namespace: The name of this interface's namespace
  • interfacename: The name of this interface
  • require: Classes to import
  • methodname: A method definition in this interface.
jsparam
/**
 * @param {string} $param1$ A sample parameter.
 */
  • param1: The name of this parameter.
jsparaminline
* @param {string|number=} $param1$ A sample parameter.
  • param1: The name of this parameter.
jsprivate
		/**     
		 * @type {$typename$}
     * @private
     */
    this.$attrname$ = $declaration$;
  • typename: The name of this attribute's type
  • attrname: The name of this attribute
  • declaration: The initial declaration of this attribute
jsprivateinline
* @private
 
jsprivatevar
		/**
		 * @type {$typename$}
     * @private
     */
    var $attrname$ = $declaration$;
  • typename: The name of this attribute's type
  • attrname: The name of this attribute
  • declaration: The initial declaration of this attribute
jsprotected
		/**     
		 * @type {$typename$}
     * @protected
     */
    this.$attrname$ = $declaration$;
  • typename: The name of this attribute's type
  • attrname: The name of this attribute
  • declaration: The initial declaration of this attribute
jsprotectedinline
* @protected
 
jsprotomem
		/**
 * @param {*=} $param1$
 */
$namespace$.$classname$.prototype.$methodname$ = function($param1$) {				
		return this.member * args;
};
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • methodname: The name of this method
  • param1: The name of the sameple parameter
jsprovide
goog.provide('$namespace$.$classname$');
  • namespace: The name of this class' namespace
  • classname: The name of this class
jsrequire
goog.require('$namespace$.$require$');
  • namespace: The name of this class' namespace
  • require: Classes to import
jsreturn
* @return {string}
 
jssubclass
/**
 * @fileoverview $classcomments$
 *
 */
goog.provide('$namespace$.$classname$');
goog.require('$require$');
/**
 * @constructor
 * @extends {$namespace$.$inherits$}
 * @param {string} $param1$ A sample parameter.
 */
$namespace$.$classname$ = function($param1$) {
	$contents$
};
goog.inherits($namespace$.$classname$, $namespace$.$inherits$);
  • classcomments: Comments describing this class
  • namespace: The name of this class' namespace
  • classname: The name of this class
  • inherits: The name of the inherited class
  • require: Classes to import
  • param1: The name of the first constructor parameter.
  • contents: The contents of the class.
jstypedef
/** @typedef {$type$} */
$namespace$.$typedefname$;
  • namespace: The name of this class' namespace
  • type: The composite type of this definition
  • typedefname: The name of this typedef

License

MIT

Development

If you are interested in helping mantain the source code, let me know and we'll organise something.  

Mantaining the code is very straight forward simply:

 

  • Download the latest source.
  • Open the solution in visual studio
  • Edit the snippets in the \snippets directory
  • F5 to build a new VSI file and the supporting documentation
  • Install the VSI as described above to test your changes

 

 

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Split Testing (A/B Testing) in ASP.Net Mvc

Posted on clock May 11, 2010 10:21 by author guido

Working on our website heat maps product, Mouse Eye Tracking, has allowed us to really get into some of the more lean and super agile approaches to developing software.  Something that we have loved doing recently is Split Testing (or A/B Testing). Its really amazing how much time you can save when using techniques like this.

Basically for our heat map product we try every deployment out before investing huge amount of time into it.  For example.  We wanted to see if the features video could be made more prominent.  So what we did is created a page for this approach, published it and compared results.  We realised that this in fact was a waste of time and left the page exactly as it was.

There are plenty of products out there that allow you to do AB testing but most of those are CMSs which is useless when your site is in a server side language so what we use is a custom ASP.Net Mvc solution that works a real treat.  It's this solution that I hope to describe in this post.

SplitABController

The brains of the whole operation is a new controller (descendant of System.Web.Mvc.Controller) that allows you to provide multiple views for each ViewResult.  This is kind of hard to explain so why not just show some code:

 

    using System;

    using System.Web;

    using System.Web.Mvc;

 

    public abstract class SplitABController : Controller

    {

        private static readonly Results results = new Results();

        private const string B_TEST_SUFFIX = "_B";

        private const string SPLIT_TEST_VIEW_COOKIE_NAME = "SPLIT_TEST_VIEW_COOKIE";

        private static ViewFilesCache cache;

 

        public static Results GetSplitTestResults() { return results; }

 

        protected over ride void OnActionExecuting(ActionExecutingContext filterContext)

        {

            AddSplitTestResultsToResultsMap(filterContext);

            base.OnActionExecuting(filterContext);

        }

 

        private void AddSplitTestResultsToResultsMap(ActionExecutingContext filterContext)

        {

// If last request was not for a split test view then just return

            if (Request.Cookies[SPLIT_TEST_VIEW_COOKIE_NAME] == null) return;

 

// Add this controller/action to the results of the split test

            ResultRow rr = ResultRow.FromString(Request.Cookies[SPLIT_TEST_VIEW_COOKIE_NAME].Value);

            results.RemoveOneFromResults(rr);

            rr.ToControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;

            rr.ToAction = filterContext.ActionDescriptor.ActionName;

            results.AddOneToResults(rr);                        

        }                

 

/// <summary>

/// If the view has a _B counterpart then we mark this action as a 'Split Test' we

/// then record the results of this split view in the next request (OnActionExecuting).

/// 

/// This method also determines if we should supply the A or B view depending on the

/// 'ShouldRequestUseBView' algorithm.

/// </summary>

        protected override ViewResult View(string viewName, string masterName, object model)

        {            

            if (String.IsNullOrEmpty(viewName)) { viewName = (string) RouteData.Values["action"]; }

            bool isSplitTestingView = IsSplitTestingView(masterName, viewName);            

// If this view does not have a _B counterpart then we mark this request as non split test (by

// removing the 'SPLIT_TEST_VIEW_COOKIE_NAME' cookie) and just send control to base.View

            if (!isSplitTestingView)

            {

                Response.Cookies.Remove(SPLIT_TEST_VIEW_COOKIE_NAME);

                return base.View(viewName, masterName, model);

            }               

// Wether to use the A or B view depending on the 'ShouldRequestUseBView' algorithm

            bool useb = ShouldRequestUseBView();

// Lets create a results row and store it in the cookie (SPLIT_TEST_VIEW_COOKIE_NAME). This will let the 

// next request (OnActionExecuting) know that we just hit a split test view.

            ResultRow rr = new ResultRow {FromController = this, FromAction = viewName, UsedBView = useb};

            Response.Cookies.Add(new HttpCookie(SPLIT_TEST_VIEW_COOKIE_NAME, rr.ToString()));

            results.AddOneToResults(rr);            

 

// Display the appropriate view (A or B)

            return useb 

                ? base.View(viewName + B_TEST_SUFFIX, masterName, model)

                : base.View(viewName, masterName, model);            

        }        

 

/// <summary>

/// Returns wether the specified view has a _B counterpart. 

/// </summary>

        private bool IsSplitTestingView(string masterName, string viewName)

        {

            if (cache == null) { lock (GetType()) { if (cache == null) { cache = new ViewFilesCache(B_TEST_SUFFIX); } } }           

            return cache.HasSplitTestingAlternative(this, masterName, viewName);            

        }

 

/// <summary>

/// If odd IP then use 'B' view.  This will give a ~50% A / B split.

/// </summary>

        private bool ShouldRequestUseBView()

        {            

            return Int32.Parse(Request.UserHostAddress.Substring(Request.UserHostAddress.LastIndexOf('.') + 1)) % 2 == 1;

        }

    }

 

Description

So what is this code doing, basically it checks if a view has a '_B' counterpart, i.e.: If there is an Index.spark and an Index_B.spark.  If the view does have a _B counterpart then we mark the request as a split test and on the next request we save the results of that test.

To use this code simply extend this controller rather than the standard System.Web.Mvc.Controller.

Download

I have created a very simple test project (which uses Spark View Engine) that you can download here.  

Once you get the project set up simply navigation to Home.mvc/Index (which has a '_B' view also) and you can click around there for a while.  You can then navigation to Home.mvc/SplitTestResults to see a sample of how the results are stored.

Disclosure

This code was ripped quite aggressively from a much more comprehensive library and is intended only to illustrate the technique described here.  I highly suggest you do not use the code in production until you are happy with its stability.

Potential

I have been using this technique now for 2 months and have found it a fantastic way to measure true user acceptance of new features.  I also know that there is no other open source solution for asp.net mvc that allows you to do split testing efficiently so if you would like to work with me on getting this code production ready as an open source project let me know and I'll be more than happy to spend a bit more time making this code a bit more robust and creating a project for it,

Thanks

Guido Tapia

PicNet Pty Ltd


Visitor Heat Maps in WordPress - New Plugin

Posted on clock May 4, 2010 08:13 by author guido

Hi All,

I'm pleased to announce that we have just released a new WordPress plugin that will allow you to effortlessly add the PicNet Mouse Eye Tracking service to your WordPress website / blog. Now you can see exactly what your visitors are doing on your web site and not need to change a single html file.

For full details on what Mouse Eye Tracking can do for your web site see the home page.

Download the plugin.

Screenshots

Heat Map

Heat Maps

Page Navigation

Page Navigation

Thanks

Guido Tapia

Software Development Manager

PicNet Pty Ltd


Lean css in javascript

Posted on clock April 19, 2010 08:00 by author guido

This weekend I was looking at the lesscss.org project and found it very interesting.  There is also a .net implementation.  The basic features of these projects is to make css less verbose, they do this by offering features like mixins, variables and nested rules.  Now all of this is very straight forward lexical analysis to produce raw css so I thought to myself why does this need a server side component, what if I want to have a pure html site.  I don't want php, ruby, .net, etc just to compile some css.  I also don't want an additional deployment process to compile my css.  So... Why not javascript.

I thought there must be some limitations but a very quick test shows that it is entirely possible.  So here we go:

We want to prevent the bowser from doing 2 requests to css so change all your:


<link rel='stylesheet' href='style.css'/>

With:


<link rel='lss' href='style.css'/> <!-- I have called it lss for less but it can be anything -->

This will prevent the borwser from requesting this file, which is good as we will be manually requesting them. So now lets add a script file to load and parse our lss files:


<script src="jsless.js" type="text/javascript"></script> 

Content of jsless.js (Note I'm using jQuery)

 

$('link').each(function() {

  var lss = $(this);

  var lssurl = lss.attr('href');

  // Should we make this block?  Probably, but lets leave for now

  $.ajax({url: lssurl, dataType:"text", success: function(css) { getcsscallback(lss, css); }});

});

 

function getcsscallback(lss, cssText) { 

  var vars = getVariables(cssText); 

  for (var i in vars) {

  i = trim(i);

  var val = trim(vars[i]); 

  cssText = cssText.replace(/@[A-z^:]+:.*/g, ''); // remove var line

  cssText = cssText.replace(new RegExp(i,  'g'), val); // replace replace variables

  }

  cssText = '<style>' + cssText + '</style>'; // TODO: Add media, etc, etc from the attributes of lss into this tag

  $('head').append(cssText);

}

 

function getVariables(cssText) {

  return getMatches(/(@[A-z^:]+):([^;]+);/g, cssText);

}

/// Following code is just supporting regex and string manipulation code

function getMatches(regex, text) { 

  var matches = {};

  var match = null;

  while (match = regex.exec(text)) {  

  matches[match[1]] = match[2]; 

  }

  return matches;

}

 

function trim(str, chars) {

  return ltrim(rtrim(str, chars), chars);

}

 

function ltrim(str, chars) {

  chars = chars || "\\s";

  return str.replace(new RegExp("^[" + chars + "]+", "g"), "");

}

 

function rtrim(str, chars) {

  chars = chars || "\\s";

  return str.replace(new RegExp("[" + chars + "]+$", "g"), "");

}

 

Thats it, I have a test project set up that you can use to see this in action.  You can also just click here to see the html.  The css (lss) used is here and the js is here.

 

I personally think this project has some potential so if you are interested in working with me just email me and we can set up an OS project and start from there.

 

Note, I have tested the above in chrome, firefox and IE8 and it appears to work.

 

Anyways hopefully this inspires someone to do this properly.

 

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Javascript Tips, Tricks and Hacks

Posted on clock April 14, 2010 06:08 by author guido

JavaScript is by far the most expressive language I use today, that expresiveness is a result of the amount of flexibility that the language gives the developer.  This is also the same reason why it is so hard to develop in JS, however I will not be focusing on that here.  This article is solely about the art of JS development.  I will be following this article up with a series of usefull patterns in javascript and usefull utility classes, but for now lets focus on the sugar.

Note: This article is extremely subjective so if any of the following views offend please accept this as my sincerest of apologies.

Variables

Sometimes the way you do things has no impact on the results but it just 'feels' (or 'smells' if you want to Fowler it up) better.  One very clear example is variable declaration.  Example;

var i;

var x = 10;

var y =100;

var product = x*y;

I prefer this:

var i,

     x = 10, 

     y = 100.

     product = x*y;

Why? Don't know, I just do.

Also, you must always remember that assignment always returns the value of the assignment so why not do something like:

var product;

callFunction(product = x * y);

return product;

When doing multy variable assignment (separated by ,) then the last assignment is returned.  This is rarely usefull so no sugar there.

 

Conditions

Become familiar with falsy expressions.  Use them in your conditions.

So instead of:

if (typeof console !== 'undefined' && typeof console.trace !== 'undefined') console.trace(); 

Why not?

if (typeof console !== 'undefined'  && console.trace) console.trace(); 

Also, lazy conditions (or null-coalescing) are also cool.  Example:

x = x || getDefaultValueOfX(); // Basically only call getDefaultValueOfX if x does not have a value.  Synonimouse with ?? operator in C#

 

Loops

Iteration are a very personal thing some prefer to go backwards some forwards.  Some declare their 'i' before their 'for' some think this is very silly indeed.  This is how I loop.

for (var i = 0, e; e = array[i]; ++i) { ... }

Nice...  Oops, better mention a caveat here.  The termination expression here is e = array[i] which means that if the array contains: 0, '', null, undefined, false then the iteration will finnish prematurely.

But this syntax can also be used for lots of nice expressive statements like:

for (var i = 0, e, j = array.length - 1; e = array[i]; ++i; --j) { ... } 

How About:

for (var e; entries.length && (e = entries.shift());) { ... } // Awesome I hear you say?

etc, etc

 

Arrays

Arrays in javascript are very interesting, they are like an object with growths.  Some of those growths are very usefull but the fact that its still an object is pretty awesome also. So:

var x = [1, 2, 3 , 4];

x.max = function() {

 var m = Number.MIN_VALUE; 

 for (var i = 0, v; v = this[i]; ++i) { if (v > m) { m = v; } }

 return m;

}

How about (Continued from above):

x.length = 100;  // This actually increased the size of the array to 100 and filled in gaps with undefined

x.length = 2;  // This will shorten the array and 'delete' all enties above the specified index.

Something that needs to be mentioned here is the awesomeness of delete.  This marks a memory space for garbage collection so its a great way to ensure that something is infact 'deleted'.

Also, I highly suggest getting to know splice.  He can be a good friend.

 

Augmentation

The previous example (array x.max) is actually a form of augmentation but this concept can be taken even further and one of the pretties uses of this is a Crockfordian parasitic inheritance.  Let's have a look:

function Animal() {

 this.tallk = function() { return "Oink! Oink!"; }

}

 

function Dog() { // Dog will extend Animal parasitically (does that word exist?)

 var d = new Animal();

 d.talk = function() { return "Woooof, Grrrrrrrrrrr!"; }

 d.playDead = function() { return '.............'; }

}

alert(new Dog().talk());

There we go, we just implemented inheritance without ugly .prototype (s) and other nasties. 

 

Closures

If you ever have a chat to a Ruby developer they will probably bore you half to death with their preaching about the beaty of a closure, anyways JS has closures also, but javascript is a more practical language so we don't don't preach we just do.

Have you ever done this:

somearray.sort(function(a, b) { return a - b; });

We'll Array.sort takes in a cloure.  So closure is basically just a function that can be passed around and reused.  This is actually an amazingly powerful feature and can open a lot of doors when designing complex systems.  However, care must be taken when using closures, the context and hence the memory used up by the context of a function remains in memory as long as the closure is alive.  This is a common casue of JS memory leaks.

 

Hashtables (Dictionaries)

Objects are dictionaries.  This is actually a very usefull data structure so don't ignore it.

var dict = {};

dict['property1'] = prop1;

dict['property2'] = prop2;

dict['sub'] = function() { return this.propert1 + this.property2; };

 

Namespaces

Namespaces are usefull, they allow you to nicely modularise your code and prevent your code from clasing with other's code.  Namespacing in javascript is very easy.  I suggest the following approach:

// Create the namespace (using the uril finction below)

namespace('au.com.picnet.scripts');

 

// Add a class to the namespace

au.com.picnet.scripts.TestClass = function() {

 this.test = function() { alert('test'); }

};

 

// Instantiate the class and call test()

new au.com.picnet.scripts.TestClass().test();

 

// A safe namespace generator, can be called many times 

// with the same ns fragmens without fear of loosing objects.

function namespace(ns) {

 ns = ns.split('.');

 var current = window;

 for (var i = 0, n; n = ns[i]; ++i) {

 if (!current[n]) current[n] = {};

 current = current[n];

 }

}

 

Function Scope

The previous example of namespaces shows function scoping in action.  Function scope simply means that a function only has access its own members and its parent memebers (if it is nested).  So a parent funciton does not have access the the members of the nested function unless they are public.  This is actually a complex toic that I may explore further in its own article but for the time being I recommend reading this.

 

This!!

The this keyword is also a tricky beast especially when it can be manipulated with Function.apply and Function.call.  But generally this points to the current function (not the current function literal) or else the global scope.  Again too complex for this article but read this.

Note I generally try not to rely on 'this' very much.  If I need to access 'this' in future I generally create a temp variable that I can use:

var instance = this

This variable is created at a point I know that 'this' points to the right object and then don't worry about the technicalities.

 

Static Classes (Singleton, Utility Classes)

Object literals actually make great singletons.  Let see an example:

namespace('au.com.picnet.scripts');

au.com.picnet.scripts.Utilities = {

 add: function(x, y) { return x + y; },

 subtract: function(x, y) { return x - y; }

};

alert('add: ' + au.com.picnet.scripts.Utilities.add(1, 2) + ' subtrace: ' + au.com.picnet.scripts.Utilities.subtract(1, 2));

 

RegExp

The RegExp is an awesomly powefull object, it can make a 100 line parsing function vanish in a puff of elegance.  Howewer!!!!!  If you are anything like me, you need to use RegExps roughly 2-3 times a year.  The other times you just copy a previous use of the same regexp.  So when that time of year comes around you ask yoursel: How the hell do I do named groups again?

Well I have found that the best way to work with RegExs is to ignore them until needed.  When you do need a regex simply give yourself a 5 minute refresher here and make sure you test your regex thrououghly in places like here.  

I personally recommend not wasting too long getting good at RegExps as they are so rarely needed.  I have actually been good at RegExps several times but that all goes away... I have now accepted it.

 

Misc

- Always use '===' instead of '==' .

- Functions have a length attribute.  This is the length of expected parameters.

- Functions have an argumens array with all the arguments passed to the function, regardless of function signature.

 

Restraining the Beast

Javascript does give the developer too much rope, this is nice when trying to flex your creative powers but can become overpowering when working on large systems.  There are a number of tools which now allow you to try to tame this beast.  And at the top of the list is GWT (And other such projects).  However this is an extreme solution to this problem I personally like Javascript and don't really want to stop using it unless there are clear advantages on a project.  So some of the tools I use and look interesting are:

- Google's Closure Compiler : Adds some type safety to your beast (with annotations)

- FireBug : Don't leave home without it

- DOM / Ajax Helper Libs (jQuery, dojo, prototype, closure libs, etc): A must for cross browser development (I personally use jQuery as it seems to have won the popularity contest and regardless what the 'hardcore' tell you, this is actually very important)

 

The next generation of JS IDEs are also very exiting, leading this list are:

- WebStorm

- Visual Studio 2010

 

So Notepad++'s domination of the js development world may be comming to an end soon.  Ahhh I actually have dreams of accurate type inferrence in real time for a JS IDE.

 

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Google Explorercanvas (excanvas) for IE. Silverlight vs VML

Posted on clock March 15, 2010 05:08 by author guido

 

Many people do not realise that excanvas has a silverlight implementation.  This implementation is apparently less stable (I have had very few issues with it) but much much faster.  The only real draw back as I see it is that it requires clients to have silverlight installed (stat owl has this penetration rate at about 40%).

I use excanvas (silverlight) to allow support IE users to use the Mouse Eye Teracking Service.  Now this is a highly graphical intensive application so the demands I put on my canvas tag are huge.  The standard excanvas (VML) implementation just did not cut it at all however the silverlight version has allowed me to support IE.

The purpose of this article is to more intelligently compare the performance of both ex canvases.  I have used slightly modified versions of the excanvas test cases for performance measures.  You can download all the tests here.

 

All tests were run in IE8 on a poor spec Win XP box. This may be quite a limited but it suffices to give us a comparison between VML excanvas and silverlight excanvas.  The tests measure the time taken to do 200 iterations of the mentioned test.  Please see the source code of the tests for more details.

Note: I am using the dev versions of excanvas from here.


TestVML (ms)Silverlight (ms)x times faster
Arc 1250 562 2.22
Clearpath 1109 281 3.95
Colors 9141 1906 4.8
DrawImage 3156 234 13.49
DrawImageFlip 128812 n/a n/a
Gradient 828 406 2.04
Gradient2 1359 422 3.22
LineWidth 378669 18953 19.98
Overflow 6859 344 19.94
Overlay 2703 n/a n/a
Pattern 3140 n/a n/a
QuadraticCurve 5032 n/a n/a
Resizing n/a n/a n/a
Restorepath 2484 n/a n/a
StrokeScaleAndRotate 7860 n/a n/a
StrokeShouldNotClosePath 4766 n/a n/a
Text 6844 n/a n/a

Conclusions

We can see that the silverlight excanvas has very limited support for many features.  However the features it does support are many multiples faster (2 - 20 times faster).  So if you are not using the advanced features, use silverlight.

 

Thanks

 

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Automatic Google Page Position Report

Posted on clock March 10, 2010 06:38 by author guido

Overview

The position of your website in the Google organic search is quickly becomming one of the most critical marketting measures.  This page/script will allow you to automate this process.

How To

  • Sign up for a google Ajax API Key (http://code.google.com/apis/ajaxsearch/signup.html)

- You will get a jsapi key from google, something like this

            'ABQIAXFEakaXw3_Fd-

zqqMhjDLzqaRTTser7lsytcEDBoz0jKRWQmOpxexR7x409podV88a5eoPr2KIvw8Ub3B'

 

 

            (Note this is not a valid key)

  • Download this html page/script and rename to .html (remove .txt extension)

  • Open this page in a text editor (note pad is just fine)

  • Replace <YOUR JSAPI KEY> (Line 53) with, you guessed it, your jsapi key.

  • On line 59 you will see the configuration for this file, you will need to change the following items

- lookfor (Line 66, 78, 87).  These tell the script what to look for in the url and youtube title.

 

- On line 75, replace "Sydney, NSW" with a location that you think some of your clients would be searching from. 

  • On line 228 the lookup table rows begin.  You can add as many rows as you wish here.  The rows must be in the format (replace <Search term or phrase>):


<tr><td><Search term or phrase></td></tr>

  • You can have headers by adding rows in this format:


<tr class='header'><th>This is a header row</th></tr>

  • Open the file in your browser and click 'Run Report'


Thats it, when the table is working you will get something that looks like this:

 

Let me know if you have any problems with this.

 

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


How to prevent 'Stop running this script' message in browsers

Posted on clock March 4, 2010 07:23 by author guido

Avoiding the 'Script taking too long' (all browsers have some form or another of this) message in browsers is relatively simple. You just have to make sure the browser knows you have not created an endless loop or recursion. And the easiest way to do is is to just give the browser a breather in between long running tasks.

So how would we go about this.  Well the simplest solution is to just break up your task into mutliple smaller tasks with a setTimeout in between these tasks.  The utility class below does just this:

Utility Class


RepeatingOperation = function(op, yieldEveryIteration) {
var count = 0;
var instance = this;
this.step = function(args) { 
if (++count >= yieldEveryIteration) { 
count = 0;
setTimeout(function() { op(args); }, 1, [])
return;
}
op(args); 
}; 
};

So how do we use this class, lets say we have the following code which is giving us a jerky browser and occasionally displaying those horrible 'Stop running this script' message:


// initdata is just an array of numbers (a very very large array)
var test1 = new Array(initdata.length);
for (var i = 0; i < initdata.length; i++) { test1[i]  = initdata[i] * 2; } // Double each item in the initdata array
continueOperations();

To use the utility class above we would change the code to this:


var test2 = new Array(initdata.length);
var i = 0;
var ro = new RepeatingOperation(function() {
test2[i] = initdata[i] * 2;
if (++i < initdata.length) { ro.step(); }
else { continueOperations(); }
}, 100);
ro.step(); 

That's it, a little bit more code, an extra closure, so not pretty but I think a relativelly stylish solution to a nasty problem.  Note: Remember this will also give you a much more responsive browser during execution of this expensive code also.

Note: This solution is used in the Mouse Eye Tracking system.  So it is production ready (at your own risk tho).

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd

 


Introducing Mouse Eye Tracking - Tunnel Vision

Posted on clock February 19, 2010 08:46 by author guido

One question that has been asked of me a few times since the release of the PicNet Mouse Eye Tracking Service is that of accuracy. How acurate can the Mouse Eye Tracking service correlate eye activity from mouse activity. We have done a lot of testing on this topic and we believe that the correlation is significant. In fact it was significant enough for us to invest a huge amount of time and effor in producing this product. We are also highly encouraged by the academic research in this field that supports our own tests (See product home page for links to this research).

However, we are aware that the accuracy is not 100% and it will never be. If you want 100% accurate data about activity on your site you need to use eye tracking. However this also has many downsides. One of the ways that we try to increase the correlation between mouse and eye is by using an as yet undocumented feature called Tunnel Vision.

Tunnel Vision tries to encourage the user to use the mouse to view the page whilst attempting not to alter the normal behavior of the user on the page. Lets have a look at tunnel vision in action:

Tunnel Vision Off


Tunnel Vision On


As you can see, tunnel vision creates a tunnel around the user's mouse giving you a clear area of vision around the cursor but more importantly tunnel vision still allows the user's peripheral vision to look around the page in preparation for the next area of focus.

I encourage you to try tunnel vision in your closed testing (Do not put this on your live site!!!) and see the results for your self.

Turning On/Off
To turn on tunnel vision simply add (use-tunnel-vision="true") to your PicNetEyeTracker span. i.e:


<span id='PicNetEyeTracker' usercode='picnetpilot' use-tunnel-vision="true">...


To turn off tunnel vision simply remove this tag or set use-tunnel-vision to "false".

I hope this feature helps you get that extra level of accuracy with your mouse/eye tracking.

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Html Web Worker Woes - Data Analysis not an Option

Posted on clock February 18, 2010 04:25 by author guido

During development of the PicNet Mouse Eye Tracking service I carefully investigated the possibility of using Html Web Workers.

After careful reading of the specs I thought this would be great but after some initial tinkering I found that communications between threads was done through the postMessage feature supported by modern browsers.

This instantly raised some suspicions as I know that this is a text only feature, I know FF will auto serialize/deserialize to/from JSON but this as expected performs pretty poorly for large data sets. But I gave it a benefit of the doubt thinking that there was no way that someone would go to the extreme pains of implementing a threading framework and cripple it by not allow memory references to be passed between threads.

WRONG!!! And now I can say that the new threading features in browsers is only usefull for making the UI more responsive. Now don't get me wrong thats great and a huge relief not to be having to use setTimeout hacks everywhere but seriously?? Why would you break my heart like that?

Threading is critical in calculation intensive or data analysis intensive applications. The PicNet Mouse Eye Tracking service is a great example of this. The javascript engine gets a whole bunch of mouse coordinates and from this data we render heat maps, curved mouse tracks, etc, etc. This is a huge amount of calculations that lock the browser JS thread but it is impossible for me to use web workers. Why is that?

The cost of postMessage
postMessage can transfer strings between threads. But it is very rare that data requiring analysis is solely string based, mostly we are working with other primative types as well such as numbers, booleans, DateTimes, etc. And the cost of converting (serializing) strings to/from these data types is huge. After some early prototypes I tossed the idea of using Web Workers aside. I know this is very early days in the life of Web Workers but I was quite taken aback by this crippling flaw in the specs.

Lets look at numbers
K, lets support my whinging with numbers. Below is a table that shows an expensive operation on an array of numbers. We process the array using the specified number of threads. Note: Refresh to see it running in real time:

Run Test
1 Threads2 Threads3 Threads4 Threads5 Threads
IdleIdleIdleIdleIdle


Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd