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!

Number#snap Useful JavaScript Game Extension #25

Well my friends, it’s been quite some time. So without further ado back to the series!

/**
 * Returns the the nearest grid resolution less than or equal to the number. 
 *
 *   EX: 
 *    (7).snap(8) => 0
 *    (4).snap(8) => 0
 *    (12).snap(8) => 8
 *
 * @param {Number} resolution The grid resolution to snap to.
 * @returns The nearest multiple of resolution lower than the number.
 * @type Number
 */
Number.prototype.snap = function(resolution) {
  return (this / resolution).floor() * resolution;
};

This handy method is useful for when you need to snap input to a grid (like in a tile editor).

I hope you enjoyed this installment of the wonderful 256 part series on JavaScript game extensions.