Skip to content

The Rendering Process

Eric Liu edited this page Aug 10, 2018 · 6 revisions

Here is a more thorough explanation of what is happening "behind the scenes" when a document is loaded.

  1. The user loads a page containing the document viewer, and it is instantiated. An asynchronous fetch request is sent for the requested document (objectData), a IIIF Image Manifest.

  2. Diva receives response in the form of a JSON object, parses it, and calculates things like the total height of all the images stacked together, the number of 256x256 (or less) tiles that are needed to show each image, and the dimensions of the images at this specific zoom level. It then stores the data as a custom Diva object (ImageManifest) in JSON format, as in the following example below for a document with one page:

{
    "pages": [
        {
            "d": [
                {
                    "h": 223,
                    "w": 170
                },
                {
                    "h": 446,
                    "w": 340
                },
                {
                    "h": 892,
                    "w": 680
                },
                {
                    "h": 1784,
                    "w": 1361
                },
                {
                    "h": 3568,
                    "w": 2723
                }
            ],
            "m": 4,
            "l": "Curzon b.07(080)",
            "il": null,
            "f": "https://iiif.bodleian.ox.ac.uk/iiif/image/caeb212c-a639-41da-a42a-60f6b05a0d0b",
            "url": "https://iiif.bodleian.ox.ac.uk/iiif/image/caeb212c-a639-41da-a42a-60f6b05a0d0b/",
            "api": 2,
            "paged": true,
            "facingPages": false,
            "canvas": "https://iiif.bodleian.ox.ac.uk/iiif/canvas/caeb212c-a639-41da-a42a-60f6b05a0d0b.json",
            "otherImages": [],
            "xoffset": null,
            "yoffset": null
        }
    ],
    "maxZoom": 4,
    "maxRatio": 1.310319500550863,
    "minRatio": 1.310319500550863,
    "itemTitle": "Curzon b.07(080)",
    "metadata": [
        {
            "label": "Digital.Bodleian",
            "value": "<span>View at: <a href=\"https://digital.bodleian.ox.ac.uk/inquire/p/caeb212c-a639-41da-a42a-60f6b05a0d0b\">Digital.Bodleian</a></span>"
        },
        {
            "label": "Shelfmark",
            "value": "Curzon b.07(080)"
        },
        {
            "label": "Subject",
            "value": "Napoleon I, Emperor of the French, 1769-1821"
        },
        {
            "label": "Type",
            "value": "Page record"
        },
        {
            "label": "Type",
            "value": "Image.Graphic"
        },
        {
            "label": "Format",
            "value": "1 print"
        },
        {
            "label": "Format",
            "value": "237 x 172 mm"
        },
        {
            "label": "Format",
            "value": "232 x 285 mm"
        },
        {
            "label": "Format",
            "value": "etching"
        },
        {
            "label": "Date",
            "value": "1814"
        },
        {
            "label": "Title",
            "value": " Le petit homme rouge berçant son fils."
        },
        {
            "label": "Displaylanguage",
            "value": "French"
        },
        {
            "label": "Source",
            "value": "modhis001-aek-0001-0"
        },
        {
            "label": "Identifier",
            "value": "12197"
        },
        {
            "label": "Collection",
            "value": "History and Politics"
        },
        {
            "label": "Language",
            "value": "fre"
        },
        {
            "label": "Description",
            "value": "French political cartoon"
        },
        {
            "label": "Description",
            "value": "References: De Vinck, No. 7815"
        },
        {
            "label": "Id",
            "value": "caeb212c-a639-41da-a42a-60f6b05a0d0b"
        }
    ],
    "paged": false,
    "_maxWidths": [
        170,
        340,
        680,
        1361,
        2723
    ],
    "_maxHeights": [
        223,
        446,
        892,
        1784,
        3568
    ],
    "_averageWidths": [
        170,
        340,
        680,
        1361,
        2723
    ],
    "_averageHeights": [
        223,
        446,
        892,
        1784,
        3568
    ],
    "_totalHeights": [
        223,
        446,
        892,
        1784,
        3568
    ],
    "_totalWidths": [
        170,
        340,
        680,
        1361,
        2723
    ],
    "_urlAdapter": {}
}

As can be seen in this example, the variables being returned are item_title, some dimension variables prefixed by _ which are determined through parsing the dims array, paged, maxZoom, maxRatio, minRatio, metadata (the manifest's metadata), and pages (an array of all the pages). Within pages, we have an array of data for each page - the number of columns, the number of rows, the width and height of the image (all of these for each zoom level), the zoom level, the page ID, and the image filename.

  1. Upon a successful request, the data returned by the request goes into the "success" callback function. Some relevant information (zoom level, total height, the array of pages etc) is stored in the settings array so that it can be accessed by other functions. Then, we loop through every page in the array of pages, and try to load it using a helper function. That helper function will first check if the page is near the viewport (within 100 pixels of it, top or bottom). If it is, it will load the page by looping through each row and column of tiles in the image, and then loading them as background images in a div. If it is not, it will not create a container or load images into the DOM, saving on downloading time until the user scrolls the viewport down.

  2. Once all the pages have been appended to the DOM, the user will be automatically scrolled to the correct place. This isn't usually relevant for the initial AJAX request, but if the width of the page is larger than the width of the panel, then the user will be scrolled horizontally so that the page is centered in the viewport.

  3. Now that the script is done loading the pages, it idles and listens for several possible events to be fired. These events are as follows:

    • Scrolling vertically through the pages of the document: when a user attempts to scroll vertically within the document panel, either using the scrollwheel, by dragging the scrollbar, or using the keyboard, a function handling the scroll request is invoked. First, the direction of the scroll (up or down) is determined. Then, we loop through all the pages above (or below, if scrolling down) the last page that was loaded that are either in the viewport or below it (more relevant when the user is trying to go to a specific page). Only pages that are actually near the viewport will be loaded, due to performance considerations; pages that are in between the last loaded page and the page the user is trying to load will not load if they are not near the viewport.
    • Zooming in using the buttons: +/- buttons are created. Whenever a user clicks one of the buttons, a helper function is invoked with the new zoom level passed as a parameter. This function stores the current vertical and horizontal scrolls, and zooms the image in or out to the new dimensions and resolutions.
    • Zooming in by double-clicking: a user can zoom in or out on a specific region, which will then be centered in the viewport, by double-clicking on it (holding the control [ctrl] key while double-clicking results in zooming out). Double-clicking calls a helper function which will figure out the desired new zoom as well the coordinates of the point that needs to be centered, set a boolean representing the double-click event to true, then zoom to that new level. The button label is then updated to reflect the new zoom level.
    • Going to a specific page: This tool is enabled by default, but can be disabled if so wished. If enabled, the user is provided with a small text box and a button permitting the user to enter a page label and jump directly to that page. If the label is not a valid page label, then the tool will attempt to match the user's input to a specific page index. For example, if working with the Beromunster manifest and the user enters bm_001, the viewer will jump to the first page. If, however, the user enters 10, the tool will fail to match against a specific label and instead attempt to match 10 to a given label (in this case, likely bm_010).