views:

584

answers:

1

I'm using the jQuery Map Hilighter plugin, but instead of fading a dark patch over each area, I would like to reverse this and instead make the surrounding area dark, keeping the hovered area the same colour.

I've looked at the code for the plugin and it appears to use the canvas element (and an MS equivalent I guess) to do the highlighting. However, Firebug isn't very forthcoming with exactly where the shapes are defined - on the demo above it just shows this:

 <canvas style="border: 0pt none ; padding: 0pt; width: 960px; height: 593px; position: absolute; left: 0pt; top: 0pt; opacity: 1;" height="593" width="960"></canvas>

And I can't see anything that specifies an element shape to hover. This is the part of the JS that appears to be creating the shape:

add_shape_to = function(canvas, shape, coords, options) {
 var i, context = canvas.getContext('2d');
 context.beginPath();
 if(shape == 'rect') {
  context.rect(coords[0], coords[1], coords[2] - coords[0], coords[3] - coords[1]);
 } else if(shape == 'poly') {
  context.moveTo(coords[0], coords[1]);
  for(i=2; i < coords.length; i+=2) {
   context.lineTo(coords[i], coords[i+1]);
  }
 } else if(shape == 'circ') {
  context.arc(coords[0], coords[1], coords[2], 0, Math.PI * 2, false);
 }
 context.closePath();
 if(options.fill) {
  context.fillStyle = css3color(options.fillColor, options.fillOpacity);
  context.fill();
 }
 if(options.stroke) {
  context.strokeStyle = css3color(options.strokeColor, options.strokeOpacity);
  context.lineWidth = options.strokeWidth;
  context.stroke();
 }
 if(options.fade) {
  fader(canvas, 0);
 }
};
+2  A: 

The shapes of the elements are defined as <area> elements inside a <map> element in the HTML code.

The simple answer to your question is to add something like this

  if (options.inverseFill) {
    context.rect(0,0, canvas.width,canvas.height);
  }

after the context.beginPath(); line, then an option in the defaults: inverseFill: true,, and then to make sure that all the areas in your image map are declared in the same clockwise direction.

What happens is that you define an extra subpath for the path that defines the dark patch, and when you fill, the overlapping area (ie, the original patch) will cancel out, as long as the winding numbers of the subpaths cancel, resulting in your desired inverted behaviour.

It gets rather more complicated if your area polygon definitions can rotate in both directions. For example if you do the above for the original MapHilight demo of the US map, only some of the states will behave correctly, since their shapes are defined in the correct clockwise direction - the rest stay dark, as their winding numbers are the wrong sign.

If you have full control over the image map definition, my advice would be to leave it at that and just ensure all areas go the same direction (ie, just reverse the coords list for each area that doesn't work).

If not, then at init time you'd need to precalculate for each shape the winding number. This would most likely involve going over the list of points and summing the angle between every two consecutive segments - calculated using atan2. Then in the add_shape_to function traverse the 4 corners of the canvas in the correct direction.

Anyway, I hope that helps

Update:

sorry I didn't see your comment earlier. for the circular area, in the add_shape_to function, replace the } else if(shape == 'circ') { part with

  } else if(shape == 'circ') {
    context.closePath();
    context.moveTo(coords[0] + coords[2], coords[1]);
    context.arc(coords[0], coords[1], coords[2], 0, Math.PI * 2, true);
    context.closePath(); 
  }

It closes the subpath before and after, then moves to the correct place, to avoid nasty red line to the top corner, and then changes the anticlockwise parameter to true to match the outside rectangle. Modify as needed

ivancho
Hi, thanks for the response. I have implemented what you said and it seems to work for some polygonal areas - I assume the others are backwards so I will sort those shortly. However, I can't get it to work at all with circular elements. Any ideas?
DisgruntledGoat