User:Ανώνυμος Βικιπαιδιστής/sandbox/MediaWiki:Imagemap-Highlight.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Ανώνυμος Βικιπαιδιστής/sandbox/MediaWiki:Imagemap-Highlight. |
$(document).ready(function() {
var
//add this class to all elements created by the script. the reason is that we call the script again on
//window resize, and use the class to remove all the "artefacts" we created in the previous run.
myClassName = 'imageMapHighlighterArtefacts'
, liHighlightClass = 'liHighlighting'
// "2d context" attributes used for highlighting.
, areaHighLighting = {fillStyle: 'rgba(0,0,0,0.30)', strokeStyle: 'yellow', lineJoin: 'round', lineWidth: 1.6}
//every imagemap that wants highlighting, should reside in a div of this 'class':
, hilightDivMarker = '.imageMapHighlighter'
// specifically for wikis - redlinks tooltip adds this message
, el = mw && mw.config && mw.config.get('wgUserLanguage') == 'el'
, pageDoesntExistMessage = el ? ' (Η σελίδα δεν υπάρχει)' : ' (page does not exist)'
, expandLegend = el ? 'Εμφάνιση λίστας χάρτη' : 'ּShow Legend'
, collapseLegend = el ? 'Απόκρυψη λίστας χάρτη' : 'Hide Legend'
;
function drawMarker(context, areas) { // this is where the magic is done.
function drawPoly(coords) {
context.moveTo(coords.shift(), coords.shift());
while (coords.length)
context.lineTo(coords.shift(), coords.shift());
}
for (var i in areas) {
var coords = areas[i].coords.split(',');
context.beginPath();
switch (areas[i].shape) {
case 'rect': drawPoly([coords[0], coords[1], coords[0], coords[3], coords[2], coords[3], coords[2], coords[1]]); break;
case 'circle': context.arc(coords[0],coords[1],coords[2],0,Math.PI*2); break;//x,y,r,startAngle,endAngle
case 'poly': drawPoly(coords); break;
}
context.closePath();
context.stroke();
context.fill();
}
}
function mouseAction(e) {
var $this = $(this),
context = $this.data('context'),
activate = e.type == 'mouseover',
li = $this.prop('tagName') == 'LI';
if (li && activate) { // in this case, we need to test visibility vis a vis scrolling
var height = $this.height(),
ol = $this.parent(),
top = $this.position().top;
if (top < 0 || top + height > ol.height())
ol.animate({scrollTop: ol.scrollTop() + top - ol.height() / 2});
}
$this.toggleClass(liHighlightClass, activate);
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
if (activate) {
drawMarker(context, $this.data('areas'));
if ($.client.profile().name === 'msie') { // ie9: dimwit needs to be told twice.
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
drawMarker(context, $this.data('areas'));
}
}
}
// massage the area "href" and create a human legible string to be used as the tooltip of "li"
function pageOfHref(href, cssClass) {
var page = href.replace(document.location.protocol + mw.config.get('wgServer') + "/wiki/", '').replace(/.*\/\//, '').replace(/_/g, ' ');
page = page.replace(/#(.*)/, function(toReplace){return toReplace.replace(/\.([\dA-F]{2})/g, '%$1');});
page = decodeURIComponent(page); // used for "title" of legends - just like "normal" wiki links.
if (cssClass.indexOf('new') + 1)
page += pageDoesntExistMessage;
return page;
}
function init() {
appendCSS('li.' + myClassName + '{white-space:normal;}\n' + //css for li element
'li.' + liHighlightClass + '{background-color:yellow;}\n' + //css for highlighted li element.
'.rtl li.' + myClassName + '{ margin-left: 3em;}\n' +
'.ltr li.' + myClassName + '{ margin-right: 3em;}');
var imgindex = 0;
$(hilightDivMarker+ ' img').each(function() {
var img = $(this), map = img.siblings('map:first');
if (!('area', map).length)
return; //not an imagemap. inside "each" anonymous function, 'return' means "continue".
var w = img.width(), h = img.height();
var dims = {position: 'absolute', width: w + 'px', height: h + 'px', border: 0, top:0, left:0};
var jcanvas = $('<canvas>', {'class': myClassName})
.css(dims)
.attr({width: w, height: h});
var bgimg = $('<img>', {'class': myClassName, src: img.attr('src')})
.css(dims);//completely inert image. this is what we see.
var context = $.extend(jcanvas[0].getContext("2d"), areaHighLighting);
// this is where the magic is done: prepare a sandwich of the inert bgimg at the bottom,
// the canvas above it, and the original, image, on top.
// so canvas won't steal the mouse events.
// pack them all TIGHTLY in a newly minted "relative" div, so when page chnage
// (other scripts adding elements, window resize etc.), canvas and imagese remain aligned.
var div = $('<div>').css({position: 'relative', width: w + 'px', height: h + 'px'});
img.before(div); // put the div just above the image, and ...
div.append(bgimg) // place the background image in the div
.append(jcanvas)// and the canvas. both are "absolute", so they don't occupy space in the div
.append(img); // now yank the original image from the window and place it on top.
img.fadeTo(1, 0); // make the image transparent - we see canvas and bgimg through it.
var eL = $(".imageMapHighlighter:eq(" + imgindex + ")").attr("data-expandLegendText");
if (eL !== undefined) { expandLegend = eL; }
var cL = $(".imageMapHighlighter:eq(" + imgindex + ")").attr("data-collapseLegendText");
if (cL !== undefined) { collapseLegend = cL; }
var ol = $('<ol>', {'class': myClassName})
.css({clear: 'both', margin: 0, left: 20, 'text-align': 'left', listStyle: 'disc', maxWidth: w + 'px', float: 'left', position: 'relative'})
.attr({'data-expandtext' : expandLegend, 'data-collapsetext': collapseLegend});
// ol below image, hr below ol. original caption pushed below hr.
var sl = $(".imageMapHighlighter:eq(" + imgindex + ")").attr("data-showLegend");
if (sl === undefined) { sl = "no"; }
if ( sl.search("yes") === 0 ) {
div.after($('<hr>', {'class': myClassName}).css('clear', 'both')).after(ol);
}
imgindex++;
var lis = {}; //collapse areas with same caption to one list item
$('area', map).each(function() {
var $this = $(this), text = this.title;
var li = lis[text]; // title already met? use the same li
if (!li) { //no? create a new one.
var href = this.href, cssClass = this['class'] || '';
lis[text] = li = $('<li>', {'class': myClassName})
.append($('<a>', {href: href, title: pageOfHref(href, cssClass), text: text, 'class': cssClass + ' internal'}))
.bind('mouseover mouseout', mouseAction)
.data('areas', [])
.data('context', context)
.appendTo(ol);
}
li.data('areas').push(this); //add the area to the li
$(this).bind('mouseover mouseout', function(e) {li.trigger(e);});
});
ol.addClass('mw-collapsed')
.makeCollapsible();
});
}
//has at least one "imagehighlight" div, and canvas-capable browser:
if ($(hilightDivMarker).length && $('<canvas>')[0].getContext) {
mw.loader.using('jquery.makeCollapsible', init);
}
});