iconfu iconfu iconfu is the world's largest collection of free, open-source icons and it comes with a handy image editor, so you can tweak icons to suit your needs exactly or even draw your own from scratch
invert blue resize move up verbose drawmode lighter previews remove swap animator library library draw shift up make a copy large editor explorer your icon contract agreement tag

08 July 2009

Don't misunderestimate your children

I was reading a Wallace and Gromit story to my (now 5-year-old) son, and he energetically pointed out

son Look, a grandfather clock!
me Yes, that's a grandfather clock. It's about to fall on top of Wallace!
Wallace That's just the thing, my lad, we'll have to turn back the clock ...
son What's "turn back the clock" ?
me Well, suppose something happened yesterday that you weren't happy about, so you decide to <blah blah long-winded explanation of expression with digression into the role of metaphor in language>
son Oh, you mean he builds a time machine?

Duh. I should have realised time travel is a standard part of every 5-year-old's vocabulary.

09 June 2009

New Iconfu

The latest iconfu, released yesterday, sports these improvements:

  • undo/redo with ctl-z and ctl-shift-z, respectively.
  • save as BMP! (careful though, BMP has no transparency, so transparent pixels are likely to come out black. You should edit your chosen icon and add an opaque background)
  • The default paypal page is now English, not French. Thanks to Paul Graham for pointing out this problem, and thanks to brains4all for the solution.

This release comes with thanks to Utku Karatas for some great suggestions.

Enjoy!

13 April 2009

The Many Faces of Iconfu

Not all colours are equal, and not all backgrounds are white. What do you do when you're designing an icon for a site with a dark background? You change the background of your favourite icon editor, of course!

iconfu

iconfu

It's easy to do: in the colour chooser, choose the colour you want to use for the background, open the "appearance" panel on the bottom right, and click "use current colour" for "background". Voilà!

07 April 2009

New iconfu

The latest and greatest iconfu is here:

  • A shiny new colour selector with HSV sliders as well as RGB sliders and a palette of basic colours (with instant conversion between HSV and RGB)
  • Automatic preview-as-favicon of your work in progress
  • Comment on icons
  • "who's online" so you know you're not alone
  • Three quick built-in tutorials so you can start using the most powerful iconfu features straight away
  • Gravatar integration so you have more control over your online identity
  • Search for icons within a particular collection while editing
  • Easliy draw anti-aliased straight lines
  • Fixed GIF downloading - some icons would fail to download as GIF due to internal errors
Enjoy! And go vote for iconfu at killerstartups.com

28 March 2009

Chart in Javascript

There aren't enough bar-chart-drawing implementations out there yet, so this article will present the best one yet. It looks like this:

a chart made with javascript

Or several little charts in a row, like this:

several bar charts in a row

Features:

  • Really easy to use
  • mouse move highlights bar under mouse
  • pops up tooltip with information for the bar under the mouse
  • All colours are configurable
  • Scales data automatically to height of canvas
  • Calculates thickness of bars automatically so all fit in the width of the canvas
  • Redraw data as often as you want - for example with data from an ajax call

The tooltip is missing from this screenshot. My mac hides the tooltip before it takes the screenshot unfortunately.

Anyway, I'd like to convince you that it's really, really easy to use. Supply your data in JSON format like this:

var data = [
[ "week 1", "1000" ],
[ "week 2", "2000" ],
[ "week 3", "3000" ]
];

Declare a canvas element:

<canvas id="weekly_chart" width="200" height="80"></canvas>

Then just call the Chart(canvas_element, bar_colour, bg_colour, hilite_colour) constructor:

var chart = new Chart($('weekly_chart'), "rgb(128,128,255)", "rgb(0,0,0)", "rgb(255,255,128)");

Then, draw your data

chart.draw(data);

It couldn't be simpler!

Here's the code. Just include it somwhere in your page. It's free under a Creative Commons Attribution Share-Alike 3.0 license - you can use, re-use, modify, redistribute, as long as you link back to this page and (re)distributions carry the same or a compatible license. It has a slight dependency on Prototype (2 calls) but you jQuery people will fix that quickly (in fact, you might even leave a comment with the jQuery alternative). Theoretically, it will work on Internet Exploder using Google's excanvas, although I haven't tested this configuration.

