Colorwheel 1K

I decided to make an HSV colorpicker for the js1k contest. Here is a demo of the colorpicker and the source code.

Getting Started

I found a great start for actually drawing the wheel at the canvas color wheel post from Ariya Hidayat. I modified that code and got the wheel on the screen in no time.

Also, I had written TinyColor, a JavaScript color parsing library, so the HSV to RGB conversion function was pretty easy to grab (though I did have to make some changes to shrink the function size, more on that later). This let me remove some of the code from the color wheel function that I also needed on mouse move events.

I tied together some buggybasic bounds checking on the circle for mousemove events and printed out the current RGB using the conversion function above, and I had a cool little demo - weighing in at around 2K.

Smaller… Much Smaller

So I needed to drop about half the weight of the project. I learned that you could use ~~x instead of Math.floor(x) provided that the number is positive, so that helped. And there are always tricks about passing in assignments to functions to save a semicolon, storing references to global objects, commonly used math functions, and so on. But it was not quite the time for dropping individual bytes, I needed some big changes.

First, DOM and CSS rules take up a lot of bytes. b.appendChild(d.createElement("input")) is just huge and cannot really be minified beyond what is there. My takeaway was that I needed less DOM elements. I was originally using a container div with a width equal to that of the canvas (400px) and had a little 'spot' div that was absolutely positioned based on the current X and current Y value. All of these lines are problems when are you trying to squeeze an 'application' into 1k:

container = b.appendChild(doc.createElement("div"));
spot = b.appendChild(doc.createElement("b"));
container.style.cssText='position:absolute;width:400px;margin:auto'
spot.style.cssText='position:relative;height:5px;width:5px'

By moving this functionality into the canvas drawing method (with fillRect, and later fillText), I dropped a couple hundred more bytes.

Next, the hsvToRgb conversion function got an overhaul (it went from 291 bytes to 205, and 33 of those are for the CSS color rule needed for the RGB background color). Takeaway here is that case statements have a lot of control characters, and this particular one was nicely shrunk down using 3 arrays.


// 291 bytes <a href='http://closure-compiler.appspot.com/code/jsc1c76aaeacd4bc7fcf6686709cc174fc3/default.js'>minified</a>.
function hsvToRgbBIG(h, s, v) {
    var r, g, b;

    var i = math.floor(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);

    switch(i % 6) {
        case : r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }

    return { r: r * 255, g: g * 255, b: b * 255 };
}

// 205 bytes <a href='http://closure-compiler.appspot.com/code/jsc1c76aaeacd4bc7fcf6686709cc174fc3/default.js'>minified</a>.
// Also includes the css color rule as the final return value.
function hsvToRgbSMALL(h, s, v) {
    h*=6;
    var i = ~~h,
        f = h - i,
        p = v * (1 - s),
        q = v * (1 - f * s),
        t = v * (1 - (1 - f) * s),
        mod = i % 6,
        r = [v, q, p, p, t, v][mod] * two55,
        g = [t, v, v, q, p, p][mod] * two55,
        b = [p, p, t, v, v, q][mod] * two55;

    return [r, g, b, "rgb("+ ~~r + "," + ~~g + "," + ~~b + ")"];
}

From there, it was mostly reorganizing and adding hacks to make the code smaller. A tip for anyone trying to do this: I wrap all the code into a executing function, so that minifiers will use one letter names for variables (rather than assuming they are global). Then I run the code through Closure Compiler online frequently when making changes to see how effective changes are. Don't forget to remove the wrapper from the minified file, though!

(function() {
    var oneHundred = 100;
    // All code goes inside here
})();

1k

I finally got to 1024 bytes! It was a fun project, I will probably to it again when another js1k comes along.

JavaScript Color Parsing - TinyColor

I threw together a color parsing library to help make my JavaScript colorpicker as small and accurate as possible. It is called TinyColor. One of the main goals is a small footprint - it clocks in at 8.98KB (3.41KB gzipped).

I have written in more detail about this on my TinyColor page. In it, I talk about the Color conversion, input recognition, color manipulation, scheme (combination) generation, and more.

jQuery UI CDN Boilerplate

I always forget these links, and they are surprisingly hard to find. Here is a quick markup skeleton to throw together for prototypes using jQuery UI.

<!doctype html>
<html>
<head>
  <title></title>

  <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.js"></script>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>
  <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/ui-lightness/jquery-ui.css" />

  <style type="text/css">
  #draggable {
    background: orange;
    width: 100px;
    height: 100px;
  }
  </style>

  <script type='text/javascript'>
  $(function() {
    $("#draggable").draggable().resizable();
  });
  </script>
</head>

<body>
<div id='draggable'>drag!</div>
</body>

</html>

jsFiddle lorem ipsum

I love jsFiddle! One feature that would make it even better is a lorem ipsum generator. When using Microsoft Word, you can type =lorem(100) and press enter, then it will generate 100 paragraphs of Lorem Ipsum for you. You can also type =rand(100) and it will pull in data from their help manual.

How great would it be to simulate large blocks of text without losing benefits of being able to scan html in a reduced test case? I don't like losing the basic layout of the HTML panel when being hit with a wall of text.

Here is my proposed syntax for this:

<div data-lorem="100"></div>

Sample implementation

See the demo on jsFiddle!

To use this now

  1. Open a jsFiddle
<div id='words' data-lorem='20w'></div>
<div id='sentences' data-lorem='20s'></div>
<div id='paragraphs' data-lorem='10'></div>

I would love if this got baked into jsFiddle so I could use this without adding the resource!

This is based off of the great loremjs library. My fork (which adds support for non jQuery, changes a couple of the defaults, and wraps contents in

tags is here: https://github.com/bgrins/loremjs

Chrome Developer Tools - monitorEvents

I have been playing with the Chrome Developer Tools lately. Here is a cool feature I didn't know about.

There are many times I have run some code in the console simply to bind to an event and simply log the result.

$("body").bind("click mousedown", function(e) {
    console.log(e);
});

There is a built in alternative called monitorEvents. Here is a quick demo on how to use it:

Inspect an element (see screenshot). Now that it has been inspected, there is a $0 variable available in the console.

Instead of that extra bind, you can just type this into the console:

monitorEvents($0, 'mouse')

Which, if you have the body selected in the Elements panel, is equivalent to typing:

monitorEvents(document.body, 'mouse')

OK, now that you can see all these events in the console and you have tracked down your issue, you probably want them to stop! Luckily, there is an unmonitorEvents function to do this.

unmonitorEvents(document.body)

You can also use 'key' instead of 'mouse' if you are tracking key events. There are actually a number of second parameters, but the support between Firebug and Devtools varies.

Possible Arguments For Firebug's monitorEvents

Via the Firebug command line API

composition contextmenu drag focus form key load mouse mutation paint scroll text ui xul

Possible Arguments For DevTools monitorEvents

Thanks to Paul Irish dropping by in the comments and linking to the source, we now know all the officially supported DevTools keywords:

mouse key touch control

Map of Events for DevTools monitorEvents:

mouse:  "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel"
key: "keydown", "keyup", "keypress", "textInput"
touch:  "touchstart", "touchmove", "touchend", "touchcancel"
control:  "resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"
no arguments: all of the above + "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation"