Operator Overloading in PaperScript

I was looking into how paper.js did their operator overloading and what I found was pretty clever:

var operators = {
  '+': 'add',
  '-': 'subtract',
  '*': 'multiply',
  '/': 'divide',
  '%': 'modulo',
  '==': 'equals',
  '!=': 'equals'
};
 
function $eval(left, operator, right) {
  var handler = operators[operator];
  if (left && left[handler]) {
    var res = left[handler](right);
    return operator == '!=' ? !res : res;
  }
  switch (operator) {
  case '+': return left + right;
  case '-': return left - right;
  case '*': return left * right;
  case '/': return left / right;
  case '%': return left % right;
  case '==': return left == right;
  case '!=': return left != right;
  default:
    throw new Error('Implement Operator: ' + operator);
  }
};

Though technically this is PaperScript and not JavaScript, so they can get around the lack of native JS operator overloading. The PaperScript code is given a minimal compile pass which replaces calls to arithmetic operators with calls to $eval().

// PaperScript
var p = new Point(10, 20);
var r = p * 5;
 
// JavaScript
var p = new Point(10, 20);
var r = $eval(p, "*", 5);

Related PaperScript source

So as long as Point#multiply is defined then the operator is effectively overloaded.

I’m very interested in the implications for PixieEngine and CoffeeScript.

Better window.requestAnimationFrame Shim

There’s been quite a bit of copy/pasting of the compatibility shim for requestAnimationFrame going around on the Net, which is all fine and dandy, but sadly the popular shim isn’t compatible with passing in the timestamp on the setTimeout fallback.

Here’s the improved one:

window.requestAnimationFrame ||= 
  window.webkitRequestAnimationFrame || 
  window.mozRequestAnimationFrame    || 
  window.oRequestAnimationFrame      || 
  window.msRequestAnimationFrame     || 
  (callback, element) ->
    window.setTimeout( ->
      callback(+new Date())
    , 1000 / 60)

Also, a JavaScript version for those of you who have suffered the misfortune of not choosing to use CoffeeScript.

window.requestAnimationFrame || (window.requestAnimationFrame = 
  window.webkitRequestAnimationFrame || 
  window.mozRequestAnimationFrame    || 
  window.oRequestAnimationFrame      || 
  window.msRequestAnimationFrame     || 
  function(callback, element) {
    return window.setTimeout(function() {
      callback(+new Date());
  }, 1000 / 60);
});

Take notice of the param passed to the callback +new Date(). It’s the timestamp that leading implementations pass in.

It has also been rumored that Chrome10 doesn’t pass in the timestamp either, so for super reliability you’ll want to have timestamp ||= +new Date() as the first line of your callback as well.

There were also several issues mentioned in this gist which have not been decisively resolved, so any feedback is certainly welcome. I also decided to just polyfill that ‘ish, because it seems legit enough.

Good luck and Godspeed.

LiveEdit

You know those edit in place plugins for jQuery? Well I couldn’t find any that met these two criteria:

  1. Work on elements not yet in the DOM
  2. Didn’t post anything to the server

Now the first requirement probably makes a lot of sense to you, but I bet you’re wondering about the second one. In these crazy mixed up times with rich HTML5 apps, I don’t want to post to the server often. Maybe I’m using local storage, or perhaps I just want to send a big heap of JSON now and again, but I definitely don’t want to post every time anyone changes the value of an editable field.

So after examining all the terrible options (classic first step when choosing jQuery plugins) I decided to throw my own terrible option into the mix.

(($) ->
  $.fn.liveEdit = () ->
    this.live 'dblclick', () ->
      $this = $(this)
 
      return if $this.is("input")
 
      textInput = $("<input/>",
        class: $this.attr("class")
        "data-origType": this.tagName
        id: if id = $this.attr("id") then id else null
        type: "text"
        value: $.trim($this.text())
      )
 
      $this.replaceWith textInput
 
      textInput.focus().select()
 
    this.live 'blur keydown', (event) ->
      if event.type == "keydown"
        return unless event.which == 13 || event.which == 9
 
      $this = $(this)
 
      return if $this.data("removed")
      return unless $this.is("input")
 
      $this.attr("data-removed", true)
 
      $this.replaceWith $("<" + $this.data("origType") + " />",
        class: $this.attr("class")
        id: if id = $this.attr("id") then id else null
        text: $this.val()
      )
 
    return this
 
)(jQuery)