(function() {
  function max(data) {
    var max = 0;
    for (var i = 0; i < data.length; i++) {
      if (data[i][1] > max) {
        max = data[i][1];
      }
    }
    return max;
  }

  function coords(event, element, f) {
    var offset = $(element).cumulativeOffset();   // $ from prototype
    var p = Event.pointer(event || window.event); // Event.pointer from prototype
    var y = p.y - offset.top;
    var x = p.x - offset.left;
    f(y, x);
  }

  window.Chart = function(canvas, fg, bg, hilite) {
    if (!canvas || !canvas.getContext) {
      return;
    }

    var cx = canvas.getContext('2d');

    this.draw = function(data) {
      cx.clearRect(0, 0, canvas.width, canvas.height);
      var thick = canvas.width / data.length;
      var scale = canvas.height / max(data);

      function highlightBars(index) {
        cx.lineWidth = 1;

        for (var i = 0; i < data.length; i++) {
          if (i == index || i == (index + 1)) {
            cx.strokeStyle = hilite;
          } else {
            cx.strokeStyle = bg;
          }
          cx.beginPath();
          cx.moveTo((i * thick) + 0.5, 0);
          cx.lineTo((i * thick) + 0.5, canvas.height);
          cx.stroke();
        }
      }

      cx.fillStyle = bg;
      cx.fillRect(0, 0, canvas.width, canvas.height);

      cx.fillStyle = fg;

      for (var i = 0; i < data.length; i++) {
        var h = data[i][1] * scale;
        if (!isNaN(h)) {
          cx.fillRect(i * thick, canvas.height - h, thick, h);
        }
      }

      highlightBars(-2);


      canvas.onmouseout = function(event) {
        highlightBars(-2);
      };

      canvas.onmousemove = function(event) {
        coords(event, canvas, function(y, x) {
          var index = ((x-1) / thick).floor();
          if (index < 0) {
            index = 0;
          }
          highlightBars(index);

          var bar = data[index];
          if (bar) {
            canvas.title = bar[0] + " : " + bar[1];
          }
        });
      };
    };
  };
})();

This is the simple version. Feel free to comment with improvements, I'll keep the code up to date with my favourite suggestions.

26 March 2009

Spidering Internal Pages

A url within an anchor tag in html may be absolute or relative. Absolute links look like <a href='http://iconfu.com'>iconfu ...</a> - they start with a protocol. Relative links look like <a href='bar.html'>bar info ...</a>. When you link to bar.html from http://example.com/pages/foo.html, the browser constructs the full reference and requests http://example.com/pages/bar.html.

So far, so good.

Relative links may also be of the form <a href='?browse=arrow'>arrow icons</a>. A browser requesting this link from http://iconfu.com/tags/list/0.html will construct this url: http://iconfu.com/tags/list/0.html?browse=arrow

This can be convenient when the code or script that handles the requested page is separate from the code or script that handles the request parameters. This doesn't happen often, but when it does, it's useful to be able to construct the url without needing to know the originating page. For example, a login handler might be implemented as a filter before the page is rendered, so the login request would simply be ?username=foo&password=bar ... this gets expanded by the browser into http://example.com/pages/foo.html?username=foo&password=bar. On the server, your login filter handles the login parameters, and your example/page script handles the rest of the url.

The bad news is that some spidering implementations handle this incorrectly (google's works fine). Instead of requesting http://iconfu.com/tags/list/0.html?browse=arrow from the earlier example, they request http://iconfu.com/tags/list?browse=arrow - they chop out "0.html". My code doesn't like this, and returns an error. Dumb MF spider implementations.

So that was that. Well, here's another bit of news: about 95% of visitors who come to iconfu through search, come from google. There are two ways to explain this: (1) google is the world's dominant search engine, who uses yahoo/live/ask.com anyway; (2) the clever people behind google analytics use some clever reporting techniques to show that google is the world's dominant search engine so why bother with the others.

We can eliminate (2) because as you know googlers Do No Evil. But today, in a flash of insight, I realised (3) perhaps those other search engines are sending me no visitors because they think my site is full of bugs and holes and 500 Internal Server Errors.

I'll fix that today and I'll let you know if I get a little more love from those unloved search engines. And then you can add "be careful with relative urls containing only a query string" to your SEO toolkit.

Open Coffee Club Paris: For Sale

Open Coffee Club, Paris, 26 March 2009

A dude is making a speech about legal issues for startups. I don't like this. I come to OCC for peer-to-peer networking, not go get lectured at. This is hijacking an open, social event to allow one person dominate and control the discussion. Not only that, but my conversation was interrupted! This wastes my time, because I am deprived of the ability to choose the people I want to converse with. I expect to meet people either because they are interesting or their service is useful to me. I have no respect for a dude who has effectively bought* OCC as a platform to market his services, and I have no respect for an OCC willing to sell itself in this way.

Some people are politely paying attention. Others look bored and are wondering when this abuse will be over. And I have nobody to talk to :((

* "bought" in the moral sense. I have no idea how the dude in question obtained authority to hijack the group.