Maphilight for Interactive Map - HELP

Twine Version: 2.8.1.

Hello all,

I’m trying to create an interactive map using twine and sugarcube. I followed this Mikewesthad’s guide on creating clickable images with HTML maps (was unable to post the link!) which involves using maphighlight (a plugin in javascript) and an image file.

However, I have inputted the code and I can’t get the maphighlight script to connect to the image map (which is displaying correctly).

Has anyone got any advice at all?

The maphighlight script is in ‘PassageDone’ and this is what my main code looks like for the map (most of the script has been omitted as it follows the same pattern for each area, just named differently):

<img src="https://i.ibb.co/HX9WGq3/Regions-and-Prefectures-of-Japan-2-svg.png" alt="Regions-and-Prefectures-of-Japan-2-svg"
usemap="#image-map">

<map name="image-map">
	 <area 
                data-passage=“Miyazaki”
                alt="Miyazaki"
                title="Miyazaki"  
                coords="89,870,129,789" 
                shape="rect">
</map>

    <map name="image-map">
    <area
    data-passage=“Kagoshima”"
    "_top"
     alt="Kagoshima"
     title="Kagoshima"  
     coords="82,835,48,887" 
     shape="rect">
</map>
     
    <map name= "image-map">
    <area
    data-passage=“Kumamoto”
    "_top" 
    alt="Kumamoto" 
    title="Kumamoto"  
    coords="62,779,85,830" 
    shape="rect">
</map>
    
    <map name= "image-map">
    <area
    data-passage=“Oita”
    "_top" 
    alt="Oita" 
    title="Oita"  
    coords="92,745,118,741,129,789,75,769" 
    shape="poly">
</map>
    

First, a couple of issues with your example.

1: The String value being assigned to the data-passage special attribute of each <area> element is currently delimited with Typographical (curvy) quotes instead of standard quotes, which causes issues when the contents of the Passage is converted into actual HTML elements.
eg. you have

data-passage=“Kagoshima”

…but it should be

data-passage="Kagoshima"

2: When you deleted the target attribute of each <area> element you left behind the "_top" value for all but the first of them, and that makes the element invalid.

3: [optional] There are many line-breaks between the elements of your example, all of which will be automatically converted into <br> element, which can cause “blank lines” in the generated output. I suggest wrapping all of the elements within a single <> macro call.

4: [optional] You don’t need multiple <map> elements, as a single such element can contain multiple child <area> elements.

The following is my variation of your example with the above three issues resolved.

<<nobr>>
<img src="https://i.ibb.co/HX9WGq3/Regions-and-Prefectures-of-Japan-2-svg.png" alt="Regions-and-Prefectures-of-Japan-2-svg"
usemap="#image-map">

<map name="image-map">
	<area
    		data-passage="Miyazaki"
    		alt="Miyazaki"
    		title="Miyazaki"
    		coords="89,870,129,789"
    		shape="rect">

	<area
    		data-passage="Kagoshima"
    		alt="Kagoshima"
    		title="Kagoshima"
    		coords="82,835,48,887"
    		shape="rect">

	<area
    		data-passage="Kumamoto"
    		alt="Kumamoto"
    		title="Kumamoto"
    		coords="62,779,85,830"
    		shape="rect">

	<area
    		data-passage="Oita"
    		alt="Oita"
    		title="Oita"
    		coords="92,745,118,741,129,789,75,769"
    		shape="poly">
</map>
<</nobr>>

5: The Twine 2 application won’t automatically create the Passages being referenced by the special data-passage attributes, nor will it create Connection Arrows in the Story/Passage Map for them.

Placing Markup based Links within a comment in a Passage can be used to trick the Twine 2 application into doing both of these things. If you want such then add a comment like the following to the above Passage code.

/* Fake Markup based Links, used to force the Twine 2 app to generate the required Passages, and related Connection Arrows.
	[[Miyazaki]], [[Kagoshima]], [[Kumamoto]], [[Oita]]
*/

6: The coords used in a <area> element area relative to the dimensions of the image they are associated with. So if that image is shown at a different resolution / size than the one you used when generating the coords then they will be wrong.

eg. if your web-browser was displaying the image using dimensions of 1024 by 768 when you generated the coords of each <area>, then those coords will be wrong if another person’s web-browser displays the same image using dimensions of 640 by 480.

Because a web-browser doesn’t automatically adjust the coords if the associated image is scaled (either up or down). And this is the reason while image-maps are difficult to use in a Responsive web-application.

You have a couple of potential solutions:
a. Force the image to be the same specific dimensions on all monitor / screen sizes, both desktop and mobile. This can be done using CSS or HTML attributes.
b. Use JavaScript to dynamically adjust the coords based on the current dimensions of the image.

Do you intend to have image-maps in multiple Passages?

If not then I suggest moving the maphilight related JavaScript, from the PassageDone special Passage, into the Passage that contains the image-map, so that JavaScript doesn’t get called for every Passage that is visited.

If you do this then you will need to wrap the <<script>> macro call within a <<done>> macro like so.

<<done>>
	<<script>>
		// Apply maphilight to all images that have a usemap attribute, e.g.
		// all the maps that are in this twine. This sets the default styling
		// for all the maps. These are all the possible styling options.
		// Note: for picking colors, check out http://hslpicker.com/. You can
		// copy the HEX value as long as you leave off the "#".
		$("img[usemap]").maphilight({
				fill: true,							// Fill the area?
				fillColor: 'dd319b',		 // HEX format without the starting "#"
				fillOpacity: 0.5,			   // Opacity of the filled area
				stroke: true,				   // Outline the area?
				strokeColor: 'ef9ace',
				strokeOpacity: 1,
				strokeWidth: 3,				// Outline width
				fade: true,						// Animate when hovered with a fade?
				alwaysOn: false,			// Always show the areas?
				neverOn: false,
				groupBy: false,
				wrapClass: true,
				shadow: false,
				shadowX: 0,
				shadowY: 0,
				shadowRadius: 6,
				shadowColor: '000000',
				shadowOpacity: 0.8,
				shadowPosition: 'outside',
				shadowFrom: false
				});
	<</script>>
<</done>>

I wasn’t able to actually test your example, even after I “fixed” it, likely because my web-browser was displaying the image using dimensions different than your own.

But I was able to confirm that the $("img[usemap]") jQuery search being used by the Maphilight related JavaScript was able to find the image-map in the Passage.

1 Like

Thank you very much for this in depth and very helpful response Greyelf - using your code and advice I have got maphighlight going and, as you’ve said, the co-ordinates are not matching - I will look into using JavaScript to dynamically adjust the coords based on the current dimensions of the image.

I’ve been using HiEv’s code for resizing the image map and have been aiming to combine this with maphighlight, but they appear to be incompatible as it throws an error out of maphighlight not being a function.

My main passage code is:

<<nobr>>
<div="resizable imageMapObserve">\
	<img src="https://i.ibb.co/HX9WGq3/Regions-and-Prefectures-of-Japan-2-svg.png" usemap="#image-map">\
</div>\

<map name="image-map">
<area 
               data-passage="Miyazaki"
               alt="Miyazaki"
               title="Miyazaki"  
               coords="89,870,129,789" 
               shape="rect">

<area
              data-passage="Kagoshima"
              alt="Kagoshima"
              title="Kagoshima"  
              coords="82,835,48,887" 
              shape="rect">

<area
              data-passage="Kumamoto"
              alt="Kumamoto" 
              title="Kumamoto"  
              coords="62,779,85,830" 
              shape="rect">

 <area
              data-passage="Oita" 
              alt="Oita" 
              title="Oita"  
              coords="92,745,118,741,129,789,75,769" 
              shape="poly">

 <area
            data-passage="Nagasaki" 
            alt="Nagasaki" 
            title="Nagasaki"
            coords="22,807,54,803,43,785,12,765" 
            shape="poly">


 <area
            data-passage="Saga"
            alt="Saga" 
            title="Saga"  
            coords="24,753,61,761,42,780,23,767" 
            shape="poly">


<area
            data-passage="Fukuoka"
            alt="Fukuoka" 
            title="Fukuoka"  
            coords="72,719,90,740,70,765,41,747" 
            shape="poly">

<area
            data-passage="Okinawa"
            alt="Okinawa" 
            title="Okinawa"  
            coords="614,778,626,782,609,831,598,826" 
            shape="poly">

<area
            data-passage="Yamiguchi"
            alt="Yamaguchi" 
            title="Yamaguchi"  
            coords="102,690,130,707,134,723,69,716" 
            shape="poly">

<area
            data-passage="Shimane"
            alt="Shimane" 
            title="Shimane"  
            coords="108,682,174,623,186,633,115,694" 
            shape="poly">

  
<area
          data-passage="Hiroshima"
          alt="Hiroshima" 
          title="Hiroshima"  
          coords="128,689,178,654,193,687,146,705" 
          shape="poly">


<area
          data-passage="Tottori"
          alt="Tottori" 
          title="Tottori"  
          coords="188,631,235,619,236,632,185,643" 
          shape="poly">

<area
          data-passage="Okayama"
          alt="Okayama" 
          title="Okayama"  
          coords="190,648,229,642,231,675,197,683" 
          shape="poly">

<area
          data-passage="Ehime"
          alt="Ehime" 
          title="Ehime"  
          coords="195,713,168,712,138,751,154,770" 
          shape="poly">

<area
          data-passage="Kochi"
          alt="Kochi" 
          title="Kochi"  
          coords="155,776,204,717,228,730,180,783" 
          shape="poly">

<area
          data-passage="Kagawa"
          alt="Kagawa" 
          title="Kagawa"  
          coords="204,693,240,697,209,709" 
          shape="poly">

<area
          data-passage="Tokushima"
          alt="Tokushima" 
          title="Tokushima"  
          coords="213,713,246,698,265,719,242,734" 
          shape="poly">

<area
          data-passage="Hyogo"
          alt="Hyogo" 
          title="Hyogo"  
          coords="239,617,256,617,284,668,261,703,236,663" 
          shape="poly">

<area
          data-passage="Kyoto"
          alt="Kyoto" 
          title="Kyoto"  
          coords="261,616,297,629,312,662,271,635" 
          shape="poly">

<area
          data-passage="Shiga"
          alt="Shiga" 
          title="Shiga"  
          coords="304,626,324,612,332,645,315,658" 
          shape="poly">

<area
          data-passage="Mie"
          alt="Mie" 
          title="Mie"  
          coords="341,639,320,662,328,713,365,682" 
          shape="poly">

<area
          data-passage="Nara"
          alt="Nara" 
          title="Nara"  
          coords="302,663,318,667,320,698,300,711" 
          shape="poly">

<area
          data-passage="Osaka"
          alt="Osaka" 
          title="Osaka"  
          coords="288,652,298,658,298,684,288,684,290,674" 
          shape="poly">
          
<area
          data-passage="Wakayama"
          alt="Wakayama" 
          title="Wakayama"  
          coords="276,692,288,691,315,738,277,718" 
          shape="poly">

<area
          data-passage="Aichi"
          alt="Aichi" 
          title="Aichi"  
          coords="394,629,351,623,356,657,382,661" 
          shape="poly">

<area
          data-passage="Shizuoka"
          alt="Shizuoka" 
          title="Shizuoka"  
          coords="454,617,411,622,388,660,461,648" 
          shape="poly">
          
<area
          data-passage="Fukui"
          alt="Fukui" 
          title="Fukui"  
          coords="318,571,342,593,299,623" 
          shape="poly">

<area
          data-passage="Gifu"
          alt="Gifu" 
          title="Gifu"
          coords="348,565,380,562,383,625,350,619,342,635,325,607,348,596,343,583" 
          shape="poly">

<area
          data-passage="Ishikawa"
          alt="Ishikawa" 
          title="Ishikawa"  
          coords="351,500,334,509,326,564,337,573" shape="poly">

<area
          data-passage="Toyama"
          alt="Toyama" 
          title="Toyama"  
          coords="380,527,348,537,346,563,380,557" 
          shape="poly">

<area
          data-passage="Nagano"
          alt="Nagano" 
          title="Nagano"  
          coords="387,534,420,526,423,572,390,624,380,593" 
          shape="poly">

<area
          data-passage="Yamanashi"
          alt="Yamanashi" 
          title="Yamanashi"  
          coords="420,587,442,585,463,596,422,611" 
          shape="poly">

<area
          data-passage="Niigata"
          alt="Niigata" 
          title="Niigata"  
          coords="464,429,398,441,381,524,436,529" 
          shape="poly">

<area
          data-passage="Gunma"
          alt="Gunma" 
          title="Gunma"  
          coords="451,517,424,546,439,572,466,553" 
          shape="poly">

<area
          data-passage="Saitama"
          alt="Saitama" 
          title="Saitama"  
          coords="440,576,461,559,480,560,487,577,470,582" 
          shape="poly">

<area
          data-passage="Tokyo"
          alt="Tokyo" 
          title="Tokyo"  
          coords="457,581,488,580,486,589,461,591,441,579" 
          shape="poly">

<area
          data-passage="Kanagawa"
          alt="Kanagawa" 
          title="Kanagawa"  
          coords="486,594,470,592,456,605,461,616,488,614" 
          shape="poly">

<area
          data-passage="Chiba"
          alt="Chiba" 
          title="Chiba"  
          coords="490,571,526,568,524,613,496,631,492,599" 
          shape="poly">

<area
          data-passage="Ibaraki"
          alt="Ibaraki" 
          title="Ibaraki"  
          coords="509,517,526,513,528,565,498,569,489,561" 
          shape="poly">

<area
          data-passage="Tochigi"
          alt="Tochigi" 
          title="Tochigi"  coords="458,519,487,501,503,519,490,552,472,557,464,542" 
          shape="poly">
    
<area
          data-passage="Fukushima"
          alt="Fukushima" 
          title="Fukushima"  coords="532,509,504,516,488,498,454,518,449,490,464,468,490,464,503,452,524,454,533,471" 
          shape="poly">

<area
          data-passage="Miyagi"
          alt="Miyagi" 
          title="Miyagi"  
          coords="508,395,546,408,523,451,492,451,499,407" 
          shape="poly">

<area
          data-passage="Yamagata"
          alt="Yamagata" 
          title="Yamagata"  coords="464,395,494,400,489,462,463,464,468,425,450,428" 
          shape="poly">

<area
          data-passage="Akita"
          alt="Akita" 
          title="Akita"  coords="457,315,496,312,493,365,508,394,466,389,447,348" 
          shape="poly">