There are two tricks here. The first is that this plugin is really a macro that makes two calls to live. The second is that the editable content keeps it’s same id and class when switched out to a text field, so as long as your selector is not based on the element type it will work. There’s plenty of room for improvements, but this is a super simple first step that meets my needs. Enjoy!

jQuery Plugin: TakeClass

This comes up all the time, you have an element, and you want to select it to be the sole active element from among it’s siblings. With jQuery that is simple enough:

element.addClass("active").siblings().removeClass("active")

Though it is not as simple as it can be and it also fails to chain well. The solution is a super simple jQuery plugin:

(($) ->
  $.fn.takeClass = (name) ->
    this.addClass(name).siblings().removeClass(name)
 
    return this
)(jQuery)

Now you can really go nuts!

newElement.appendTo(layerSelect).takeClass("active").find(".name").mousedown()

Optimizing JSDoc Toolkit for Large JS Files

Recently I was running into a problem with JSDock Toolkit where it would throw an error saying js: exception from uncaught JavaScript throw: java.lang.OutOfMemoryError: Java heap space.

The solution was to add the -s flag so that it would not try and generate a large, marked-up source file for viewing with the docs.

java -jar jsdoc-toolkit/jsrun.jar jsdoc-toolkit/app/run.js gamelib.js -d=docs -n -s

I also added the -n flag to prevent it from documenting methods that didn’t have comments, such as minified jQuery or Box2d, though this was irrelevant in preventing the js: exception from uncaught JavaScript throw: java.lang.OutOfMemoryError: Java heap space error.

Capistrano Rails: A group writable tmp directory

