The image you insert as the background must also be embedded at the highest resolution you want it to be zoomed to. So, for example, if you want the zoomed regions to be magnified by 150%, then this image needs to be 150% larger than it will appear when shrunk to fit the Kindle Fire screen. For a full screen image this would be 1536x900 pixels (1024x600 times 1.5). The pixels per inch, by the way, does not matter: 72 ppi will display the same as 300 ppi on the screen, since it's the number of pixels that determines its dimensions relative to the display size.
So now we get to the crux of the matter. This div container creates the Tap Target Zone: the area within which a double-tap activates the zoom of that region. The size and position of the Target Zone is defined by the div class values provided in the CSS:
Here the top edge of the tap zone begins 30% down from the top, 15% in from the left, extends downward a further 45% of the display height, and 70% of its width - leaving 15% on the right and 25% on the bottom not covered by the tap zone. As I mentioned in my prior post on live text, one of the benefits of activating live text by deleting the book-type metadata entry is that it causes the Tap Target Zone to appear as a gray box when touched, allowing you to see exactly where the target boundaries are. Even if you do not intend to use live text in your final product (although I can't imagine why), it will help you to position your target element here.
DIV 4: LINES 22-28
Our final container holds the data that defines the magnified region itself, and here is where things get a little tricky. The div id value must equal the targetId from the JSON object, as this is the target that link is referencing. The class value defines the "parent" element, which is simply a container to enclose a number of distinct constituent elements. The parent is required here in order to create the lightbox effect, since the lightbox needs an opacity value that applies only to it, and not the zoomed content itself. If you don't intend to use a lightbox you can use a standard magTarget here and do away with the parent altogether, as I've done on Page 4 of the template.
You will notice that the only values applied to the target-mag-parent element in the stylesheet are a width and height of 100%, and a display value of none. The former simply makes the parent large enough to contain everything you put inside it and no larger, and the latter keeps it invisible until it's activated. Also, if you delete the lightbox element as mentioned in the previous paragraph, be sure to include the display: none entity in the magTarget CSS so that the magnified element is not visible until activated. Otherwise, it will appear by default, and disappear when double-tapped (which, by the way, might be good to know if you want something hidden underneath a larger image to appear, as might be useful in children's books).
This parent div container holds two individual sub-containers, the first being our lightbox element and the second one containing the magnified content itself.
Line 23 inserts the lightbox, which is defined in the CSS by the target-mag-lb values. Like the parent element itself, the target-mag-lb values define the lightbox as covering 100% of the width and height of its content. But since the only content in the lightbox is a background fill color without any defined size parameters of its own, the lightbox defaults to the overall dimensions of the display screen, thus filling the entire page with color. The color used in Amazon's examples is a dark shade of gray, which I've retained as it seems a natural choice for dimming out an image, but of course you can use any color that you like. The opacity value determines how much this fill obscures the background image.
Now at last we come to the magnified content itself. This is held within the second sub-container, whose id value defines its size and position:
#zoom1-magTarget {
top: 21%;
left: 0%;
height: 62%;
width: 100%;
}
And whose
class defines some values for its content:
div.target-mag {
position: absolute;
overflow: hidden;
border: 5px solid #000000;
}
We'll get to size and position in a minute, as this is a rather tangled affair, but first let's dispense with some other factors. The
target-mag values here are only part of the picture, as there are several sub-components entered separately. However, these provide some overall values that define how the magTarget functions...
First, it will use
absolute positioning to make it easier to place exactly where we want it. The
overflow value keeps the portions of the image not visible within the window
hidden. And finally, we'll add a nice little border around the whole to make it stand out better. You can also use the
border-radius tag to round the edges if you like, or any other decorative frills you care to add, so long as they're supported. This, incidentally, is how you might create circular
magTargets for use as callout boxes or dialogue balloons: by adding a high
border-radius value and a white background fill under centered text, your magnified target would look like a dialogue bubble, albeit without the pointed indicator.
In this example I've added a bit of text to overlay atop the magnified image, and this requires a bit of explanation. Since we can't use the
SourceId tag to magnify the actual text on the page (since that source does not include the magnified image we also want), we must enter the alternate text here. Consequently, this can be the exact same text or something altogether different, as it is here.
p.textzoom {
font-size: 150%;
margin: 20%;
top: 18%;
z-index: 1;
}
I've used a separate paragraph class to define the values of the magnified text that vary from the default text, foremost of which is that it be 150% larger. The next two lines position the text where I want it in the magnified target, and the final one is what allows the text to be overlaid on top of the image rather than being forced below. Since the default
z-index value is "0" any larger number will place that element higher in the vertical stack. Bear in mind that the positioning information here is relative to the
magTarget boundaries, because my default paragraph has a
relative position value. This actually makes it easier to position elements within the enlarged region, since it's easier to visualize their position with regard to their immediate surroundings.
Finally we come to the image itself, which is added as before using the
img src= insertion method, minus the
class tag. Here we're referencing the same image as the one above, but this isn't strictly necessary. You could, in fact, use this to create images that
change when double-tapped, such as a facial expression or an opened door. In that case you might create an image of the same size but with different content that the double-tap or swipe would trigger. You might, in fact, have a series of events all strung together, each one triggered by sequential swipes. But I'm letting my imagination get away from me... let's get back to the matter at hand.
In the stylesheet there are a number of additional entries for the
div.target-mag element, but with the
img entity appended. The first of these defines the actual image resolution:
div.target-mag img {
position: absolute;
height: 1536px;
width: 900px;
}
These are the actual dimensions of the image you've included in your file, and this entry tells the device that the image contained within the
target-mag is 1536x900 pixels in size. The following entries provide values for that image various magnifications by appending a
zoom factor:
div.target-mag img.zoom100 {
position: absolute;
height: 1024px;
width: 600px;
}
div.target-mag img.zoom150 {
position: absolute;
height: 1536px;
width: 900px;
}
The first of these defines the default display size, and will be the size of your
page rather than the
screen size; that is, as discussed earlier, whatever size your page is when fitted to the Kindle Fire screen, which may or may not be the full display resolution if the aspect ratio doesn't match. Here I'm using an image that is formatted to fit the Fire display precisely.
The second entry defines the size of that image magnified by 150%, which in this example is our default zoom factor. However, you can include as many variations on this as you wish, but to do so you will also need to include a
class tag to your
img src= entry in the HTML, as such:
<img class="zoom150" src="...
In this way you can magnify various panels at different zoom levels, providing your image is embedded at the size that magnification factor requires. If you only use one zoom factor throughout your book you can leave this
class tag out.
One more thing should be mentioned. While the
Kindle Publishing Guidelines expressly state that there are four
standard zoom factors, you can in fact use any magnification level you choose. The
zoom### tag is just a reference that tells the device to display the image at that size, rather than shrinking it to fit the display. But I've used other magnification factors and they work just fine. The number given after
zoom doesn't even have to be the actual zoom factor used (although using another number would likely prove confusing); it's the values entered for the
height and
width that matter.
So now that we have our content added we need to work out how to size and position it...
MAG TARGET SIZE & POSITION
Determining the size and placement of the
magTarget window can be a matter of considerable frustration, but a little simple math can go a long way toward alleviating these headaches. Let's say that your image is like the one in the picture shown above, and you want your first
magTarget to appear in the upper left corner at 150% of the display size. First you must determine how large the panel to be enlarged is, and the easiest way to do this is to open your full-page image in a graphics program such as Photoshop or GIMP. Using the rulers set to show
percent, you first measure the width and height of the section to be magnified, and then multiply those dimensions by the amount of magnification to achieve your window size.
So, for example, an image section 42% wide by 35% high in the original intended to be viewed at 150% when zoomed would require a
magTarget 63% by 52.5% in size. These values are entered in the stylesheet in the
#name-magTarget entry (where
name is the specific tag reference for that entity). Using percentages, by the way, removes the necessity of calculating pixels to percents, and "future proofs" the layout against changes in display resolution by using relative values rather than absolute ones, theoretically requiring only the change of the absolute height/width display values and replacing the actual images with higher resolution ones. I haven't been quite as consistent as I should in using percents instead of pixels myself, however.
Bear in mind, of course, that the amount of magnification determines the maximum size of an image section that can be zoomed. Thus, for an image you want to zoom by 200%, 50% x 50% is the largest section of a full page image you can isolate within a window, which in that case would be a window 100%x100% in size, covering the entire display with the enlarged section of the image. At 150%, a width and height of 66.6% would achieve the same result.
Positioning the window on the page works much the same way, although in most cases, given the larger size of the magnified region, you'll want to align it to one or more of the edges, such as
left: 0% in the example given above. The
width: 100% value fills the screen horizontally, while the
top: 21% and
height: 62% values place the image near the middle of the page vertically, with a 17% margin remaining on the bottom.
Of course, if isn't quite as simple as that once you move away from the upper left-hand corner. Since the full size image is much larger than the display screen, much of it will fall beyond the edges, beyond the reach of the window. Thus, we need another entry in the stylesheet:
#zoom1-magTarget img {
top: -77%;
left: -25%;
}
The image by default is positioned in the upper left-hand corner, with the overflow going off the right and bottom of the screen. Therefore, in order to view those sections of the enlarged image we need to move it up and left until the section we want to view is visible within the window. Now, if you thought you had a headache before, you're in for a real treat now.
The crucial factor here is that all values are in percentages of the
magTarget size, not the actual
image size, nor the
display size (unless, of course, your window size is the same as the display). Thus, you need to work out how far you need to move the image, and convert that to percentages of the window you've created to view the magnified panel.
For example, let's say you have an image that is 1200 pixels wide by 2048 pixels high: that is, exactly four times the size of the Kindle Fire screen, with a window size the same
width as the display (600px), but only half its
height (512px), aligned to the bottom of the screen. This might be a common configuration to view a panel in the lower-right corner, for example, zoomed to fill the bottom portion of the screen.
Since the actual image by default is placed flush against the top and left of the screen, you'll need to move the image 600 pixels to the left and 1024 pixels up from its default position in order to view the lower-right quarter in a window at the bottom of the screen. Your values would therefore be
left: -100% and
top:-200%. That is to say, you need to move the image 100% of the width of the
magTarget size (600px), and twice its height (512px x2 =1024px). It's easiest if you always place your window flush against at least one edge of the display, and preferably a corner, leaving the other two sides for adjusting the window size to fit the given panel.
Of course, it's rarely that easy, since you also need to take the window position into account, as well as any margins surrounding it if it's centered or only flush against one edge. And, of course, you've defined your
magTarget window using percents not pixels, so there's a little math involved there, too. But using this same formula you can work out fairly quickly just how far you need to move the image to get it roughly where you need it. A little tweaking once it's more or less in place will ultimately get it where you want it.
CREATING A SEMI-TRANSPARENT FILL
As promised in my last post, I'm adding this addendum describing the modifications required to include a transparent background fill for your mag targets that leaves the text fully opaque. You'll need to create your default content using a
parent element as we did in the example above. This allows us to include two separate
div containers in the
magTarget that enclose the lightbox and the text within separate entities so that they can be formatted individually
.
Here's my HTML for the added content on Page 3 of the template:
<div id="zoom2">
<a class="app-amzn-magnify" data-app-amzn-magnify=
'{"targetId":"zoom2-magTargetParent", "ordinal":5}'>
<p class="note2">Default Content Here</p>
</a>
</div>
<div id="zoom2-magTargetParent" class="target-mag2-parent">
<div class="target-mag2-lb"></div>
<div id="zoom2-magTarget" class="target-mag2">
<p>Magnified Text</p>
</div>
</div>
When inserting your default content in the main
div container be sure to enclose it within the anchor tag for the JSON object so that the default text will disappear when the magnified region appears. Otherwise you'll see the default content through the transparent fill. But anything contained within the JSON link will disappear. You can format this content however you like, with one caveat: for some strange reason it appears you must insert this content
directly between the anchor tags, without any intervening
div containers. Otherwise the link will not be active. I have some theories about this, but no time to test them right now (that is, if this tutorial is ever to be finished). I'll update the post when I work it out. [SEE UPDATE BELOW!]
For the
target content you'll format the
parent element the same as before, with a
height and
width of 100% and a
display value of
none to make it hidden by default. Within this you want to create a
div element for your lightbox, and another for your magnified content. It's easier to fill the background after you know how large the
magTarget will be, so let's format that content first:
#zoom2-magTarget {
top: 75%;
left: 0%;
display: block;
}
div.target-mag2 {
position: absolute;
display: none;
font-size: 150%;
padding: 15px;
border: 5px solid #000000;
background-color: none;
}
First, use the
div id values to size and position your magnified region. Here I've positioned it three quarters of the way down the screen and aligned it to the left edge. I haven't defined a
width or
height, as these will be determined by the magnified text, which in this case will fill the full width of the screen and create a box tall enough to fit it all. You can, of course, define a width less than that of the display, as I did in the first
magTarget example on this page.
The
class tag values are where you format the appearance of the
magTarget. Unlike the image zoom example, here is where you define the zoom factor for the text content, which in this case has a magnification value of 150%. Adding a percent here allows you to multiply the default formatting by a consistent factor, rather than trying to calculate the larger pixel value. The other important change here is to set the
background-color to
none (or just leave it out). This creates a fully transparent container with just the content visible.
Now that you have your magnified region active and visible you can format the lightbox to fill it in. Of course, you want the fill to be
inside the magnified region rather than outside it, so you'll need to change the size and position values to match the text container. Your
top and
left position values will be the same as the text container itself, so just copy those. The
width you've also either set or left unspecified as I have, in which case it equals 100%. But the
height is a little trickier, since the text itself determines that value. You'll just have to use some educated guesswork to get it close and adjust until you get it right.
div.target-mag2-lb {
top: 75%;
left: 0%;
height: 18.5%;
width: 100%;
background-color: #FFFFFF;
opacity: .3;
}
The fill itself is provided by the
background-color value - here set to white - and an
opacity that determines how transparent or opaque that color is, in a value ranging from 0 to 1, where 0 is invisible and 1 is completely opaque. You can enter the color value as a hexadecimal code as I have here, or as RGB, or simply by using names for basic colors, such as black and white. White seems the logical choice, as it appears to lighten and desaturate the underlying full page image, making the text easier to read by standing out in higher contrast against the lightened backdrop.
Here, by the way, you don't need to use a
z-index to stack the text on top of the color fill as you did with the magnified image, since the
background-color element is placed at the bottom by default.
That's about all I can tell you for right now, although I'm sure there much more to it than that, and more than you can do. Just use your imagination and the possibilities are likely endless. Best of luck, and let me know what you come up with.
UPDATE: SATURDAY 3-24-12
So this is one of those really stupid things you do when you're tired and have been staring blindly at code for days on end. I finally found some time this morning to have a look at the
div issue mentioned above, in which it
appeared as if you had to insert text directly between the JSON anchors. This, as I suspected, is not the case. You can, in fact, add anything you like within the anchors and it will disappear when the link is activated.
What was precluding it from doing so in my semi-transparent fill example was the absence of a
height value for the root container ("zoom2"), so that my TapTarget had
width and correct positioning, but no
height, and thus was inaccessible (though technically present). I had somehow neglected to add this in the latter example, even though it's in the main example above ("zoom1"). This was likely due to the fact that text itself determines the height of its container. But, of course, it does not do so for the parent container which contains that container. That height you have to set yourself. Also, be sure you add the following to your css:
div.fs a {
display: block;
width : 100%;
height: 100%;
}
This will tell the JSON object to fill the space you've just provided with an active link. My apologies for the confusion. I didn't mention that specifically in the tutorial, although it's in the template, so I thought I'd mention it here just in case. My apologies for any confusion.