<area
          data-passage="Iwate"
          alt="Iwate" 
          title="Iwate"  coords="502,321,531,306,546,330,557,354,544,402,510,393,496,365"
          shape="poly">

<area
          data-passage="Aomori"
          alt="Aomori" 
          title="Aomori"  coords="510,249,491,243,462,267,448,299,455,312,493,309,506,317,528,305,516,273" 
          shape="poly">

<area
        data-passage="Hokkaido"
        alt="Hokkaido" 
        title="Hokkaido"  coords="496,3,656,54,676,114,626,146,585,208,500,222,455,253,444,243,432,190" 
        shape="poly">
    
</map>

<<done>>
            <<script>>

                        // Apply maphilight to all images that have a usemap attribute, e.g.
                        // all the maps that are in this twine. This sets the default styling
                        // for all the maps. These are all the possible styling options.
                        // Note: for picking colors, check out http://hslpicker.com/. You can
                        // copy the HEX value as long as you leave off the "#".
                        $("img[usemap]").maphilight({
                          fill: true,             	// Fill the area?
                          fillColor: 'dd319b',    	// HEX format without the starting "#"
                          fillOpacity: 0.5,       	// Opacity of the filled area
                          stroke: true,           	// Outline the area?
                          strokeColor: 'ef9ace',
                          strokeOpacity: 1,
                          strokeWidth: 3,			// Outline width
                          fade: true,             	// Animate when hovered with a fade?
                          alwaysOn: false,        	// Always show the areas?
                          neverOn: false,
                          groupBy: false,
                          wrapClass: true,
                          shadow: false,
                          shadowX: 0,
                          shadowY: 0,
                          shadowRadius: 6,
                          shadowColor: '000000',
                          shadowOpacity: 0.8,
                          shadowPosition: 'outside',
                          shadowFrom: false
                        });

            <</script>>
 <</done>>
 
<</nobr>>

My javascript code is as follows:

