Debugging Web Workers

May 2012

While working on FileReader.js Web Worker file processing with FileReaderSync, I needed to figure out what was going on with the script inside a web worker. It can be very difficult to track down errors without standard developer tool support, like logging and debugging. Luckily, in Chrome Devtools, this is possible.

How to do it

It can be a little tricky to find, but click over to the ‘Scripts’ panel, and expand the ‘Workers’ accordion on the right. Then check the ‘Pause on Start’ checkbox and you will enter the debugging mode once the worker gets fired up. Here is a screenshot of the relevant checkbox:


Screencast

Here is a screencast of me playing with this feature:

Unable to display content. Adobe Flash is required.

Load Web Workers Without A JavaScript File

May 2012

Ever want to load a JavaScript Web Worker without specifying an external JavaScript file? There are a couple of different ways to do this by creating a blog and object URL – I wrapped this functionality up into a little plugin to share.

Here is the code. Or checkout out a working jsfiddle demo

 
var WorkerHelper = (function() {
 
    var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
    var URL = window.URL || window.webkitURL;
 
    function getURL (script) {
        if (window.Worker && BlobBuilder && URL) {
            var bb = new BlobBuilder();
            bb.append(script);
            return URL.createObjectURL(bb.getBlob());
        }
 
        return null;
    };
 
    function getWorker (script, onmessage) {
        var url = getURL(script);
        if (url) {
            var worker = new Worker(url);
            worker.onmessage = onmessage;
            return worker;
        }
 
        return null;
    };
 
    return {
        getURL: getURL,
        getWorker: getWorker     
    }
 
})();
 
<div id='log'></div>
 
<script type='text/worker' id='worker-script'>
    self.addEventListener('message', function(e) { 
        postMessage(e.data / 2); 
    },false);
</script>​
 
<script type='text/javascript'>
 
// Load a worker from a string, and manually initialize the worker
var inlineWorkerURL = WorkerHelper.getURL(
    "self.addEventListener('message', function(e) { postMessage(e.data * 2); } ,false);"
);
var inlineWorker = new Worker(inlineWorkerURL);
inlineWorker.onmessage = function(e) {
    document.getElementById('log').innerHTML += '<br />Inline: ' + e.data;
};
 
 
// Load a worker from a script of type=text/worker, and use the getWorker helper
var scriptTagWorker = WorkerHelper.getWorker(
    document.getElementById('worker-script').textContent,
    function(e) {
        document.getElementById('log').innerHTML += '<br />Script Tag: ' + e.data;
    }
);
 
inlineWorker.postMessage(1);
inlineWorker.postMessage(2);
inlineWorker.postMessage(100);
scriptTagWorker.postMessage(1);
scriptTagWorker.postMessage(2);
scriptTagWorker.postMessage(100);
 
</script>

Drag Out Images and Canvas With Filenames

May 2012

It can be annoying that when you drag out images of a browser window, they are named png.png (or something equally useless). I was playing around with fixing this – it is a little inconvenience in my CSS Sprite Generator that would be nice to have working (naming the file based on their input). Here is what I came up with (no library dependancies):

function dragoutImages() {
 
    if (!document.addEventListener) {
        return;
    }
 
    document.addEventListener("dragstart", function(e) {
        var element = e.target;
        var src;
 
        if (element.tagName === "IMG" && element.src.indexOf("data:") === 0) {
            src = element.src;
        }
 
        if (element.tagName === "CANVAS") {
            try {
                src = element.toDataURL();
            }
            catch(e) {  }
        }
 
        if (src) {
            var name = element.getAttribute("alt") || "download";
            var mime = src.split(";")[0].split("data:")[1];
            var ext = mime.split("/")[1] || "png";
            var download = mime + ":" + name + "." + ext + ":" + src;
 
            e.dataTransfer.setData("DownloadURL", download);   
        }
    }, false);
}

You just need to specify the alt attribute on the image or canvas to specify your name (along with the draggable attribute on canvas elements) and the script should handle the rest.

Browser Support

I am not 100% sure on browser support. This used to be Chrome only according to this HTML5rocks article, but maybe other browsers have picked it up by now. It is a neat little addition when available though.

Demos

See the full demo: drag out images with custom file name. This shows the ability to drag out both image and canvas tags.

On this page, you should be able to drag out the following colorpicker screenshot, which will be called spectrum.png.

spectrum

Astar Graph Search – Variable Costs

May 2012

I’ve been working on updating my A* Graph Search Algorithm (A* on Github) and toying with the idea of adding variable costs to the grid, also known as weighted paths.

I opened an issue to add weighting to graph nodes a while ago, but am a little stuck on the implementation details. My initial thought was to change the semantics of the graph. Right now, here is a sample graph:

 
var GraphNodeType = { 
    OPEN: 0, 
    WALL: 1 
};
 
// 0 represents an open node, 1 represents a wall 
var graph = new Graph([
    [0,0,0,0],
    [1,0,0,1],
    [1,1,0,0]
]);

My initial plan for adding weighting was something like this:

 
var GraphNodeType = { 
    WALL: 0,
};
 
// Anything > 0 represents the cost to travel to that node, 0 represents a wall
var graph = new Graph([
    [2,1,3,4],
    [0,1,1,0],
    [0,0,3,10]
]);

