Creating a Lightbox Using IIIF Presentation and Image APIs

Introduction

As I explained in my previous post on the IIIF APIs, some objects in CONTENTdm are made up of multiple images. This presents a challenge to a consumer who wants to embed this object in their own site. One way to handle this is for the consumer to use the IIIF Presentation and Image APIs to create a lightbox to display the object. For those who might be unfamiliar with the concept of a “lightbox,” this is a way of displaying an image or set of images by displaying a smaller version of the image(s) that opens a larger, full-screen version of the image.

For the purposes of this example, the goal is to parse a manifest for a postcard, which consists of two images representing the front and back of the postcard, and display them.

Creating a lightbox

HTML for the lightbox

The first thing that has to be done to accomplish this goal is to create a spot on the webpage to display the thumbnails and then the full-size image.

<div id="images"><!-- image thumbnails here --></div>

<div id="photo_popup" class="modal">

<span class="close cursor">×</span>

<div class="modal-content">

    <div id="mySlide"><!--full size image here --></div>

    <div class="caption-container">

      <p id="caption"><!-- caption here --></p>

    </div>

</div>

</div>

CSS for the lightbox

Because a lightbox is constructed using CSS to format and style the full-size version of the image a particular way, the relevant styles need to be added to the page as well.

body {
  font-family: Verdana, sans-serif;
  margin: 0;
}
* {
  box-sizing: border-box;
}
.row > .column {
  padding: 0 8px;
}
.row:after {
  content: "";
  display: table;
  clear: both;
}
.column {
  float: left;
  width: 25%;
}
/* The Modal (background) */
.modal {
  display: none;
  position: fixed;
  z-index: 1;
  padding-top: 100px;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: black;
}
/* Modal Content */
.modal-content {
  position: relative;
  background-color: #fefefe;
  margin: auto;
  padding: 0;
  width: 90%;
  max-width: 700px;
}
/* The Close Button */
.close {
  color: white;
  position: absolute;
  top: 10px;
  right: 25px;
  font-size: 35px;
  font-weight: bold;
}
.close:hover,
.close:focus {
  color: #999;
  text-decoration: none;
  cursor: pointer;
}
.caption-container {
  text-align: center;
  background-color: black;
  padding: 2px 16px;
  color: white;
}
img.demo {
  opacity: 0.6;
}
.active,
.demo:hover {
  opacity: 1;
}
img.hover-shadow {
  transition: 0.3s
}
.hover-shadow:hover {
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)
}

Reading the manifest

Once these basic parts of the lightbox are created, the manifest for the object needs to be read in order to add thumbnails for each image to the page.

$.getJSON( " https://sandbox.contentdm.oclc.org/digital/iiif-info/floodpost/290",
function (data) {
$("#images").empty();
var html = '';
html += '<h2 style="text-align:center">' + data.label + '</h2>';
//thumbnails                       
});

The code above makes an HTTP request to the URL https://sandbox.contentdm.oclc.org/digital/iiif-info/floodpost/290, which is the manifest for the postcard, “Flooded Street East Side, Dayton, Ohio.” The HTTP request retrieves a JSON response and then parses out the label element from the manifest and places it in an h2 tag.

Displaying thumbnails

Next, the code needs to get each canvas [S3] and the associated resource service URL. A canvas is a logical view of some part of the digital object that the client is supposed to display to the user. A canvas can have one or more resources. In the case of the manifest we're working with, each canvas has a single resource, an image. The resource service URL is the URL for the IIIF API endpoint for the image.

html += '<div class="row">';
$.each(data.sequences[0].canvases, function(i,canvas){
html += '<div class="column">';
html += '<span id="' + canvas.images[0].resource.service['@id'] + '"><img src="';
html += canvas.images[0].resource.service['@id'] + '/full/300,/0/default.jpg" alt="' + canvas.label
html += '" class="hover-shadow-cursor"/></span>';
html += '</div>';
});
html += '</div>';
$('#images').append(html);

For each canvas, an HTML div is generated that contains span tag with

  • an ID for the image service and
  • an image tag
    • with a src attribute that points to the image sized to 300 pixels wide and
    • with an alt attribute set to the label for the canvas.

Each canvas div is then added to the div with the ID of “images.” The result is that thumbnails for each canvas are displayed the user.

Opening the lightbox

The next portion of code needs to allow the larger version of the image to be displayed to the user. This is accomplished via a JavaScript that fires a “click” event on the element with the class “hover-shadow-cursor”, which we set in the above code that generates our thumbnails.

This event causes a series of actions to be taken.

$(document.body).on('click', '.hover-shadow-cursor', function(event) {
    event.preventDefault();
    // create a lightbox
    img += '<img src="' + $(this).parent().attr('id');
    img += '/full/1000,/0/default.jpg" style="width:100%"/>';
    var caption = $(this).attr('alt');
    $('#photo_popup').css("display", "block");
    $('#mySlide').css("display", "block");
    $('#mySlide').append(img);
    $('#caption').append(caption);
});

First, a new image tag is created with a src attribute set to the full version of the image sized to 1000 pixels wide. Next, a caption is created and set to the value of the alt attribute of the thumbnail (the label for the image). Next, the elements in the HTML for the lightbox are set to display. Finally, the img and caption elements are added to the page.

Closing the lightbox

For a lightbox to function properly, a user needs to be able to close it. To do this, code to close the lightbox needs to be added. This is done from another “click” event, which is attached to the element with the class “close.”

$(document.body).on('click', '.close', function(event) {
$('#photo_popup').css("display", "none");
$("#mySlide").empty();
$("#caption").empty();
});

This “click” event sets the lightbox element to not display and removes the image and caption portions of the HTML.

Conclusion

Using the Presentation and Image APIs together offers developers many different options for displaying a digital object outside the context of the digital repository. While this example is designed specifically to display two images, the basic code can be altered to display many thumbnails. This is done by deciding the number of thumbnails to display in each row and altering the code to display rows with this number of images.

Example

$.each(data.sequences[0].canvases, function(i,canvas){
               if (i === 0) {
                   html += '<div class="row">';
               }
               html += '<div class="column">';
               html += '<span id="' + canvas.images[0].resource.service['@id'];
               html += '"><img src="' + canvas.images[0].resource.service['@id'];
               html += '/full/300,/0/default.jpg" alt="' + canvas.label;
               html += '"class="hover-shadow-cursor"/></span>';
               html += '</div>';
               if (i === data.sequences[0].canvases.length - 1) {
                   html += '</div>';
               } else if ((i + 1) % 4 === 0) {
                   html += '</div>';
                   html += '<div class="row">';
               }
       });

The technique can also be used to embed a single thumbnail that opens a larger image.

$.each(data.sequences[0].canvases, function(i,canvas){
    html += '<div class="image">';
    html += '<span id="' + canvas.images[0].resource.service['@id'] + '">';
    html += '<img src="' + canvas.images[0].resource.service['@id'] + '/full/300,/0/default.jpg"';
    html += ' alt="' + canvas.label + '" class="hover-shadow-cursor"/></span>';
    });
    $('#images').append(html);
});

Another potential option would be to alter the code to show both the image and the metadata from the manifest. An example of this is in the Developer Network repository.

These examples are fairly simple uses of the Presentation and Image APIs. However, these APIs can be used to power much more robust tools for displaying digital objects. Open-source viewer tools—like Mirador and Universal Viewer—use these two APIs. They take these basic concepts and elevate them to create dynamic, full-featured digital object viewers that provide navigation, zooming, display of multiple objects, and other features.

  • Karen Coombs

    Karen Coombs

    Senior Product Analyst