// Tweaked version of maphilight (12-06-2016 build) to work with SugarCube 2 and Twine
!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):b(a.jQuery)}(window,function(a){var b,c,d,e,f,g,h,i,j,k,l;if(c=!!document.createElement("canvas").getContext,b=function(){var a=document.createElement("div");a.innerHTML='<v:shape id="vml_flag1" adj="1" />';var b=a.firstChild;return b.style.behavior="url(#default#VML)",!b||"object"==typeof b.adj}(),!c&&!b)return void(a.fn.maphilight=function(){return this});if(c){i=function(a){return Math.max(0,Math.min(parseInt(a,16),255))},j=function(a,b){return"rgba("+i(a.substr(0,2))+","+i(a.substr(2,2))+","+i(a.substr(4,2))+","+b+")"},d=function(b){var c=a('<canvas style="width:'+a(b).width()+"px;height:"+a(b).height()+'px;"></canvas>').get(0);return c.getContext("2d").clearRect(0,0,a(b).width(),a(b).height()),c};var m=function(a,b,c,d,e){if(d=d||0,e=e||0,a.beginPath(),"rect"==b)a.rect(c[0]+d,c[1]+e,c[2]-c[0],c[3]-c[1]);else if("poly"==b){a.moveTo(c[0]+d,c[1]+e);for(var f=2;f<c.length;f+=2)a.lineTo(c[f]+d,c[f+1]+e)}else"circ"==b&&a.arc(c[0]+d,c[1]+e,c[2],0,2*Math.PI,!1);a.closePath()};e=function(b,c,d,e,f){var h=b.getContext("2d");if(e.shadow){h.save(),"inside"==e.shadowPosition&&(m(h,c,d),h.clip());var i=100*b.width,k=100*b.height;m(h,c,d,i,k),h.shadowOffsetX=e.shadowX-i,h.shadowOffsetY=e.shadowY-k,h.shadowBlur=e.shadowRadius,h.shadowColor=j(e.shadowColor,e.shadowOpacity);var l=e.shadowFrom;l||(l="outside"==e.shadowPosition?"fill":"stroke"),"stroke"==l?(h.strokeStyle="rgba(0,0,0,1)",h.stroke()):"fill"==l&&(h.fillStyle="rgba(0,0,0,1)",h.fill()),h.restore(),"outside"==e.shadowPosition&&(h.save(),m(h,c,d),h.globalCompositeOperation="destination-out",h.fillStyle="rgba(0,0,0,1);",h.fill(),h.restore())}h.save(),m(h,c,d),e.fill&&(h.fillStyle=j(e.fillColor,e.fillOpacity),h.fill()),e.stroke&&(h.strokeStyle=j(e.strokeColor,e.strokeOpacity),h.lineWidth=e.strokeWidth,h.stroke()),h.restore(),e.fade&&a(b).css("opacity",0).animate({opacity:1},100)},f=function(a){a.getContext("2d").clearRect(0,0,a.width,a.height)}}else d=function(b){return a('<var style="zoom:1;overflow:hidden;display:block;width:'+b.width+"px;height:"+b.height+'px;"></var>').get(0)},e=function(b,c,d,e,f){var g,h,i,j;for(var k in d)d[k]=parseInt(d[k],10);g='<v:fill color="#'+e.fillColor+'" opacity="'+(e.fill?e.fillOpacity:0)+'" />',h=e.stroke?'strokeweight="'+e.strokeWidth+'" stroked="t" strokecolor="#'+e.strokeColor+'"':'stroked="f"',i='<v:stroke opacity="'+e.strokeOpacity+'"/>',"rect"==c?j=a('<v:rect name="'+f+'" filled="t" '+h+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+d[0]+"px;top:"+d[1]+"px;width:"+(d[2]-d[0])+"px;height:"+(d[3]-d[1])+'px;"></v:rect>'):"poly"==c?j=a('<v:shape name="'+f+'" filled="t" '+h+' coordorigin="0,0" coordsize="'+b.width+","+b.height+'" path="m '+d[0]+","+d[1]+" l "+d.join(",")+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+b.width+"px;height:"+b.height+'px;"></v:shape>'):"circ"==c&&(j=a('<v:oval name="'+f+'" filled="t" '+h+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(d[0]-d[2])+"px;top:"+(d[1]-d[2])+"px;width:"+2*d[2]+"px;height:"+2*d[2]+'px;"></v:oval>')),j.get(0).innerHTML=g+i,a(b).append(j)},f=function(b){var c=a("<div>"+b.innerHTML+"</div>");c.children("[name=highlighted]").remove(),b.innerHTML=c.html()};g=function(a){var b,c=a.getAttribute("coords").split(",");for(b=0;b<c.length;b++)c[b]=parseFloat(c[b]);return[a.getAttribute("shape").toLowerCase().substr(0,4),c]},l=function(b,c){var d=a(b);return a.extend({},c,!!a.metadata&&d.metadata(),d.data("maphilight"))},k=function(a){return!!a.complete&&("undefined"==typeof a.naturalWidth||0!==a.naturalWidth)},h={position:"absolute",left:0,top:0,padding:0,border:0};var n=!1;a.fn.maphilight=function(i){return i=a.extend({},a.fn.maphilight.defaults,i),c||n||(a(window).ready(function(){document.namespaces.add("v","urn:schemas-microsoft-com:vml");var b=document.createStyleSheet(),c=["shape","rect","oval","circ","fill","stroke","imagedata","group","textbox"];a.each(c,function(){b.addRule("v\\:"+this,"behavior: url(#default#VML); antialias:true")})}),n=!0),this.each(function(){var j,m,n,o,p,q,s;if(j=a(this),!k(this))return window.setTimeout(function(){j.maphilight(i)},200);if(n=a.extend({},i,!!a.metadata&&j.metadata(),j.data("maphilight")),s=j.get(0).getAttribute("usemap"),s&&(o=a('map[name="'+s.substr(1)+'"]'),j.is('img,input[type="image"]')&&s&&o.length>0)){if(j.hasClass("maphilighted")){var t=j.parent();j.insertBefore(t),t.remove(),a(o).unbind(".maphilight")}m=a("<div></div>").css({display:"block",backgroundImage:'url("'+this.src+'")',backgroundSize:"contain",position:"relative",padding:0,width:this.width,height:this.height}),n.wrapClass&&(n.wrapClass===!0?m.addClass(a(this).attr("class")):m.addClass(n.wrapClass)),j.before(m).css("opacity",0).css(h).remove(),b&&j.css("filter","Alpha(opacity=0)"),m.append(j),p=d(this),a(p).css(h),p.height=this.height,p.width=this.width,a(o).bind("alwaysOn.maphilight",function(){q&&f(q),c||a(p).empty(),a(o).find("area[coords]").each(function(){var b,f;f=l(this,n),f.alwaysOn&&(!q&&c&&(q=d(j[0]),a(q).css(h),q.width=j[0].width,q.height=j[0].height,j.before(q)),f.fade=f.alwaysOnFade,b=g(this),c?e(q,b[0],b[1],f,""):e(p,b[0],b[1],f,""))})}).trigger("alwaysOn.maphilight").bind("mouseover.maphilight, focus.maphilight",function(b){var d,f,h=b.target;if(f=l(h,n),!f.neverOn&&!f.alwaysOn){if(d=g(h),e(p,d[0],d[1],f,"highlighted"),f.groupBy){var i;i=/^[a-zA-Z][\-a-zA-Z]+$/.test(f.groupBy)?o.find("area["+f.groupBy+'="'+a(h).attr(f.groupBy)+'"]'):o.find(f.groupBy);var j=h;i.each(function(){if(this!=j){var a=l(this,n);if(!a.neverOn&&!a.alwaysOn){var b=g(this);e(p,b[0],b[1],a,"highlighted")}}})}c||a(p).append("<v:rect></v:rect>")}}).bind("mouseout.maphilight, blur.maphilight",function(a){f(p)}),j.before(p),j.addClass("maphilighted")}})},a.fn.maphilight.defaults={fill:!0,fillColor:"000000",fillOpacity:.2,stroke:!0,strokeColor:"

/*! Image Map Resizer
 *  Desc: Resize HTML imageMap to scaled image.
 *  Copyright: (c) 2014-15 David J. Bradshaw - dave@bradshaw.net
 *  License: MIT
 *  Modified for use in Twine/SugarCube by: HiEv (2020) v1.0
 */
(function() {
	function scaleImageMap() {
		function resizeMap() {
			function resizeAreaTag(cachedAreaCoords, idx) {
				function scale(coord) {
					var dimension = 1 === (isWidth = 1 - isWidth) ? "width" : "height";
					return (padding[dimension] + Math.floor(Number(coord) * scalingFactor[dimension]));
				}

				var isWidth = 0;
				areas[idx].coords = cachedAreaCoords.split(",").map(scale).join(",");
			}

			if (image) {
				var scalingFactor = {
					width: $(image).width() / image.naturalWidth,
					height: $(image).height() / image.naturalHeight,
				};
				var padding = {
					width: parseInt(
						window.getComputedStyle(image, null).getPropertyValue("padding-left"),
						10
					),
					height: parseInt(
						window.getComputedStyle(image, null).getPropertyValue("padding-top"),
						10
					),
				};
				cachedAreaCoordsArray.forEach(resizeAreaTag);
			}
		}
		function getCoords(e) {
			// Normalize coord-string to csv format without any space chars
			return e.coords.replace(/ *, */g, ",").replace(/ +/g, ",");
		}
		function debounce() {
			clearTimeout(timer);
			timer = setTimeout(resizeMap, 250);
		}
		function start() {
			function setupMap () {
				if ($("img").width()) {
					resizeMap();
				} else {
					if (++tries < 100) {
						setTimeout(setupMap, 20);
					}
				}
			}

			var tries = 0;
			if (image) {
				setupMap();
				var imo = $(context).find(".imageMapObserve");
				if (imo.length) {
					$(context).off("mouseup", ".imageMapObserve", resizeMap);
					imo.on("mouseup", resizeMap);
					if (window.ResizeObserver) {
						new ResizeObserver(debounce).observe($(context)[0].querySelector(".imageMapObserve"));
					}
				}
			}
		}
		function addEventListeners() {
			if (image) {
				image.addEventListener("load", resizeMap, false);  // Detect late image loads in IE11
			}
			window.addEventListener("focus", resizeMap, false);  // Cope with window being resized whilst on another tab
			window.addEventListener("resize", debounce, false);
			window.addEventListener("readystatechange", resizeMap, false);
			document.addEventListener("fullscreenchange", resizeMap, false);
			$("#ui-bar-toggle").click(debounce);
		}
		function beenHere() {
			return "function" === typeof map._resize;
		}
		function getImg(name) {
			return $(context).find('img[usemap="' + name + '"]')[0];
		}
		function setup() {
			areas = map.getElementsByTagName("area");
			cachedAreaCoordsArray = Array.prototype.map.call(areas, getCoords);
			image = getImg("#" + map.name) || getImg(map.name);
			map._resize = resizeMap;  // Bind resize method to HTML map element
		}

		var  /* jshint validthis:true */
			map = this, areas = null,
			cachedAreaCoordsArray = null,
			image = null, timer = null;
		if (!beenHere()) {
			setup();
			addEventListeners();
			start();
		} else {
			var imo = $(context).find(".imageMapObserve");
			if (imo.length) {
				$(context).off("mouseup", ".imageMapObserve", resizeMap);
				imo.on("mouseup", resizeMap);
				if (window.ResizeObserver) {
					new ResizeObserver(debounce).observe($(context)[0].querySelector(".imageMapObserve"));
				}
			}
			map._resize();  // Already setup, so just resize map
		}
	}
	function factory() {
		function chkMap(element) {
			if (!element.tagName) {
				throw new TypeError("Object is not a valid DOM element");
			} else if ("MAP" !== element.tagName.toUpperCase()) {
				throw new TypeError("Expected <MAP> tag, found <" + element.tagName + ">.");
			}
		}
		function init(element) {
			if (element) {
				chkMap(element);
				scaleImageMap.call(element);
				maps.push(element);
			}
		}

		var maps;
		return function imageMapResizeF(target) {
			maps = [];  // Only return maps from this call
			switch (typeof target) {
				case "undefined":
				case "string":
					Array.prototype.forEach.call(context.querySelectorAll(target || "map"), init);
					break;
				case "object":
					init(target);
					break;
				default:
					throw new TypeError("Unexpected data type (" + typeof target + ").");
			}
			return maps;
		};
	}

	var context = document;
	if (typeof define === "function" && define.amd) {
		define([], factory);
	} else if (typeof module === "object" && typeof module.exports === "object") {
		module.exports = factory();  // Node for browserfy
	} else {
		window.imageMapResize = factory();
	}
	if ("jQuery" in window) {
		window.jQuery.fn.imageMapResize = function $imageMapResizeF() {
			context = this.prevObject;
			return this.filter("map").each(scaleImageMap).end();
		};
	}
})();

$(document).on(":passagerender", function (event) {
	$(event.content).find("map").imageMapResize();
});
/* Image Map Resizer - End */ff0000",strokeOpacity:1,strokeWidth:1,fade:!0,alwaysOn:!1,neverOn:!1,groupBy:!1,wrapClass:!0,shadow:!1,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:.8,shadowPosition:"outside",shadowFrom:!1}})
;

Currently my stylesheet is as follows:

/* Resizable element style */
.resizable {
	display: inline-block;
	overflow: hidden;
	line-height: 0;
	resize: both;
}
.resizable img {
	width: 100%;
	height: 100%;
}

Can anyone give any advice?

Thanks

Some minor changes to your last examples:

1: The <div> element is missing the class property name.
eg. your example has…

<div="resizable imageMapObserve">

…and it should be…

<div class="resizable imageMapObserve">

2: The JavaScript code example has strange content after the /* Image Map Resizer - End */ block comment.
eg. I suspect the following content at the end of the JavaScript code…

ff0000",strokeOpacity:1,strokeWidth:1,fade:!0,alwaysOn:!1,neverOn:!1,groupBy:!1,wrapClass:!0,shadow:!1,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:.8,shadowPosition:"outside",shadowFrom:!1}})

…should not be there, so I deleted in my copy of your code, and I suggest you do the same to the copy in your project.

3: The <<nobr>> macro vs JavaScript inline // comments.

JavaScript inline // comments rely on the line-break at the end of the line to end the comment. The <<nobr>> macro suppress all line-breaks found within the bounds of its body, which can cause issues the line break was at the end of a inline comment.
eg. If your Passage contains a <<script>> macro call like the following, that is within the body of a <<nobr>> macro…

<<nobr>>
	<<script>>
		// An inline comment...
		someImportantJavaScript('do something);
	<</script>>
<</nobr>>

…then the <<nobr>> macro basically cause the contents of the <<script>> macro to become…

<<script>>// An inline comment... someImportantJavaScript('do something);<</script>>

…which means the function call is now part of the comment, so it won’t be executed. For this reason I suggest either;

  • Don’t place JavaScript that contains inline comments in the body of a <<nobr>> macro call.
  • Use JavaScript Block based /* comments */ instead.

eg. A modified variation of the <<done>> macro section of your example.

<<done>>
	<<script>>
		/* Apply maphilight to all images that have a usemap attribute, e.g.
			all the maps that are in this twine. This sets the default styling
			for all the maps. These are all the possible styling options.
			Note: for picking colors, check out http://hslpicker.com/. You can
		 	copy the HEX value as long as you leave off the "#".
		*/
		$("img[usemap]").maphilight({
				fill: true,							/* Fill the area? */
				fillColor: 'dd319b',		/* HEX format without the starting "#" */
				fillOpacity: 0.5,				/* Opacity of the filled area */
				stroke: true,					/* Outline the area? */
				strokeColor: 'ef9ace',
				strokeOpacity: 1,
				strokeWidth: 3,				/* Outline width */
				fade: true,						/* Animate when hovered with a fade? */
				alwaysOn: false,			/* Always show the areas? */
				neverOn: false,
				groupBy: false,
				wrapClass: true,
				shadow: false,
				shadowX: 0,
				shadowY: 0,
				shadowRadius: 6,
				shadowColor: '000000',
				shadowOpacity: 0.8,
				shadowPosition: 'outside',
				shadowFrom: false
		});
	<</script>>
 <</done>>

4: Moving the :passagerender event handle HiEv’s code.

HiEv’s code includes the following at the end of it…

$(document).on(":passagerender", function (event) {
	$(event.content).find("map").imageMapResize();
});

…which sets up an event handler that causes the imageMapResize() function to be called for every <map> element found in the contents of the current Passage being visited. But it tries to do that for every Passage visited, even those that don’t actually contain a <map> element, which is likely to be majority of the Passages in your project.

For this reason I suggest removing that section of code from the Story > JavaScript area of your project, and to add the following slightly modified variation of it to the Passage with the <map> element.

note: Ideally the following should be placed between the </map> end-tag of the map element and the <<done>> start tag of the done macro call.

<<script>>
	$(document).one(":passagerender", function (event) {
		$(event.content).find("map").imageMapResize();
	});
<</script>>

The Passage content should end up looking something like…

<<nobr>>
	<div class="resizable imageMapObserve">
    	<img src="https://i.ibb.co/HX9WGq3/Regions-and-Prefectures-of-Japan-2-svg.png" usemap="#image-map">
	</div>

<map name="image-map">
	<area 
               data-passage="Miyazaki"
               alt="Miyazaki"
               title="Miyazaki"  
               coords="89,870,129,789" 
               shape="rect">

	<area
              data-passage="Kagoshima"
              alt="Kagoshima"
              title="Kagoshima"  
              coords="82,835,48,887" 
              shape="rect">

<area
              data-passage="Kumamoto"
              alt="Kumamoto" 
              title="Kumamoto"  
              coords="62,779,85,830" 
              shape="rect">

 	<area
              data-passage="Oita" 
              alt="Oita" 
              title="Oita"  
              coords="92,745,118,741,129,789,75,769" 
              shape="poly">

 	<area
            data-passage="Nagasaki" 
            alt="Nagasaki" 
            title="Nagasaki"
            coords="22,807,54,803,43,785,12,765" 
            shape="poly">

 	<area
            data-passage="Saga"
            alt="Saga" 
            title="Saga"  
            coords="24,753,61,761,42,780,23,767" 
            shape="poly">

	<area
            data-passage="Fukuoka"
            alt="Fukuoka" 
            title="Fukuoka"  
            coords="72,719,90,740,70,765,41,747" 
            shape="poly">

	<area
            data-passage="Okinawa"
            alt="Okinawa" 
            title="Okinawa"  
            coords="614,778,626,782,609,831,598,826" 
            shape="poly">

	<area
            data-passage="Yamiguchi"
            alt="Yamaguchi" 
            title="Yamaguchi"  
            coords="102,690,130,707,134,723,69,716" 
            shape="poly">

	<area
            data-passage="Shimane"
            alt="Shimane" 
            title="Shimane"  
            coords="108,682,174,623,186,633,115,694" 
            shape="poly">
  
	<area
          data-passage="Hiroshima"
          alt="Hiroshima" 
          title="Hiroshima"  
          coords="128,689,178,654,193,687,146,705" 
          shape="poly">

	<area
          data-passage="Tottori"
          alt="Tottori" 
          title="Tottori"  
          coords="188,631,235,619,236,632,185,643" 
          shape="poly">

	<area
          data-passage="Okayama"
          alt="Okayama" 
          title="Okayama"  
          coords="190,648,229,642,231,675,197,683" 
          shape="poly">

	<area
          data-passage="Ehime"
          alt="Ehime" 
          title="Ehime"  
          coords="195,713,168,712,138,751,154,770" 
          shape="poly">

	<area
          data-passage="Kochi"
          alt="Kochi" 
          title="Kochi"  
          coords="155,776,204,717,228,730,180,783" 
          shape="poly">

	<area
          data-passage="Kagawa"
          alt="Kagawa" 
          title="Kagawa"  
          coords="204,693,240,697,209,709" 
          shape="poly">

	<area
          data-passage="Tokushima"
          alt="Tokushima" 
          title="Tokushima"  
          coords="213,713,246,698,265,719,242,734" 
          shape="poly">

	<area
          data-passage="Hyogo"
          alt="Hyogo" 
          title="Hyogo"  
          coords="239,617,256,617,284,668,261,703,236,663" 
          shape="poly">

	<area
          data-passage="Kyoto"
          alt="Kyoto" 
          title="Kyoto"  
          coords="261,616,297,629,312,662,271,635" 
          shape="poly">

	<area
          data-passage="Shiga"
          alt="Shiga" 
          title="Shiga"  
          coords="304,626,324,612,332,645,315,658" 
          shape="poly">

	<area
          data-passage="Mie"
          alt="Mie" 
          title="Mie"  
          coords="341,639,320,662,328,713,365,682" 
          shape="poly">

	<area
          data-passage="Nara"
          alt="Nara" 
          title="Nara"  
          coords="302,663,318,667,320,698,300,711" 
          shape="poly">

	<area
          data-passage="Osaka"
          alt="Osaka" 
          title="Osaka"  
          coords="288,652,298,658,298,684,288,684,290,674" 
          shape="poly">
          
	<area
          data-passage="Wakayama"
          alt="Wakayama" 
          title="Wakayama"  
          coords="276,692,288,691,315,738,277,718" 
          shape="poly">

	<area
          data-passage="Aichi"
          alt="Aichi" 
          title="Aichi"  
          coords="394,629,351,623,356,657,382,661" 
          shape="poly">

	<area
          data-passage="Shizuoka"
          alt="Shizuoka" 
          title="Shizuoka"  
          coords="454,617,411,622,388,660,461,648" 
          shape="poly">
          
	<area
          data-passage="Fukui"
          alt="Fukui" 
          title="Fukui"  
          coords="318,571,342,593,299,623" 
          shape="poly">

	<area
          data-passage="Gifu"
          alt="Gifu" 
          title="Gifu"
          coords="348,565,380,562,383,625,350,619,342,635,325,607,348,596,343,583" 
          shape="poly">

	<area
          data-passage="Ishikawa"
          alt="Ishikawa" 
          title="Ishikawa"  
          coords="351,500,334,509,326,564,337,573" shape="poly">

	<area
          data-passage="Toyama"
          alt="Toyama" 
          title="Toyama"  
          coords="380,527,348,537,346,563,380,557" 
          shape="poly">

	<area
          data-passage="Nagano"
          alt="Nagano" 
          title="Nagano"  
          coords="387,534,420,526,423,572,390,624,380,593" 
          shape="poly">

	<area
          data-passage="Yamanashi"
          alt="Yamanashi" 
          title="Yamanashi"  
          coords="420,587,442,585,463,596,422,611" 
          shape="poly">

	<area
          data-passage="Niigata"
          alt="Niigata" 
          title="Niigata"  
          coords="464,429,398,441,381,524,436,529" 
          shape="poly">

	<area
          data-passage="Gunma"
          alt="Gunma" 
          title="Gunma"  
          coords="451,517,424,546,439,572,466,553" 
          shape="poly">

	<area
          data-passage="Saitama"
          alt="Saitama" 
          title="Saitama"  
          coords="440,576,461,559,480,560,487,577,470,582" 
          shape="poly">

	<area
          data-passage="Tokyo"
          alt="Tokyo" 
          title="Tokyo"  
          coords="457,581,488,580,486,589,461,591,441,579" 
          shape="poly">

	<area
          data-passage="Kanagawa"
          alt="Kanagawa" 
          title="Kanagawa"  
          coords="486,594,470,592,456,605,461,616,488,614" 
          shape="poly">

	<area
          data-passage="Chiba"
          alt="Chiba" 
          title="Chiba"  
          coords="490,571,526,568,524,613,496,631,492,599" 
          shape="poly">

	<area
          data-passage="Ibaraki"
          alt="Ibaraki" 
          title="Ibaraki"  
          coords="509,517,526,513,528,565,498,569,489,561" 
          shape="poly">

	<area
          data-passage="Tochigi"
          alt="Tochigi" 
          title="Tochigi"  coords="458,519,487,501,503,519,490,552,472,557,464,542" 
          shape="poly">
    
	<area
          data-passage="Fukushima"
          alt="Fukushima" 
          title="Fukushima"  coords="532,509,504,516,488,498,454,518,449,490,464,468,490,464,503,452,524,454,533,471" 
          shape="poly">

	<area
          data-passage="Miyagi"
          alt="Miyagi" 
          title="Miyagi"  
          coords="508,395,546,408,523,451,492,451,499,407" 
          shape="poly">

	<area
          data-passage="Yamagata"
          alt="Yamagata" 
          title="Yamagata"  coords="464,395,494,400,489,462,463,464,468,425,450,428" 
          shape="poly">

	<area
          data-passage="Akita"
          alt="Akita" 
          title="Akita"  coords="457,315,496,312,493,365,508,394,466,389,447,348" 
          shape="poly">

	<area
          data-passage="Iwate"
          alt="Iwate" 
          title="Iwate"           coords="502,321,531,306,546,330,557,354,544,402,510,393,496,365"
          shape="poly">

	<area
          data-passage="Aomori"
          alt="Aomori" 
          title="Aomori"  coords="510,249,491,243,462,267,448,299,455,312,493,309,506,317,528,305,516,273" 
          shape="poly">

	<area
        data-passage="Hokkaido"
        alt="Hokkaido" 
        title="Hokkaido"  coords="496,3,656,54,676,114,626,146,585,208,500,222,455,253,444,243,432,190" 
        shape="poly">
</map>

<<script>>
	$(document).one(":passagerender", function (event) {
		$(event.content).find("map").imageMapResize();
	});
<</script>>

<<done>>
	<<script>>
		/* Apply maphilight to all images that have a usemap attribute, e.g.
			all the maps that are in this twine. This sets the default styling
			for all the maps. These are all the possible styling options.
			Note: for picking colors, check out http://hslpicker.com/. You can
		 	copy the HEX value as long as you leave off the "#".
		*/
		$("img[usemap]").maphilight({
				fill: true,							/* Fill the area? */
				fillColor: 'dd319b',		/* HEX format without the starting "#" */
				fillOpacity: 0.5,				/* Opacity of the filled area */
				stroke: true,					/* Outline the area? */
				strokeColor: 'ef9ace',
				strokeOpacity: 1,
				strokeWidth: 3,				/* Outline width */
				fade: true,						/* Animate when hovered with a fade? */
				alwaysOn: false,			/* Always show the areas? */
				neverOn: false,
				groupBy: false,
				wrapClass: true,
				shadow: false,
				shadowX: 0,
				shadowY: 0,
				shadowRadius: 6,
				shadowColor: '000000',
				shadowOpacity: 0.8,
				shadowPosition: 'outside',
				shadowFrom: false
		});
	<</script>>
 <</done>>
  <</nobr>>

note: When I visit the above Passage in my test project both the “Image Map Resizing” functionality and the “Map Hilight” functionality work.

But the “coords” of the <area> elements are still wrong for my setup, so the only highlighted areas I can find are in the bottom right corner of the image, around the “white” overview of the island.

However the size of those areas appear to be “correct”, and the highlighted areas that I can access are consistent when the image map is resized.

Hello Greyelf,

Thank you for taking the time to explain each step and the issues thus far. I’ve made all the recommended changes, but am still encountering the following errors:

Error [tw-user-script-0]: Invalid or unexpected token.

followed by

A fatal error has occured. Aborting
Error: $(…).find(…).imageMapResize is not a function.

followed by

Error: <>: bad evaluation: $(…).maphilight is not a function.

Stack Trace:
Error: <>: bad evaluation: $(…).maphilight is not a function
at Function.wikiWithOptions (:3:48325)
at Function.wiki (:3:48509)
at :3:250651
at :3:198706

Based on your previous reply, I feel this is still an issue with comments and the function call lines but I just keep hitting walls.

The tw-user-script part of that error message indicates there is a issue in the Story > JavaScript area of your project.

Experience tells me that that error is likely being cause by one or more lines in that JavaScript not being ended with a semi-colon when needed. Which can cause the structure of the JavaScript to be considered invalid.

The first error would halt the execution of the contents of the Story > JavaScript area, thus the functionality it is meant to create doesn’t happen, thus causing the later errors you are seeing.

The following is the JavaScript from my own test project, try replacing the contents of your project’s Story > JavaScript area with it to see if it gets rid of the first error.

note: Use the application’s Publish to File option to make a backup of your existing project before replacing your own JavaScript!!

// Tweaked version of maphilight (12-06-2016 build) to work with SugarCube 2 and Twine
!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):b(a.jQuery)}(window,function(a){var b,c,d,e,f,g,h,i,j,k,l;if(c=!!document.createElement("canvas").getContext,b=function(){var a=document.createElement("div");a.innerHTML='<v:shape id="vml_flag1" adj="1" />';var b=a.firstChild;return b.style.behavior="url(#default#VML)",!b||"object"==typeof b.adj}(),!c&&!b)return void(a.fn.maphilight=function(){return this});if(c){i=function(a){return Math.max(0,Math.min(parseInt(a,16),255))},j=function(a,b){return"rgba("+i(a.substr(0,2))+","+i(a.substr(2,2))+","+i(a.substr(4,2))+","+b+")"},d=function(b){var c=a('<canvas style="width:'+a(b).width()+"px;height:"+a(b).height()+'px;"></canvas>').get(0);return c.getContext("2d").clearRect(0,0,a(b).width(),a(b).height()),c};var m=function(a,b,c,d,e){if(d=d||0,e=e||0,a.beginPath(),"rect"==b)a.rect(c[0]+d,c[1]+e,c[2]-c[0],c[3]-c[1]);else if("poly"==b){a.moveTo(c[0]+d,c[1]+e);for(var f=2;f<c.length;f+=2)a.lineTo(c[f]+d,c[f+1]+e)}else"circ"==b&&a.arc(c[0]+d,c[1]+e,c[2],0,2*Math.PI,!1);a.closePath()};e=function(b,c,d,e,f){var h=b.getContext("2d");if(e.shadow){h.save(),"inside"==e.shadowPosition&&(m(h,c,d),h.clip());var i=100*b.width,k=100*b.height;m(h,c,d,i,k),h.shadowOffsetX=e.shadowX-i,h.shadowOffsetY=e.shadowY-k,h.shadowBlur=e.shadowRadius,h.shadowColor=j(e.shadowColor,e.shadowOpacity);var l=e.shadowFrom;l||(l="outside"==e.shadowPosition?"fill":"stroke"),"stroke"==l?(h.strokeStyle="rgba(0,0,0,1)",h.stroke()):"fill"==l&&(h.fillStyle="rgba(0,0,0,1)",h.fill()),h.restore(),"outside"==e.shadowPosition&&(h.save(),m(h,c,d),h.globalCompositeOperation="destination-out",h.fillStyle="rgba(0,0,0,1);",h.fill(),h.restore())}h.save(),m(h,c,d),e.fill&&(h.fillStyle=j(e.fillColor,e.fillOpacity),h.fill()),e.stroke&&(h.strokeStyle=j(e.strokeColor,e.strokeOpacity),h.lineWidth=e.strokeWidth,h.stroke()),h.restore(),e.fade&&a(b).css("opacity",0).animate({opacity:1},100)},f=function(a){a.getContext("2d").clearRect(0,0,a.width,a.height)}}else d=function(b){return a('<var style="zoom:1;overflow:hidden;display:block;width:'+b.width+"px;height:"+b.height+'px;"></var>').get(0)},e=function(b,c,d,e,f){var g,h,i,j;for(var k in d)d[k]=parseInt(d[k],10);g='<v:fill color="#'+e.fillColor+'" opacity="'+(e.fill?e.fillOpacity:0)+'" />',h=e.stroke?'strokeweight="'+e.strokeWidth+'" stroked="t" strokecolor="#'+e.strokeColor+'"':'stroked="f"',i='<v:stroke opacity="'+e.strokeOpacity+'"/>',"rect"==c?j=a('<v:rect name="'+f+'" filled="t" '+h+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+d[0]+"px;top:"+d[1]+"px;width:"+(d[2]-d[0])+"px;height:"+(d[3]-d[1])+'px;"></v:rect>'):"poly"==c?j=a('<v:shape name="'+f+'" filled="t" '+h+' coordorigin="0,0" coordsize="'+b.width+","+b.height+'" path="m '+d[0]+","+d[1]+" l "+d.join(",")+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+b.width+"px;height:"+b.height+'px;"></v:shape>'):"circ"==c&&(j=a('<v:oval name="'+f+'" filled="t" '+h+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(d[0]-d[2])+"px;top:"+(d[1]-d[2])+"px;width:"+2*d[2]+"px;height:"+2*d[2]+'px;"></v:oval>')),j.get(0).innerHTML=g+i,a(b).append(j)},f=function(b){var c=a("<div>"+b.innerHTML+"</div>");c.children("[name=highlighted]").remove(),b.innerHTML=c.html()};g=function(a){var b,c=a.getAttribute("coords").split(",");for(b=0;b<c.length;b++)c[b]=parseFloat(c[b]);return[a.getAttribute("shape").toLowerCase().substr(0,4),c]},l=function(b,c){var d=a(b);return a.extend({},c,!!a.metadata&&d.metadata(),d.data("maphilight"))},k=function(a){return!!a.complete&&("undefined"==typeof a.naturalWidth||0!==a.naturalWidth)},h={position:"absolute",left:0,top:0,padding:0,border:0};var n=!1;a.fn.maphilight=function(i){return i=a.extend({},a.fn.maphilight.defaults,i),c||n||(a(window).ready(function(){document.namespaces.add("v","urn:schemas-microsoft-com:vml");var b=document.createStyleSheet(),c=["shape","rect","oval","circ","fill","stroke","imagedata","group","textbox"];a.each(c,function(){b.addRule("v\\:"+this,"behavior: url(#default#VML); antialias:true")})}),n=!0),this.each(function(){var j,m,n,o,p,q,s;if(j=a(this),!k(this))return window.setTimeout(function(){j.maphilight(i)},200);if(n=a.extend({},i,!!a.metadata&&j.metadata(),j.data("maphilight")),s=j.get(0).getAttribute("usemap"),s&&(o=a('map[name="'+s.substr(1)+'"]'),j.is('img,input[type="image"]')&&s&&o.length>0)){if(j.hasClass("maphilighted")){var t=j.parent();j.insertBefore(t),t.remove(),a(o).unbind(".maphilight")}m=a("<div></div>").css({display:"block",backgroundImage:'url("'+this.src+'")',backgroundSize:"contain",position:"relative",padding:0,width:this.width,height:this.height}),n.wrapClass&&(n.wrapClass===!0?m.addClass(a(this).attr("class")):m.addClass(n.wrapClass)),j.before(m).css("opacity",0).css(h).remove(),b&&j.css("filter","Alpha(opacity=0)"),m.append(j),p=d(this),a(p).css(h),p.height=this.height,p.width=this.width,a(o).bind("alwaysOn.maphilight",function(){q&&f(q),c||a(p).empty(),a(o).find("area[coords]").each(function(){var b,f;f=l(this,n),f.alwaysOn&&(!q&&c&&(q=d(j[0]),a(q).css(h),q.width=j[0].width,q.height=j[0].height,j.before(q)),f.fade=f.alwaysOnFade,b=g(this),c?e(q,b[0],b[1],f,""):e(p,b[0],b[1],f,""))})}).trigger("alwaysOn.maphilight").bind("mouseover.maphilight, focus.maphilight",function(b){var d,f,h=b.target;if(f=l(h,n),!f.neverOn&&!f.alwaysOn){if(d=g(h),e(p,d[0],d[1],f,"highlighted"),f.groupBy){var i;i=/^[a-zA-Z][\-a-zA-Z]+$/.test(f.groupBy)?o.find("area["+f.groupBy+'="'+a(h).attr(f.groupBy)+'"]'):o.find(f.groupBy);var j=h;i.each(function(){if(this!=j){var a=l(this,n);if(!a.neverOn&&!a.alwaysOn){var b=g(this);e(p,b[0],b[1],a,"highlighted")}}})}c||a(p).append("<v:rect></v:rect>")}}).bind("mouseout.maphilight, blur.maphilight",function(a){f(p)}),j.before(p),j.addClass("maphilighted")}})},a.fn.maphilight.defaults={fill:!0,fillColor:"000000",fillOpacity:.2,stroke:!0,strokeColor:"ff0000",strokeOpacity:1,strokeWidth:1,fade:!0,alwaysOn:!1,neverOn:!1,groupBy:!1,wrapClass:!0,shadow:!1,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:.8,shadowPosition:"outside",shadowFrom:!1}});


/*! Image Map Resizer
 *  Desc: Resize HTML imageMap to scaled image.
 *  Copyright: (c) 2014-15 David J. Bradshaw - dave@bradshaw.net
 *  License: MIT
 *  Modified for use in Twine/SugarCube by: HiEv (2020) v1.0
 */
(function() {
	function scaleImageMap() {
		function resizeMap() {
			function resizeAreaTag(cachedAreaCoords, idx) {
				function scale(coord) {
					var dimension = 1 === (isWidth = 1 - isWidth) ? "width" : "height";
					return (padding[dimension] + Math.floor(Number(coord) * scalingFactor[dimension]));
				}

				var isWidth = 0;
				areas[idx].coords = cachedAreaCoords.split(",").map(scale).join(",");
			}

			if (image) {
				var scalingFactor = {
					width: $(image).width() / image.naturalWidth,
					height: $(image).height() / image.naturalHeight,
				};
				var padding = {
					width: parseInt(
						window.getComputedStyle(image, null).getPropertyValue("padding-left"),
						10
					),
					height: parseInt(
						window.getComputedStyle(image, null).getPropertyValue("padding-top"),
						10
					),
				};
				cachedAreaCoordsArray.forEach(resizeAreaTag);
			}
		}
		function getCoords(e) {
			// Normalize coord-string to csv format without any space chars
			return e.coords.replace(/ *, */g, ",").replace(/ +/g, ",");
		}
		function debounce() {
			clearTimeout(timer);
			timer = setTimeout(resizeMap, 250);
		}
		function start() {
			function setupMap () {
				if ($("img").width()) {
					resizeMap();
				} else {
					if (++tries < 100) {
						setTimeout(setupMap, 20);
					}
				}
			}

			var tries = 0;
			if (image) {
				setupMap();
				var imo = $(context).find(".imageMapObserve");
				if (imo.length) {
					$(context).off("mouseup", ".imageMapObserve", resizeMap);
					imo.on("mouseup", resizeMap);
					if (window.ResizeObserver) {
						new ResizeObserver(debounce).observe($(context)[0].querySelector(".imageMapObserve"));
					}
				}
			}
		}
		function addEventListeners() {
			if (image) {
				image.addEventListener("load", resizeMap, false);  // Detect late image loads in IE11
			}
			window.addEventListener("focus", resizeMap, false);  // Cope with window being resized whilst on another tab
			window.addEventListener("resize", debounce, false);
			window.addEventListener("readystatechange", resizeMap, false);
			document.addEventListener("fullscreenchange", resizeMap, false);
			$("#ui-bar-toggle").click(debounce);
		}
		function beenHere() {
			return "function" === typeof map._resize;
		}
		function getImg(name) {
			return $(context).find('img[usemap="' + name + '"]')[0];
		}
		function setup() {
			areas = map.getElementsByTagName("area");
			cachedAreaCoordsArray = Array.prototype.map.call(areas, getCoords);
			image = getImg("#" + map.name) || getImg(map.name);
			map._resize = resizeMap;  // Bind resize method to HTML map element
		}

		var  /* jshint validthis:true */
			map = this, areas = null,
			cachedAreaCoordsArray = null,
			image = null, timer = null;
		if (!beenHere()) {
			setup();
			addEventListeners();
			start();
		} else {
			var imo = $(context).find(".imageMapObserve");
			if (imo.length) {
				$(context).off("mouseup", ".imageMapObserve", resizeMap);
				imo.on("mouseup", resizeMap);
				if (window.ResizeObserver) {
					new ResizeObserver(debounce).observe($(context)[0].querySelector(".imageMapObserve"));
				}
			}
			map._resize();  // Already setup, so just resize map
		}
	}
	function factory() {
		function chkMap(element) {
			if (!element.tagName) {
				throw new TypeError("Object is not a valid DOM element");
			} else if ("MAP" !== element.tagName.toUpperCase()) {
				throw new TypeError("Expected <MAP> tag, found <" + element.tagName + ">.");
			}
		}
		function init(element) {
			if (element) {
				chkMap(element);
				scaleImageMap.call(element);
				maps.push(element);
			}
		}

		var maps;
		return function imageMapResizeF(target) {
			maps = [];  // Only return maps from this call
			switch (typeof target) {
				case "undefined":
				case "string":
					Array.prototype.forEach.call(context.querySelectorAll(target || "map"), init);
					break;
				case "object":
					init(target);
					break;
				default:
					throw new TypeError("Unexpected data type (" + typeof target + ").");
			}
			return maps;
		};
	}

	var context = document;
	if (typeof define === "function" && define.amd) {
		define([], factory);
	} else if (typeof module === "object" && typeof module.exports === "object") {
		module.exports = factory();  // Node for browserfy
	} else {
		window.imageMapResize = factory();
	}
	if ("jQuery" in window) {
		window.jQuery.fn.imageMapResize = function $imageMapResizeF() {
			context = this.prevObject;
			return this.filter("map").each(scaleImageMap).end();
		};
	}
})();
/* Image Map Resizer - End */