One major issue with that is that it breaks backwards compatibility with the plugin. A user, spellfork, on the Github issue came up with a neat solution, basically passing in two separate arrays to the graph function, where one represents the “obstacle map” (walls), and the second represents the “terrain map” (costs).

 
// First array: 0 represents an open node, 1 represents a wall 
// Second array: movement costs are represented by numeric value 
var graph = new Graph([
    [0,0,0,0],
    [1,0,0,1],
    [1,1,0,0]
],[
    [2,1,3,4],
    [0,1,1,0],
    [0,0,3,10]
]);

This is nice because the terrain map is optional, but not as nice if you need to do a lot of work to generate the two separate maps.

Maybe there is a better solution that I am not thinking of? Any ideas about the best way to implement this? Drop a comment here or over in the Github issue to help get this implemented!

Expanding Textareas jQuery Plugin

April 2012

Ever want a textarea to expand based on the size of the input that someone types? I made a jQuery plugin to handle expanding textareas! The basic technique is based off of a cool article called Expanding Text Areas Made Elegant. Check out the Expanding Textareas Demo and play with the Expanding Textareas Source Code.

I think it’s a pretty cool plugin that is a lot nicer than using the standard hacks for keeping textarea heights up to date. And it works really well with proportional widths, custom fonts, and min/max heights!

Here is a screenshot (which also links to the demo):


Expanding Textareas jQuery plugin

Chrome DevTools Colorpicker Screencast

April 2012

I put together a screencast explaining the colorpicker functionality recently added into WebKit Web Inspector (aka Chrome DevTools for brevity). For some backstory on how this got implemented, check out my initial colorpicker concept video or the description of the implementation.

Here is a quick screencast showing off the colorpicking functionality (currently running in Chrome Canary):

Unable to display content. Adobe Flash is required.

Oh, and the jQuery plugin I am working with is called unmodal.

Gradient Generator

April 2012

I have been working a browser based gradient generator. I’ve never had the best experience using gradient generators, so I decided to see if I could do better.

It is a prototype right now (a weekend project), but I am hoping to do more with it as time permits.

Features

  • It outputs to CSS, Canvas, and SVG
  • Allows for separate color and alpha stops
  • Keyboard support (left, shift+left, right, shift+right, ctrl+c, ctrl+v)
  • You can Copy/Paste current stop
  • Undo/Redo
  • Easily sharable URLs with the hash tag Example gradient or a GET parameter (Example with GET parameter).
  • Local Storage Support to keep track of your work
  • Potential Future Features

    • Support for radial gradients
    • Cross browser CSS output
    • Saving your gradients to server
    • Multiple layers for stacked gradients
    • More CSS 3 effect generators (box shadows, rounded corners, etc) built into the UI
    • Any other ideas? Leave a comment or tweet them to @bgrins!

    I haven’t come up with a better name yet, so check it out here: http://briangrinstead.com/gradient!

    Gradient Generator Screenshot

Input Type=Color Polyfill

April 2012

My jQuery Colorpicker – Spectrum now has a mode that acts as a polyfill to input type=color.

What this means

Now that the color input is supported in Chrome nightlies, along with Opera, people may want to start using this cool new form element.

While you can still customize the colorpicker and bend it to your will, if you’d like to use this new mode just include the HTML:

<input type='color' value='#4499f0' />

Along with a reference to spectrum.js and spectrum.css:

<link rel='stylesheet' href='spectrum.css' />
<script type='text/javascript' src='spectrum.js'></script>

Demo

See the color input polyfill demo page for more info!

UI Anglepicker

April 2012

I created a jQuery UI Widget for picking angles.

Demo: JavaScript Angle Picker Demo
Source Code: https://github.com/bgrins/ui.anglepicker

Big thanks to Original JavaScript and CSS based on: https://github.com/mrflix/LayerStyles

Inverse Rectangle Intersection In JavaScript

February 2012

Given a parent rectangle and a collection of children rectangles on a 2D plane, how do you find a collection of non-overlapping rectangles that cover the inverse of the original set?

For instance, given the container rectangle along with the set [A, B] -> we want an output similar to [1, 2, 3, 4, 5].

         +----------------------------------------------------------------+
         |                                                                |
         |                                                                |
         |       +------------------+        +--------------------+       |
         |       |                  |        |                    |       |
         |       |                  |        |                    |       |
         |       |        A         |        |        B           |       |
         |       |                  |        |                    |       |
         |       |                  |        |                    |       |
         |       |                  |        |                    |       |
         |       +------------------+        +--------------------+       |
         |                                                                |
         |                                                                |
         |                                                                |
         |                                                                |
         |                                                                |
         +----------------------------------------------------------------+


         +----------------------------------------------------------------+
         |                                                                |
         |                               1                                |
         +-------+------------------+--------+--------------------+-------+
         |       |                  |        |                    |       |
         |       |                  |        |                    |       |
         |   2   |                  |   3    |                    |       |
         |       |                  |        |                    |   4   |
         |       |                  |        |                    |       |
         |       |                  |        |                    |       |
         +-------+------------------+--------+--------------------+-------+
         |                                                                |
         |                                                                |
         |                              5                                 |
         |                                                                |
         |                                                                |
         +----------------------------------------------------------------+

Solution

Enter the inverse-intersection JavaScript project. It is a kind of micro library. No dependancies, just the math required to solve this problem!

You can grab the JavaScript file from Github.