0 votes
by (150 points)
I want to display an image with a client-side image map on a page, and have links in the image be similar to the standard twine links (e.g., [[Go to Room 1->room1]]), so that when the user clicks a part of the image, they're taken to the linked page.

I've tried putting twine-style inks in the raw HTML, but no luck -- the HTML seems to be copied to the output verbatim.  I guess it might be possible to build up the HTML as a string, with the twine links added at various points, but that would end up being pretty ugly.  Is there a better way?

2 Answers

0 votes
by (159k points)

If I understand your question correctly you want to do the following:

a. Display an image (a Map?) within a particular Passage.
b. You want to display markup based links on top of this image in set locations/positions.

The following steps implement one way you could archive that outcome.

1. Identifying the Map Passage.
I suggest assigning the relevant Passage a know Passage Tag (like map) which you can target in your CSS.

2. Displaying the image (Map) when the Map Passage is shown.
I suggest using CSS within your story"s Story Stylesheet area to allocate a background image (the Map) to the tagged Passage, I suggest using a background image because that will make it easier to display the links on top of the image. Harlowe uses a tw-passage element to represent the area to that the current Passage content is displayed in, and that element will contain the current Passage's tag list within it's tags attribute.

tw-passage[tags~="map"] {
	background-image: url('media/map.jpg');
	background-repeat: no-repeat;
	background-size: cover;
	height: 800px;

note: I don't know the name or dimensions of your image, so you will need to edit the above CSS to suit your needs. The tw-passage will need a height (in relation to the image's height) to force the element to be large enough to contain the image. You may also want to use other background related CSS attributes.

3. Uniquely identifying each markup based link.
Your example infers that each markup based link will target a different Passage (eg. room1, room2, etc), if that is true then you can use that information to uniquely identify each markup based link. Each the tw-link element created to represent each markup based link will contain a passage-name attributed which is assigned the name of the relevant Target Passage. The HTML for a markup based link looks like the following:

<tw-expression type="macro" name="link-goto">
	<tw-link tabindex="0" passage-name="room1" data-raw="">Go to Room 1</tw-link>

4, Using CSS to re-position each individual markup based link.
The follow demonstrates the type of CSS you will need to place within your Story Stylesheet area to position a particular markup based link in a particular location/position on top of the image.

tw-passage[tags~="map"] tw-link[passage-name="room1"] {
    width: 10em;
	position: absolute;
	top: 5em;
	left: 3em;

The above uses the passage-name attribute to indicate which markup based link to target, it assigns a width to the element to make sure it is wide enough to show the relevant Link Text without wrapping, and it includes both a top & left attribute to correctly position the starting point of the tw-link element.

note: You would need to change at least the passage-name attribute and the top / left attribute(s) for each markup based link being shown. I suggest reading up on CSS to determine if there are any other attributes you may wish to use. 

by (150 points)

Thanks for the answer -- some useful tips in there.  But unfortunately that's not what I meant by 'image map' -- I should have made it clearer.

You can see an example of an HTML image map here.  It shows some HTML on the left, and the result on the right.  The image map in the HTML defines a bunch of areas in the image that are links, and link to the corresponding 'href' of the image map. What I'm trying to do is get the 'href' to be a twine-style link to another 'page' of the story.

+1 vote
by (159k points)
edited by

HTML image map... and related area element.

As far as I am aware Harlowe has no support for referencing a Passage via a href attribute (in either an anchor element or an area element), nor does it have a Javascript API so there is no function() to call to initiate passage traversal. So to solve your request you must first overcome two main issues.

note: the following examples are based on a combination of the area-map you linked to in one of your comments as well as the markup based link in your original post.

1. Adding onclick handlers to each of your area elements.

This can be done by adding a script element contain Javascript like the following to the end of the Passage containing the area-map. The code locates a particular area element based on the value of its alt attribute and then assigned a click handler to that element. A jQuery preventDefault() function call is used to suppress the area element's href attribute being triggered.

$('area[alt="Sun"]').on("click", function(e){
	Code to simulate the clicking of a particular link.

2. Simulating the clicking of a markup based link.

One way to do this is to add actual markup based links to the Passage which you then hide, then use Javascript to send a click event to one of these hidden markup based links. So if you had some hidden links like the following.

<div style="display: none;">
[[Go to Room 1->room1]]
[[Go to Room 2->room2]]

... then using the generated tw-link element's passage-name attribute to locate the particular markup based link you could send a click event like so.



Combining these two techniques together would results in Javascript like the following.

$('area[alt="Sun"]').on("click", function(e){

... which results in the room1 Passage being shown to the Reader once the Sun area is selected.

by (150 points)
That's excellent.  Just tried it, and it works perfectly!  Many thanks.

I'm curious about the preventDefault() call.  Things seem to work the same with or without it.  When would it make a difference?
by (159k points)
edited by

When would it make a difference?

When ever the web-browser's developer decides that they support the chaining of the area element's href attribute as well as the element's onclick handler, because you never want that to happen within a Twine story as that is likely to result in the Reader looking at something other than the current Passage of your story.

I updated my solution to include a link to the jQuery preventDefault() function.