Open aeschylus opened 9 years ago
The dummy image should be implemented with a legacy tilesource, and the info.json for the real tilesource should be delayed until needed.
For the API methods on the canvas/resource level, see #39.
http://iangilman.com/osd/test/demo/m2/js/page.js accomplished most of this functionality, so it is a good reference.
The ultimate goal of this will be to create an introspect-able foundation and API on which to build and update openseadragon tiledImages that update when the layout and request status properties of these objects update, as well as other multi-modal renderings of the same data updating simultaneously.
For instance, a renderer (openseadragon) might place a tilesource at each of the calculated positions in the coordinate space, or some thumbnail creator might retrieve all the appropriate images from remote source and fuse them into a single jpeg for printing in a PDF, or a text-based interface listing of available resource, with their properties listed or controls attached to them, could be generated as the properties are updated with the setters.
A canvas is an abstract container with an x and y position in the openseadragon world. It is created from a IIIF canvas, and its main relevant property is having a height and width, which describe an aspect ratio for the object. Canvases have several image resources mapped onto them, so it will be necessary to initialize these image resources as separate objects from the canvas, specifying their positions in the coordinate system as functions of their parent canvas's position and their own "local" position on the canvas.
The initial configuration should be given a IIIF canvas description, and return an object with a number of updatable properties, getters, and setters, which can be accessed from outside the library and rendered in a number of different ways. The trick will be attaching the child images/resources as a reorderable list, and having some property that says whether or not the canvas needs to instruct its image resources to begin loading themselves and dismiss its static image placeholder.
At any time, it must be possible to determine the x and y coordinates, and the width and height (in the global coordinate system), as well as the ordering and properties of the children, of this object through a getter. Any dynamic change made to the structure through a setter must emit an event, so that any of an unknown number of representations of this internal structure who may be listening for this change may pull the updated data through a getter and re-render themselves. See flux.
Only one static tilesource is needed in openseadragon for the whole canvas, as a placeholder in a zoomed-out state. This may be thought of as a kind of "semantic zoom", in which additional information is concealed by a representation of a higher level of abstraction over the large set of image data - similar to mapping applications like google maps, which progressively provide more or less information appropriate for the "zoom level". This tilesource should be possible to dismiss once the canvas' other tilesources have been loaded.
An image resource has an aspect ratio and a position on the canvas, and may be composed of either a static image of a given dimension, a static image of a configurable dimension (resolution), or a tiling tilesource. Any of these may be clipped within a box, and may be hidden, re-ordered with respect to their neighbors. By default, if a IIIF tilesource url to an info.json is available, it must not be dereferenced until the image is in fact supposed to be visible. By default, openseadragon will lazy load the image resources themselves, but it will attempt to download the info.json immediately once the tilesource is added. This is the source of the major performance problems, so the tilesources must not even be created (or thus the info.json url dereferenced) until absolutely necessary.
We need to determine what kind of image it is: static or dynamic, "main", alternate, or "detail". This will then be mapped to the appropriate simple x, y, width, and height properties, and the static thumb and info.json url wil and clipmask will be retrieved accordingly. This is a lot of compatibility/variation checking on the image metadata to determine the correct initialisation parameters, so it would be good for the initialisation to be as uniform as possible, and just generate the correctly formatted initialisation in a factory. This would prevent dozens of if-thens all over the component's methods depending on these different types, though in the end that might be the only way. I will help out with this "resource factory", since I am one of about 12 people on earth who know all the annoying variations of image and placement types that need to be checked and compared.
At any time, it must be possible to introspect through a getter the x, y, width, and height of the object, as well as its state of the request for image data. This would make it possible, for instance, to render an SVG placeholder like a dotted box or "X" in its location, with a spinner, while it is being requested. That external UI component could listen to an event signaling that the image resources have arrived and then check the status with a getter to fade away, leaving the image in place of the former placeholder.
IIIF defines ways for the image to be "clipped" within its desired position, so that, for instance, a certain region of the annotating image can be featured within a region of the canvas, while the sides (such as a color bar or blank black space in the source image) do not appear, and instead "hang off" or are "clipped" outside of its local display box.
Some of these URLs appear on the demo page, but they are collected here as sample data for realizing the particular features they support.
There is a IIIF test fixtures collection with a minimal representation of each feature; the most notable manifests being:
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/24/manifest.json",
"@type": "sc:Manifest",
"label": "Test 24 Manifest: Image with IIIF Service"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/25/manifest.json",
"@type": "sc:Manifest",
"label": "Test 25 Manifest: Image with IIIF Service, embedded info"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/26/manifest.json",
"@type": "sc:Manifest",
"label": "Test 26 Manifest: Image different size to Canvas"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/27/manifest.json",
"@type": "sc:Manifest",
"label": "Test 27 Manifest: No Image"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/28/manifest.json",
"@type": "sc:Manifest",
"label": "Test 28 Manifest: Choice of Image"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/29/manifest.json",
"@type": "sc:Manifest",
"label": "Test 29 Manifest: Choice of Image with IIIF Service"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/30/manifest.json",
"@type": "sc:Manifest",
"label": "Test 30 Manifest: Main + Detail Image"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/31/manifest.json",
"@type": "sc:Manifest",
"label": "Test 31 Manifest: Detail with IIIF Service"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/32/manifest.json",
"@type": "sc:Manifest",
"label": "Test 32 Manifest: Multiple Detail Images"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/33/manifest.json",
"@type": "sc:Manifest",
"label": "Test 33 Manifest: Detail Image with Choice"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/34/manifest.json",
"@type": "sc:Manifest",
"label": "Test 34 Manifest: Detail Image with Choice, and 'no image' as option"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/35/manifest.json",
"@type": "sc:Manifest",
"label": "Test 35 Manifest: Partial Image as Main Image"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/36/manifest.json",
"@type": "sc:Manifest",
"label": "Test 36 Manifest: Partial Image as Main Image with IIIF Service"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/37/manifest.json",
"@type": "sc:Manifest",
"label": "Test 37 Manifest: Partial Image as Detail Image"
},
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/38/manifest.json",
"@type": "sc:Manifest",
"label": "Test 38 Manifest: Partial Image as Detail Image with IIIF Service"
},
As we can see, there are quite a few possible variations of image representation, but for the sake of openseadragon's tilesources, really we just need to know whether the source is static or dynamic, and if it needs to be clipped, and where it should be placed (x,y,w,h).
Images under a canvas's images list may be either "static" or dynamic. Pared-down test data:
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/30/manifest.json",
"@type": "sc:Manifest",
"label": "Test 30 Manifest: Main + Detail Image"
}, // static
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/24/manifest.json",
"@type": "sc:Manifest",
"label": "Test 24 Manifest: Image with IIIF Service"
}, // dynamic
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/26/manifest.json",
"@type": "sc:Manifest",
"label": "Test 26 Manifest: Image different size to Canvas"
}, // static, clipped
More realistic data: http://dms-data.stanford.edu/data/manifests/BnF/jr903ng8662/manifest.json
Pared-down test data: see "detail" image manifests above (there are several) More realistic case: http://demos.biblissima-condorcet.fr/iiif/metadata/BVMM/chateauroux/manifest.json
Pared-down test data: see "choice" related items above More realistic case: http://manifests.ydc2.yale.edu/manifest/Osbornfa1v2.json
It should be easy, through the resultant API, to create a photoshop-like "layers" palette for a single canvas in detail mode. For instance, the API methods for moving an image resource up or down in the stack, so that the others sit on top of it, adjusting its opacity, or simply toggling it on and off, should be present and easy to work with. For the ordering properties, see #39.
Stack of resource objects.
Resource has an id, a service, a dummy and a real (or possibly no tilesource, just "dummy" or static image).
Resource has opacity, x, y, and clip region. It is visible or hidden, and "needed" or "not needed" (it doesn't need to be rendered or requested yet).