/** Modified by Niels van der Elst (nielsos@gmx.net) 07-09-2008 - Select and de-select shapes onclick and with direct callback. Example: Toggle shape - Link shapes with the linked attribute. Every shape with the same linked value will be turned on and off simultaneous Example: class="{alwaysOn:true,linked:1}" **/ (function($) { var has_VML, create_canvas_for, add_shape_to, clear_canvas, shape_from_area, canvas_style, fader, hex_to_decimal, css3color, is_image_loaded; var counter = 0; has_VML = document.namespaces; has_canvas = document.createElement('canvas'); has_canvas = has_canvas && has_canvas.getContext; if(!(has_canvas || has_VML)) { $.fn.maphilight = function() { return this; }; return; } // For non IE browsers!!! if(has_canvas) { fader = function(element, opacity, interval) { if(opacity <= 1) { element.style.opacity = opacity; window.setTimeout(fader, 10, element, opacity + 0.1, 10); } }; hex_to_decimal = function(hex) { return Math.max(0, Math.min(parseInt(hex, 16), 255)); }; css3color = function(color, opacity) { return 'rgba('+hex_to_decimal(color.substr(0,2))+','+hex_to_decimal(color.substr(2,2))+','+hex_to_decimal(color.substr(4,2))+','+opacity+')'; }; create_canvas_for = function(img) { var c = $('').get(0); c.getContext("2d").clearRect(0, 0, c.width, c.height); return c; }; add_shape_to = function(canvas, shape, coords, options, name) { 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); } }; clear_canvas = function(canvas, area) { canvas.getContext('2d').clearRect(0, 0, canvas.width,canvas.height); }; } // IE!!! else { // ie executes this code document.namespaces.add("v", "urn:schemas-microsoft-com:vml"); var style = document.createStyleSheet(); var shapes = ['shape','rect', 'oval', 'circ', 'fill', 'stroke', 'imagedata', 'group','textbox']; $.each(shapes, function() { style.addRule('v\\:' + this, "behavior: url(#default#VML); antialias:true"); } ); create_canvas_for = function(img) { return $('').get(0); }; add_shape_to = function(canvas, shape, coords, options, name, id) { var fill, stroke, opacity, e; fill = ''; stroke = (options.stroke ? 'strokeweight="'+options.strokeWidth+'" stroked="t" strokecolor="#'+options.strokeColor+'"' : 'stroked="f"'); opacity = ''; if(shape == 'rect') { e = $(''); } else if(shape == 'poly') { e = $(''); } else if(shape == 'circ') { e = $(''); } e.get(0).innerHTML = fill+opacity; $(canvas).append(e); }; clear_canvas = function(canvas) { $(canvas).find('[name=highlighted]').remove(); }; } shape_from_area = function(area) { var i, coords = area.getAttribute('coords').split(','); for (i=0; i < coords.length; i++) { coords[i] = parseFloat(coords[i]); } return [area.getAttribute('shape').toLowerCase().substr(0,4), coords]; }; is_image_loaded = function(img) { if(!img.complete) { return false; } // IE if(typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) { return false; } // Others return true; } canvas_style = { position: 'absolute', left: 0, top: 0, padding: 0, border: 0 }; $.fn.maphilight = function(opts) { opts = $.extend({}, $.fn.maphilight.defaults, opts); return this.each(function() { var img, wrap, options, map, canvas, canvas_always, mouseover, highlighted_shape; img = $(this); if(!is_image_loaded(this)) { // If the image isn't fully loaded, this won't work right. Try again later. return window.setTimeout(function() { img.maphilight(opts); }, 200); } options = $.metadata ? $.extend({}, opts, img.metadata()) : opts; map = $('map[name="'+img.attr('usemap').substr(1)+'"]'); if(!(img.is('img') && img.attr('usemap') && map.size() > 0)) { return; } if(img.hasClass('maphilighted')) { // We're redrawing an old map, probably to pick up changes to the options. // Just clear out all the old stuff. var wrapper = img.parent(); img.insertBefore(wrapper); wrapper.remove(); //alert('yes'); } wrap = $('
').css({display:'block',background:'url('+this.src+')',position:'relative',padding:0,width:this.width,height:this.height}); img.before(wrap).css('opacity', 0).css(canvas_style).remove(); if($.browser.msie) { img.css('filter', 'Alpha(opacity=0)'); } wrap.append(img); canvas = create_canvas_for(this); $(canvas).css(canvas_style); canvas.height = this.height; canvas.width = this.width; canvas.id = this.id; mouseover = function(e) { var shape, area_options; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if (area_options.linked) { var thislinked = area_options.linked; $(map).find('area[coords]').each(function() { var shape, area_options, object; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if (thislinked == area_options.linked) { shape = shape_from_area(this); add_shape_to(canvas, shape[0], shape[1], area_options, "highlighted", null); } }); } else { shape = shape_from_area(this); add_shape_to(canvas, shape[0], shape[1], area_options, "highlighted", null); } //if(!area_options.alwaysOn) //{ // shape = shape_from_area(this); // add_shape_to(canvas, shape[0], shape[1], area_options, "highlighted", null); //} } draw = function(object) { var shape, area_options, object; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; // NON IE if(has_canvas) { canvas_always = create_canvas_for(img.get()); $(canvas_always).css(canvas_style); canvas_always.width = img.width(); canvas_always.height = img.height(); canvas_always.id = 'canvas_' + $(object).attr("id"); img.before(canvas_always); } shape = shape_from_area(object); // IE! if ($.browser.msie) { add_shape_to(canvas, shape[0], shape[1], area_options, "", $(object).attr("id")); } else { add_shape_to(canvas_always, shape[0], shape[1], area_options, ""); } } mouseclick = function(e,id) { var shape, area_options, object; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if (id) { object = id; } else { object = this; } if (!$('#canvas_' + $(object).attr('id')).attr('id')) { if (area_options.linked) { var thislinked = area_options.linked; $(map).find('area[coords]').each(function() { var shape, area_options, object; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if (thislinked == area_options.linked) { // alert($(this).attr('id') + ' ' + area_options.linked); draw(this); } }); } else { draw(object); } } else { if (area_options.linked) { var thislinked = area_options.linked; $(map).find('area[coords]').each(function() { var shape, area_options, object; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if (thislinked == area_options.linked) { $('#canvas_' + $(this).attr('id')).remove(); } }); clear_canvas(canvas); } else { $('#canvas_' + $(object).attr('id')).remove(); clear_canvas(canvas); } } } if(options.alwaysOn) { $(map).find('area[coords]').each(mouseover); } else { if($.metadata) { // If the metadata plugin is present, there may be areas with alwaysOn set. // We'll add these to a *second* canvas, which will get around flickering during fading. $(map).find('area[coords]').each(function() { var shape, area_options; area_options = $.metadata ? $.extend({}, options, $(this).metadata()) : options; if(area_options.alwaysOn) { draw(this); } }); } $(map).find('area[coords]').mouseover(mouseover).mouseout(function(e) { clear_canvas(canvas); }); $(map).find('area[coords]').click(mouseclick); } img.before(canvas); // if we put this after, the mouseover events wouldn't fire. img.addClass('maphilighted'); }); }; $.fn.maphilight.defaults = { fill: true, fillColor: '0057b8', fillOpacity: 0.85, stroke: false, strokeColor: 'ffffff', strokeOpacity: 1, strokeWidth: 1, fade: true, alwaysOn: false }; })(jQuery);