PageSourceSearch

https://www.bandbireland.com/App_Themes/bandb/js/jquery.maphilight.js

js bandbireland.com collected 2026-09-24 19:16:05 UTC 13,485 bytes, 376 lines download raw bytes

1(function($) {
2	var has_VML, has_canvas, create_canvas_for, add_shape_to, clear_canvas, shape_from_area,
3		canvas_style, hex_to_decimal, css3color, is_image_loaded, options_from_area;
4
5	has_canvas = !!document.createElement('canvas').getContext;
6
7	// VML: more complex
8	has_VML = (function() {
9		var a = document.createElement('div');
10		a.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
11		var b = a.firstChild;
12		b.style.behavior = "url(#default#VML)";
13		return b ? typeof b.adj == "object": true;
14	})();
15
16	if(!(has_canvas || has_VML)) {
17		$.fn.maphilight = function() { return this; };
18		return;
19	}
20	
21	if(has_canvas) {
22		hex_to_decimal = function(hex) {
23			return Math.max(0, Math.min(parseInt(hex, 16), 255));
24		};
25		css3color = function(color, opacity) {
26			return 'rgba('+hex_to_decimal(color.substr(0,2))+','+hex_to_decimal(color.substr(2,2))+','+hex_to_decimal(color.substr(4,2))+','+opacity+')';
27		};
28		create_canvas_for = function(img) {
29			var c = $('<canvas style="width:'+img.width+'px;height:'+img.height+'px;"></canvas>').get(0);
30			c.getContext("2d").clearRect(0, 0, c.width, c.height);
31			return c;
32		};
33		var draw_shape = function(context, shape, coords, x_shift, y_shift) {
34			x_shift = x_shift || 0;
35			y_shift = y_shift || 0;
36			
37			context.beginPath();
38			if(shape == 'rect') {
39				// x, y, width, height
40				context.rect(coords[0] + x_shift, coords[1] + y_shift, coords[2] - coords[0], coords[3] - coords[1]);
41			} else if(shape == 'poly') {
42				context.moveTo(coords[0] + x_shift, coords[1] + y_shift);
43				for(i=2; i < coords.length; i+=2) {
44					context.lineTo(coords[i] + x_shift, coords[i+1] + y_shift);
45				}
46			} else if(shape == 'circ') {
47				// x, y, radius, startAngle, endAngle, anticlockwise
48				context.arc(coords[0] + x_shift, coords[1] + y_shift, coords[2], 0, Math.PI * 2, false);
49			}
50			context.closePath();
51		}
52		add_shape_to = function(canvas, shape, coords, options, name) {
53			var i, context = canvas.getContext('2d');
54			
55			// Because I don't want to worry about setting things back to a base state
56			
57			// Shadow has to happen first, since it's on the bottom, and it does some clip /
58			// fill operations which would interfere with what comes next.
59			if(options.shadow) {
60				context.save();
61				if(options.shadowPosition == "inside") {
62					// Cause the following stroke to only apply to the inside of the path
63					draw_shape(context, shape, coords);
64					context.clip();
65				}
66				
67				// Redraw the shape shifted off the canvas massively so we can cast a shadow
68				// onto the canvas without having to worry about the stroke or fill (which
69				// cannot have 0 opacity or width, since they're what cast the shadow).
70				var x_shift = canvas.width * 100;
71				var y_shift = canvas.height * 100;
72				draw_shape(context, shape, coords, x_shift, y_shift);
73				
74				context.shadowOffsetX = options.shadowX - x_shift;
75				context.shadowOffsetY = options.shadowY - y_shift;
76				context.shadowBlur = options.shadowRadius;
77				context.shadowColor = css3color(options.shadowColor, options.shadowOpacity);
78				
79				// Now, work out where to cast the shadow from! It looks better if it's cast
80				// from a fill when it's an outside shadow or a stroke when it's an interior
81				// shadow. Allow the user to override this if they need to.
82				var shadowFrom = options.shadowFrom;
83				if (!shadowFrom) {
84					if (options.shadowPosition == 'outside') {
85						shadowFrom = 'fill';
86					} else {
87						shadowFrom = 'stroke';
88					}
89				}
90				if (shadowFrom == 'stroke') {
91					context.strokeStyle = "rgba(0,0,0,1)";
92					context.stroke();
93				} else if (shadowFrom == 'fill') {
94					context.fillStyle = "rgba(0,0,0,1)";
95					context.fill();
96				}
97				context.restore();
98				
99				// and now we clean up
100				if(options.shadowPosition == "outside") {
101					context.save();
102					// Clear out the center
103					draw_shape(context, shape, coords);
104					context.globalCompositeOperation = "destination-out";
105					context.fillStyle = "rgba(0,0,0,1);";
106					context.fill();
107					context.restore();
108				}
109			}
110			
111			context.save();
112			
113			draw_shape(context, shape, coords);
114			
115			// fill has to come after shadow, otherwise the shadow will be drawn over the fill,
116			// which mostly looks weird when the shadow has a high opacity
117			if(options.fill) {
118				context.fillStyle = css3color(options.fillColor, options.fillOpacity);
119				context.fill();
120			}
121			// Likewise, stroke has to come at the very end, or it'll wind up under bits of the
122			// shadow or the shadow-background if it's present.
123			if(options.stroke) {
124				context.strokeStyle = css3color(options.strokeColor, options.strokeOpacity);
125				context.lineWidth = options.strokeWidth;
126				context.stroke();
127			}
128			
129			context.restore();
130			
131			if(options.fade) {
132				$(canvas).css('opacity', 0).animate({opacity: 1}, 100);
133			}
134		};
135		clear_canvas = function(canvas) {
136			canvas.getContext('2d').clearRect(0, 0, canvas.width,canvas.height);
137		};
138	} else {   // ie executes this code
139		create_canvas_for = function(img) {
140			return $('<var style="zoom:1;overflow:hidden;display:block;width:'+img.width+'px;height:'+img.height+'px;"></var>').get(0);
141		};
142		add_shape_to = function(canvas, shape, coords, options, name) {
143			var fill, stroke, opacity, e;
144			for (var i in coords) { coords[i] = parseInt(coords[i], 10); }
145			fill = '<v:fill color="#'+options.fillColor+'" opacity="'+(options.fill ? options.fillOpacity : 0)+'" />';
146			stroke = (options.stroke ? 'strokeweight="'+options.strokeWidth+'" stroked="t" strokecolor="#'+options.strokeColor+'"' : 'stroked="f"');
147			opacity = '<v:stroke opacity="'+options.strokeOpacity+'"/>';
148			if(shape == 'rect') {
149				e = $('<v:rect name="'+name+'" filled="t" '+stroke+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+coords[0]+'px;top:'+coords[1]+'px;width:'+(coords[2] - coords[0])+'px;height:'+(coords[3] - coords[1])+'px;"></v:rect>');
150			} else if(shape == 'poly') {
151				e = $('<v:shape name="'+name+'" filled="t" '+stroke+' coordorigin="0,0" coordsize="'+canvas.width+','+canvas.height+'" path="m '+coords[0]+','+coords[1]+' l '+coords.join(',')+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+canvas.width+'px;height:'+canvas.height+'px;"></v:shape>');
152			} else if(shape == 'circ') {
153				e = $('<v:oval name="'+name+'" filled="t" '+stroke+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(coords[0] - coords[2])+'px;top:'+(coords[1] - coords[2])+'px;width:'+(coords[2]*2)+'px;height:'+(coords[2]*2)+'px;"></v:oval>');
154			}
155			e.get(0).innerHTML = fill+opacity;
156			$(canvas).append(e);
157		};
158		clear_canvas = function(canvas) {
159			// jquery1.8 + ie7 
160			var $html = $("<div>" + canvas.innerHTML + "</div>");
161			$html.children('[name=highlighted]').remove();
162			canvas.innerHTML = $html.html();
163		};
164	}
165	
166	shape_from_area = function(area) {
167		var i, coords = area.getAttribute('coords').split(',');
168		for (i=0; i < coords.length; i++) { coords[i] = parseFloat(coords[i]); }
169		return [area.getAttribute('shape').toLowerCase().substr(0,4), coords];
170	};
171
172	options_from_area = function(area, options) {
173		var $area = $(area);
174		return $.extend({}, options, $.metadata ? $area.metadata() : false, $area.data('maphilight'));
175	};
176	
177	is_image_loaded = function(img) {
178		if(!img.complete) { return false; } // IE
179		if(typeof img.naturalWidth != "undefined" && img.naturalWidth === 0) { return false; } // Others
180		return true;
181	};
182
183	canvas_style = {
184		position: 'absolute',
185		left: 0,
186		top: 0,
187		padding: 0,
188		border: 0
189	};
190	
191	var ie_hax_done = false;
192	$.fn.maphilight = function(opts) {
193		opts = $.extend({}, $.fn.maphilight.defaults, opts);
194		
195		if(!has_canvas && !ie_hax_done) {
196			$(window).ready(function() {
197				document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
198				var style = document.createStyleSheet();
199				var shapes = ['shape','rect', 'oval', 'circ', 'fill', 'stroke', 'imagedata', 'group','textbox'];
200				$.each(shapes,
201					function() {
202						style.addRule('v\\:' + this, "behavior: url(#default#VML); antialias:true");
203					}
204				);
205			});
206			ie_hax_done = true;
207		}
208		
209		return this.each(function() {
210			var img, wrap, options, map, canvas, canvas_always, mouseover, highlighted_shape, usemap;
211			img = $(this);
212
213			if(!is_image_loaded(this)) {
214				// If the image isn't fully loaded, this won't work right.  Try again later.
215				return window.setTimeout(function() {
216					img.maphilight(opts);
217				}, 200);
218			}
219
220			options = $.extend({}, opts, $.metadata ? img.metadata() : false, img.data('maphilight'));
221
222			// jQuery bug with Opera, results in full-url#usemap being returned from jQuery's attr.
223			// So use raw getAttribute instead.
224			usemap = img.get(0).getAttribute('usemap');
225
226			if (!usemap) {
227				return
228			}
229
230			map = $('map[name="'+usemap.substr(1)+'"]');
231
232			if(!(img.is('img,input[type="image"]') && usemap && map.size() > 0)) {
233				return;
234			}
235
236			if(img.hasClass('maphilighted')) {
237				// We're redrawing an old map, probably to pick up changes to the options.
238				// Just clear out all the old stuff.
239				var wrapper = img.parent();
240				img.insertBefore(wrapper);
241				wrapper.remove();
242				$(map).unbind('.maphilight').find('area[coords]').unbind('.maphilight');
243			}
244
245      // IE8 gets the image size wrong =/
246			var nWidth = this.width;
247			var nHeight = this.height;
248			if (document.body.className.indexOf('IE8') != -1) {
249			  nWidth = 289;
250			  nHeight = 324;
251			}
252
253			wrap = $('<div></div>').css({
254				display:'block',
255				background:'url("'+this.src+'")',
256				position:'relative',
257				padding:0,
258				width: nWidth,
259				height: nHeight
260				});
261			if(options.wrapClass) {
262				if(options.wrapClass === true) {
263					wrap.addClass($(this).attr('class'));
264				} else {
265					wrap.addClass(options.wrapClass);
266				}
267			}
268			img.before(wrap).css('opacity', 0).css(canvas_style).remove();
269			if(has_VML) { img.css('filter', 'Alpha(opacity=0)'); }
270			wrap.append(img);
271			
272			canvas = create_canvas_for(this);
273			$(canvas).css(canvas_style);
274			canvas.height = this.height;
275			canvas.width = this.width;
276			
277			mouseover = function(e) {
278				var shape, area_options;
279				area_options = options_from_area(this, options);
280				if(
281					!area_options.neverOn
282					&&
283					!area_options.alwaysOn
284				) {
285					shape = shape_from_area(this);
286					add_shape_to(canvas, shape[0], shape[1], area_options, "highlighted");
287					if(area_options.groupBy) {
288						var areas;
289						// two ways groupBy might work; attribute and selector
290						if(/^[a-zA-Z][\-a-zA-Z]+$/.test(area_options.groupBy)) {
291							areas = map.find('area['+area_options.groupBy+'="'+$(this).attr(area_options.groupBy)+'"]');
292						} else {
293							areas = map.find(area_options.groupBy);
294						}
295						var first = this;
296						areas.each(function() {
297							if(this != first) {
298								var subarea_options = options_from_area(this, options);
299								if(!subarea_options.neverOn && !subarea_options.alwaysOn) {
300									var shape = shape_from_area(this);
301									add_shape_to(canvas, shape[0], shape[1], subarea_options, "highlighted");
302								}
303							}
304						});
305					}
306					// workaround for IE7, IE8 not rendering the final rectangle in a group
307					if(!has_canvas) {
308						$(canvas).append('<v:rect></v:rect>');
309					}
310				}
311			}
312
313			$(map).bind('alwaysOn.maphilight', function() {
314				// Check for areas with alwaysOn set. These are added to a *second* canvas,
315				// which will get around flickering during fading.
316				if(canvas_always) {
317					clear_canvas(canvas_always);
318				}
319				if(!has_canvas) {
320					$(canvas).empty();
321				}
322				$(map).find('area[coords]').each(function() {
323					var shape, area_options;
324					area_options = options_from_area(this, options);
325					if(area_options.alwaysOn) {
326						if(!canvas_always && has_canvas) {
327							canvas_always = create_canvas_for(img[0]);
328							$(canvas_always).css(canvas_style);
329							canvas_always.width = img[0].width;
330							canvas_always.height = img[0].height;
331							img.before(canvas_always);
332						}
333						area_options.fade = area_options.alwaysOnFade; // alwaysOn shouldn't fade in initially
334						shape = shape_from_area(this);
335						if (has_canvas) {
336							add_shape_to(canvas_always, shape[0], shape[1], area_options, "");
337						} else {
338							add_shape_to(canvas, shape[0], shape[1], area_options, "");
339						}
340					}
341				});
342			});
343			
344			$(map).trigger('alwaysOn.maphilight').find('area[coords]')
345				.bind('mouseover.maphilight', mouseover)
346				.bind('mouseout.maphilight', function(e) { clear_canvas(canvas); });
347			
348			img.before(canvas); // if we put this after, the mouseover events wouldn't fire.
349			
350			img.addClass('maphilighted');
351		});
352	};
353	$.fn.maphilight.defaults = {
354		fill: true,
355		fillColor: '000000',
356		fillOpacity: 0.2,
357		stroke: true,
358		strokeColor: 'ff0000',
359		strokeOpacity: 1,
360		strokeWidth: 1,
361		fade: true,
362		alwaysOn: false,
363		neverOn: false,
364		groupBy: false,
365		wrapClass: true,
366		// plenty of shadow:
367		shadow: false,
368		shadowX: 0,
369		shadowY: 0,
370		shadowRadius: 6,
371		shadowColor: '000000',
372		shadowOpacity: 0.8,
373		shadowPosition: 'outside',
374		shadowFrom: false
375	};
376})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.