Maybe you’ve run into [out :: …] rm: cannot remove `/…/releases/20110221192810/tmp/restart.txt’: Permission denied

I did. The reason was because we were deploying with multiple users and when the tmp directory was being created it was not set to group writable.

Fortunately it is an easy fix, just add this into your cap deploy script:

after :deploy do
  run "chmod -R g+w #{release_path}/tmp"
end

jQuery Drag Image From Desktop Plugin

Here’s the CoffeeScript for a jQuery plugin I wrote that makes accepting images dragged in from the desktop super easy. The event.fix part at the beginning is because jQuery currently doesn’t pass on the dataTransfer attribute of events. Once that’s taken care of we create the plugin.

(($) ->
  $.event.fix = ((originalFix) ->
    (event) ->
      event = originalFix.apply(this, arguments)
 
      if event.type.indexOf('drag') == 0 || event.type.indexOf('drop') == 0
        event.dataTransfer = event.originalEvent.dataTransfer
 
      event
 
  )($.event.fix)
 
  $.fn.dropImageReader = (callback) ->
    stopFn = (event) ->
      event.stopPropagation()
      event.preventDefault()
 
    this.each () ->
      element = this
      $this = $(this)
 
      $this.bind 'dragenter dragover dragleave', stopFn
 
      $this.bind 'drop', (event) ->
        stopFn(event)
 
        Array.prototype.forEach.call event.dataTransfer.files, (file) ->
          imageType = /image.*/
          if !file.type.match(imageType)
            return
 
          reader = new FileReader()
 
          reader.onload = (evt) ->
            callback.call(element, file, evt)
 
          reader.readAsDataURL(file)
 
)(jQuery)

The plugin takes a callback that will be called when any of the matched elements receive an image file via the drop event. Here’s an example usage:

$(".tiles").dropImageReader (file, event) ->
  img = $ "<img/>",
    alt: file.name
    src: event.target.result
    title: file.name
 
  $(this).append img

For image drops all you really care about is the file name and the data url, but if for some reason you need different file results here’s the line to modify: reader.readAsDataURL(file). You can also extend or alter what is passed to the callback if this is too mundane for your needs.

And here’s the JS version for anyone eager to copy/paste:

  (function() {
    $.event.fix = (function(originalFix) {
      return function(event) {
        event = originalFix.apply(this, arguments);
 
        if (event.type.indexOf('drag') === 0 || event.type.indexOf('drop') === 0) {
          event.dataTransfer = event.originalEvent.dataTransfer;
        }
 
        return event;
      };
    })($.event.fix);
 
    $.fn.dropImageReader = function(callback) {
      var stopFn;
 
      stopFn = function(event) {
        event.stopPropagation();
        event.preventDefault();
      };
 
      return this.each(function() {
        var $this, element;
 
        element = this;
        $this = $(this);
 
        $this.bind('dragenter dragover dragleave', stopFn);
 
        $this.bind('drop', function(event) {
          stopFn(event);
 
          Array.prototype.forEach.call(event.dataTransfer.files, function(file) {
            var imageType, reader;
 
            imageType = /image.*/;
            if (!file.type.match(imageType)) {
              return;
            }
 
            reader = new FileReader();
 
            reader.onload = function(evt) {
              return callback.call(element, file, evt);
            };
 
            reader.readAsDataURL(file);
          });
        });
      });
    };
  })(jQuery);

Happy image dropping!

Array#invoke Useful JavaScript Game Extension #24

Array#invoke is a method to make the common task of inoking a method on all elements in an array easier. Though you could use your own anonymous function as a map or each iterator to achieve the same result, this shortcut method makes it clear what the intention is and removes the extra syntax clutter.

What invoke does is to call the named method on each element in the array, passing in any arguments if given.

/**
* Invoke the named method on each element in the array
* and return a new array containing the results of the invocation.
*
* @param {String} method The name of the method to invoke.
* @param [arg...] Optional arguments to pass to the method being invoked.
*
* @type Array
* @returns A new array containing the results of invoking the 
* named method on each element.
*/
Array.prototype.invoke = function(method) {
  var args = Array.prototype.slice.call(arguments, 1);
 
  return this.map(function(element) {
    return element[method].apply(element, args);
  });
};

Here are some examples of it in action:

[1.1, 2.2, 3.3, 4.4].invoke("floor")
=> [1, 2, 3, 4]
 
['hello', 'world', 'cool!'].invoke('substring', 0, 3)
=> ['hel', 'wor', 'coo']

The result of each invocation is returned in an array. This allows for easy chaining of data transformations:

values.invoke("scale", 4).invoke("subtract", 3)...

Fans of Ruby and Rails will know about Symbol#to_proc, a closely related idiom:

names = people.map &:name

Thanks for reading!

Select and Reject – Useful JavaScript Game Extensions #22 and #23

Remember back when we discussed Array#partition? Cool, because having a partition method makes these next two a breeze!

/**
 * Return the group of elements for which the iterator's return value is true.
 * 
 * @param {Function} iterator The iterator receives each element in turn as 
 * the first agument.
 * @param {Object} [context] Optional context parameter to be
 * used as `this` when calling the iterator function.
 *
 * @type Array
 * @returns An array containing the elements for which the iterator returned true.
 */
Array.prototype.select = function(iterator, context) {
  return this.partition(iterator, context)[0];
};
 
/**
 * Return the group of elements for which the iterator's return value is false.
 * 
 * @param {Function} iterator The iterator receives each element in turn as 
 * the first agument.
 * @param {Object} [context] Optional context parameter to be
 * used as `this` when calling the iterator function.
 *
 * @type Array
 * @returns An array containing the elements for which the iterator returned false.
 */
Array.prototype.reject = function(iterator, context) {
  return this.partition(iterator, context)[1];
};

We can cheat quite a bit by delegating the brunt of the work to partition and just return the partition that matches what we want, the true partition in the case of select, and the false partition in the case of reject.

Another thing to note is that in most modern browsers JavaScript already has an equivalent method to select implemented. It’s called filter. It may make sense to use select as an alias for filter, in the cases where it exists.

The important thing to notice is that by implementing robust extensions that are general it opens the door for simpler implementations of specific common cases. This in turn leads to an increase in consistency and a reduction of errors because there is only one method that does the real work instead of several similar methods. When the code changes there is only one place necessary to make the change in rather than many places, and that’s always a good thing.