###*
Calling a debounced function will postpone its execution until after
wait milliseconds have elapsed since the last time the function was
invoked. Useful for implementing behavior that should only happen after
the input has stopped arriving. For example: rendering a preview of a
Markdown comment, recalculating a layout after the window has stopped
being resized...
lazyLayout = calculateLayout.debounce(300)
$(window).resize(lazyLayout)
@name debounce
@methodOf Function#
@returns {Function} The debounced version of this function.
###
Function::debounce = (wait) ->
timeout = null
func = this
return ->
context = this
args = arguments
later = ->
timeout = null
func.apply(context, args)
clearTimeout(timeout)
timeout = setTimeout(later, wait)
Already I can see an important use for it. In the code editor we copy out the buffer every keyup. This can lead to a bunch of extra work for the browser when typing. Usually it’s not a big deal because the files are generally small, but on larger files it can add up and cause some lagging. When using debounce the editor will only trigger after enough milliseconds have elapsed since the end of new keyup events. This will keep the IDE from lagging on larger files while you are typing.
Another place debounce is useful is in a game that implements a Halo style health regeneration. Every time the player takes damage a debounced startRegen function could be called. That way the regen will only start after enough time without taking damage has elapsed. In the game version it would probably be better to constrain it to ticks of the engine, or engine elapsed time for more accuracy.
I’m always a big fan of Function functions, they are a great way to reduce boilerplate and solve higher-order problems.
Pasting anything other than simple text into the browser has historically been stupendously impossible. Until now… It’s a miracle, image data pasted into the browser can be retrieved with JavaScript (at least since Chrome 13.0.782.220)! Just use this jQuery plugin and start receiving paste events with images all their sweet gooey image data. This picks up paste events initiated with Ctrl+V, it does not provide arbitrary clipboard access (which is probably sane from a security standpoint). What’s insane is that it used to be so hard to get pasted image data, but that is all behind us now.
Copy and paste me in this webpage!
Give it a try now, right click this wizard and choose “Copy Image”, then jam Ctrl+V or Command+V. Be amazed (unless you’re not using Chrome, and in that case, get off my lawn). It also works in the pixel editor on PixieEngine. Use the wizard there too, the editor currently only handles small images. Generally there is no size restriction, you can even paste image data from your favorite image editing programs, boot one up and try it out on this page.
# Created by STRd6
# MIT License
# jquery.paste_image_reader.js.coffee
(($) ->
$.event.fix = ((originalFix) ->
(event) ->
event = originalFix.apply(this, arguments)
if event.type.indexOf('copy') == 0 || event.type.indexOf('paste') == 0
event.clipboardData = event.originalEvent.clipboardData
return event
)($.event.fix)
defaults =
callback: $.noop
matchType: /image.*/
$.fn.pasteImageReader = (options) ->
if typeof options == "function"
options =
callback: options
options = $.extend({}, defaults, options)
this.each ->
element = this
$this = $(this)
$this.bind 'paste', (event) ->
found = false
clipboardData = event.clipboardData
Array::forEach.call clipboardData.types, (type, i) ->
return if found
if type.match(options.matchType) or clipboardData.items[i].type.match(options.matchType)
file = clipboardData.items[i].getAsFile()
reader = new FileReader()
reader.onload = (evt) ->
options.callback.call element,
dataURL: evt.target.result
event: evt
file: file
name: file.name
reader.readAsDataURL(file)
found = true
)(jQuery)
Pretty simple plugin, eh? The first part is extending the copy and paste events in jQuery with the clipboardData object. Once the paste events have been extended with all the clipboard data that Chrome provides we can use that data to extract the image contents.
The meat of the plugin is binding a paste event to all the elements in the selector. When a paste event is triggered we loop through each MIME type until we hit one that claims to be an image. Once we find it we get the corresponding file data and load it as a dataURL. This can be used directly in CSS or passed on to the server and chopped up, base64 decoded, and stored as a regular png.
To use it you choose what element to listen to paste events on (html should get all of them). I haven’t messed around much with scoping it to other elements, but I don’t see why it wouldn’t work.
Now when someone pastes a copied image to the page it sets the background to the pasted image. This is just scratching the surface, but the great thing is that you can now capture paste events containing images in pure JS/HTML.
What’s that? CoffeeScript is hot for you to handle? Well here’s the JS version:
// Created by STRd6
// MIT License
// jquery.paste_image_reader.js
(function($) {
var defaults;
$.event.fix = (function(originalFix) {
return function(event) {
event = originalFix.apply(this, arguments);
if (event.type.indexOf('copy') === 0 || event.type.indexOf('paste') === 0) {
event.clipboardData = event.originalEvent.clipboardData;
}
return event;
};
})($.event.fix);
defaults = {
callback: $.noop,
matchType: /image.*/
};
return $.fn.pasteImageReader = function(options) {
if (typeof options === "function") {
options = {
callback: options
};
}
options = $.extend({}, defaults, options);
return this.each(function() {
var $this, element;
element = this;
$this = $(this);
return $this.bind('paste', function(event) {
var clipboardData, found;
found = false;
clipboardData = event.clipboardData;
return Array.prototype.forEach.call(clipboardData.types, function(type, i) {
var file, reader;
if (found) {
return;
}
if (type.match(options.matchType) || clipboardData.items[i].type.match(options.matchType)) {
file = clipboardData.items[i].getAsFile();
reader = new FileReader();
reader.onload = function(evt) {
return options.callback.call(element, {
dataURL: evt.target.result,
event: evt,
file: file,
name: file.name
});
};
reader.readAsDataURL(file);
return found = true;
}
});
});
});
};
})(jQuery);
Hey! I know that you want to use joysticks and gamepads in your HTML/JavaScript games, so what are you waiting for? Check out Boomstick and give it a shot.
This cross-platform, multi-browser extension gives JavaScript access to all joysticks on all platforms. Pretty rad.
Right now I’m having great results with it in my game Red Ice. It can support up to 8 joysticks straight away, so don’t worry.
Once you’ve got it plug in a joystick and check out the readme for how to access joystick data. Or you could just start developing on PixieEngine which has libraries for joystick handling built in.
But at any rate, use it, abuse it, and let me know what awesome games you make (also if you encounter any bugs or issues.)
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);
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.
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.
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:
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.
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.
/**
* Pretend the array is a circle and grab a new array containing length elements.
* If length is not given return the element at start, again assuming the array
* is a circle.
*
* @param {Number} start The index to start wrapping at, or the index of the
* sole element to return if no length is given.
* @param {Number} [length] Optional length determines how long result
* array should be.
* @returns The element at start mod array.length, or an array of length elements,
* starting from start and wrapping.
* @type Object or Array
*/
Array.prototype.wrap = function(start, length) {
if(length != null) {
var end = start + length;
var result = [];
for(var i = start; i < end; i++) {
result.push(this[i.mod(this.length)]);
}
return result;
} else {
return this[start.mod(this.length)];
}
};
Here’s a useful little method that empties out an array. Sure you could type myArray.length = 0; but that is kind of weird. For some reason myArray.clear() just makes more sense to me.
/**
* Empties the array of it's contents. It is modified in place.
*
* @type Array
* @returns this, now emptied.
*/
Array.prototype.clear = function() {
this.length = 0;
return this;
};
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.
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: