A shadow is upon us

Other people contributing to my projects is often the cause of my improving them. This is because people tend to contribute something that works for the case they care about, without necessarily testing how it combines with the rest of the product. There’s nothing wrong with this. They did some work and wanted to give it back; that’s how open source should work.

A case in point here is how shadows just got added to maphilight. A pull request was submitted for a commit that added shadow support for rectangles in canvas only. I accepted the request because, hey, that’s a nice improvement, and it seemed to work. But I wasn’t really happy with rectangles-only.

So, I started fiddling with it. I had, for whatever reason, never touched shadows in canvas before. In fact, it’s been quite a while since I did the research into canvas that was involved in writing maphilight in the first place.

Looking at the commit I see that the shadows have been implemented with a combination of clipping regions and redrawing the shape with some shadow options on the path.

Now, I’m confused by the clipping being done, since I’ve never seen it work quite like that before. It’s drawing a rectangle around the whole canvas, then another around the rectangle we’re shadowing, and telling it to clip. So I do a bit of testing, and I find that this isn’t doing what I think the submitter meant it to.

I think they wanted it to set up a clip region only outside the shape, so that the shadows they drew wouldn’t appear inside it. However, in practice it seems that it’s just adding the two rectangles together and leaving us with a clip region the size of the whole canvas. It’s possible that this did work in another browser, but not in Chrome where I was testing…

Since subtractive clipping obviously wasn’t the answer, I looked into globalCompositeOperation to clean up after the fill. It turned out that destination-out was the operation I needed to empty my shape. Also, because the shadow-drawing had been added after the regular shape, I had to move it to be before that, otherwise the shadow was being drawn on top of the stroke and cleaning it up would wipe out the fill.

Okay! Now we have outline shadows.

But, another issue with this method: it’d fill and stroke on the shape, regardless of the settings you were using. If you had no fill / stroke it’d use the default (flat black) settings, which are ugly. Also, it harmed your opacity settings — the stroke and fill were being done twice. So when I added a shadow to a strokeless mostly-transparent rectangle I noticed that it gained a thin black outline, and was darker than it should have been.

I messed around a little bit with trying to erase the fill or stroke, but eventually decided that this was more hassle than it was worth. What wound up being the simplest option was drawing the shape massively off the edge of the canvas, and using shadow offsets to cast the shadow into the right spot.

Now we had a shadow that didn’t involve drawing anything stroking or filling onto the canvas near our existing shape. At this point I had completely rewritten the code I’d merged in. About the only thing remaining was the option names Raven24 had chosen.

I went ahead and added some options for whether the shadow was cast inside or outside the shape, since I could see reasons for both, and added some overrides for whether it’d be casting from the fill or the stroke, since the varying possible configurations made it difficult to reliably guess which would look better.

I still didn’t add it to non-canvas. Largely because now that IE has finally given in and implemented canvas I view that as being a dead branch. Needs to keep working, and any major changes have to be ported over… but minor display differences are somewhat acceptable. Also, I don’t have access to IE right now, since I’m away from home. If I ever have reason to look into shadows in VML I’m sure I’ll add it in then, for the heck of it.

You can see all this in action on the demo page if you’re interested.

And that’s how community involvement improves things. 😀

Maphilight 1.3

I released maphilight 1.3 just now. (Though really I consider github the more authoritative source.)

So, IE9 broke maphilight because it was finally exposing the has_canvas codepath to IE. Turns out all the canvas stuff worked beautifully, but one call to setTimeout was relying on a non-IE feature. So that’s fixed!

Also changed since the 1.2 release (one year ago, gosh):

  • New option groupBy lets you bundle several areas together
  • New option wrapClass lets you set a classname for the wrapper div created to hold the canvas elements used by maphilight. If it’s set to true it’ll use the classname from the image.
  • .data(‘maphilight’) is checked for areas, as well as the metadata plugin. With jQuery > 1.4.3 this means that you can use JSON in an HTML5 data- attribute to pass this in. See the API docs for details.
  • Performance on image maps containing a lot of areas was terrible because I was stupid about where I triggered an event.
  • Opera compatibility was harmed by jQuery bug #6708 (fixed in 1.6), so work around that.

Feel free to submit issues / pull requests on the github project.

Ooo capitalism

“Clickable Maps” is selling pre-made maps explicitly for use with Maphilight.

The pre-purchase samples are pretty good examples of what’s possible. This USA map shows remote triggering of a hilight, for instance.

Note: I wouldn’t have released under the MIT license if this sort of thing bothered me.

maphilight 1.2

I finally got around to officially releasing maphilight 1.2.

This mostly just updates the official jquery.com release to the HEAD of the github project.

I’d been putting it off because I spent quite a while without easy access to a Windows machine with IE8 to test the fixes that people provided. But I switched back to Windows as my main desktop recently (mainly to play games), so that was resolved.

There’s not much in the way of changes:

  • IE8 works now
  • New “neverOn” option for use with metadata by Zach Dennis, which stops individual areas from ever being hilighted
  • Handles being called on the same area twice differently; now rebuilds the hilighted regions
  • …and I added an example of triggering the hilight from another element, since it’s one of the most commonly asked questions

Hopefully I’ll be able to post here a bit more now that I have some of that guilt for not updating off my shoulders. 😛

maphilight: image map mouseover highlighting

UPDATE 2011-05-04: Version 1.3 released. Works in IE9. (There’s a pattern here.)

UPDATE 2010-05-22: Version 1.2 released. Works in IE8.

I just released maphilight, a jQuery plugin that turns image maps into wonderful graphical masterpieces.

Image maps aren’t so popular any more, for some strange reason. So a quick definition: an imagemap is an <img> with the usemap attribute, pointing to a <map> that describes polygons that link places within that image.

This sprung from me wanting to display pretty highlighting of countries on a map, but not wanting to mess with flash for it. It involves enough annoying fiddling with <canvas> (and VML, because IE is in the stone age) that I feel I’m saving other people a decent amount of work by releasing it.

Simple demo
Pretty demo using a world map
Documentation
Download (requires jQuery)

(Tools like “HTML-Image map Creator WYSIWYG” might be handy if you want to make image maps yourself.)