The standalone viewer

MAT's document component can be used, without the rest of MAT, to view, annotate, align, or compare annotated documents. You may want to embed this capability in your own Web tool or workflow. This document describes how to include the appropriate Web pages from the MAT distribution; how to generate a document which the MAT document component can understand; and how to enable hand annotation, comparison and alignment.

For instance, let's say you have a Java servlet which accesses a database in which your annotations are stored. You might use our Java library to produce a serialized document in the appropriate format, retrieve it in your Web application via AJAX, and pass this serialization to the embedded standalone document viewer. Alternatively, you could forward your annotations to your Web application in your own format, and use our JavaScript library to create the appropriate document.

An example can be found in $MAT_PKG_HOME/web/examples/standalone_viewer_example.html.

Viewer setup

The following includes are required from $MAT_PKG_HOME/web/htdocs:

The Javascript files must be loaded in the order given. If you're running the MAT Web server, you can load them in your document head as follows (where "yourserver" is the host where the MAT Web server is running):

<script type="text/javascript" src="http://yourserver:7801/MAT/js/mat_utils.js"></script>
<script type="text/javascript" src="http://yourserver:7801/MAT/js/mat_core.js"></script>
<script type="text/javascript" src="http://yourserver:7801/MAT/js/core_ui.js"></script>
<script type="text/javascript" src="http://yourserver:7801/MAT/js/mat_doc_display.js"></script>
<script type="text/javascript" src="http://yourserver:7801/MAT/js/mat_standalone_doc_viewer.js"></script>
<link rel="stylesheet" type="text/css" href="http://yourserver:7801/MAT/css/mat_core.css">

Alternatively, you can copy these six files to your own Web server.

No other files are required. Although the MAT UI relies heavily on the Yahoo! UI Toolkit, the standalone doc viewer does not, nor does it rely on any other toolkit.

Creating the viewer

In order to create the standalone viewer, you need, minimally, a tag set and a DIV where the viewer will be rendered.

<script type="text/javascript">
var Tags = [{label: "PERSON", css: "background-color: #CCFF66"},
{label: "LOCATION", css: "background-color: #F99CC"},
{label: "ORGANIZATION", css: "background-color: #99CCFF"}];

var docDiv = document.getElementById("docDiv");

// Set up the viewer.
var viewer = new MAT.DocDisplay.StandaloneViewer({
tags: Tags,
div: docDiv
});
</script>

There's a lot more you can do, which we'll return to when we look at the viewer details. For now, let's move on to creating documents.

Creating and displaying a single document

The document you provide should be a Javascript object which corresponds to the MAT JSON format, versions 1 or 2. For instance:

<script type="text/javascript">
var Document1 = {
"signal": "David Asher is a former coordinator of North Korea policy at the State Department.",
"metadata": {},
"asets": [{"type": "ORGANIZATION", "attrs": [], "annots": [[65, 81]]},
{"type": "LOCATION", "attrs": [], "annots": [[39, 50]]},
{"type": "PERSON", "attrs": [], "annots": [[0, 11]]}]
};
</script>

We assume that you'd create these documents automatically somehow, by converting documents in your favorite format into MAT JSON format, or from your previous interactions with MAT. The document you pass can also be a JSON string in this format, rather than the resulting structure, or, alternatively, you can use the MAT JavaScript UI to create the appropriate document, e.g.:

<script type="text/javascript">
var Document1 = viewer.newDocument("David Asher is a former coordinator of North Korea policy at the State Department."); Document1.createAnnotation("PERSON", 0, 11);
Document1.createAnnotation("LOCATION", 39, 50);
Document1.createAnnotation("ORGANIZATION", 65, 81);
</script>

To display this document, just call renderSingleDocument():

<script type="text/javascript">
viewer.renderSingleDocument(Document1);
</script>

The viewer will reset itself before it displays the document, so you can reuse the viewer as often as you want.

Displaying aligned documents

You can also display an alignment of multiple documents which all have the same document signal. Keep in mind that this mechanism only works for span annotations.

<script type="text/javascript">
viewer.renderDocumentAlignment([
{doc: Document1, position: "above", initial: "1"},
{doc: Document2, position: "above", initial: "2"},
{doc: GoldDocument, position: "behind", initial: "G"}
]);
</script>

In this example, the argument to renderDocumentAlignment is a Javascript array of objects with the following keys and values:

key
value
description
doc
a MAT JSON document
either a JSON string, a Javascript object, or an object created by newDocument()
position
a string
either "above" (annotations appear above the text), "behind" (annotations appear behind the text) or "below" (annotations appear below the text)
initial
a one-character string
a shorthand reference to the document in the viewer

The stacking order of the documents is determined by the order of the entries in the Javascript array: earlier elements are above later elements. There can be only one element with a position of "behind", obviously.

The viewer will reset itself before it displays the document alignment, so you can reuse the viewer as often as you want.

Displaying a document comparison

Unlike document alignments, a true document comparison works for both spanned and spanless annotations. These documents are created by the Python library, using the same pairing algorithm used by the scorer. So in order to generate such a document, you'll need to do some work in your own Web backend, either by capturing the output of the MATCreateComparisonDocument utility, or (if your Web backend is Python) by directly calling the libraries which that utility calls. Once you have such a document (either a JSON object or its corresponding string), you can create the comparison view as follows:

<script type="text/javascript">
viewer.renderDocumentComparison(doc);
</script>

or

<script type="text/javascript">
viewer.renderDocumentComparison(doc, {
pivot: {
docName: ...,
initial: ...
},
others: [{
position: ...,
docName: ...,
initial: ...
}, ...]
});
</script>

In this second case, the second argument is a JavaScript object which describes the documents, and gives you more control over how the documents are referenced in the comparison view. The pivot is the reference document; the others are the documents which you're comparing to the reference document. The others array should be in the same order as the documents that you passed to the comparison creation document utility. The position and initial attributes have the same interpretation as they do for document alignments; the docName is a longer name by which you want the document to be described. Note that you can't change the position of the pivot; it is always behind the text.

Enabling hand annotation

If you want to do hand annotation in your document, you'll need to add a few more headers, and you'll need to provide access to the YAHOO! UI Toolkit, which we use to manage the annotation popups.

Add the following headers immediately before the load line for mat_standalone_doc_viewer.js:

<script type="text/javascript" src="http://yourserver:7801/MAT/resources/yui-2.6.0-dist/build/yuiloader/yuiloader.js"></script>
<script type="text/javascript" src="http://yourserver:7801/MAT/js/workbench_ui_popup_mgr.js"></script>
<link href="http://yourserver:7801/MAT/css/workbench_ui_annotation.css" rel="stylesheet" type="text/css">

Once you've done this, you need to do three more things.

First, we need to ensure that YUI is loaded before we create the viewer. Because of how browsers load documents, this is harder than it should be. You'll need to place the code which creates the viewer in an onload() function, and you'll also need to make use of the MAT.DocDisplay.StandaloneViewer.waitForYUI() function. Second, create your viewer with the "annotatable" attribute set; and third, enable hand annotation using the enableHandAnnotation method. These steps are all illustrated here:

<html>
<head>
....
<script>
function onload() {
MAT.DocDisplay.StandaloneViewer.waitForYUI(function () {
var viewer = new MAT.DocDisplay.StandaloneViewer({
tags: Tags,
annotatable: true,
div: docDiv
});

viewer.enableHandAnnotation();
});
}
</script>
....
</head>
<body onload="onload()">
....
</body>
</html>

These last two steps are separate so that if you want to control whether hand annotation is enabled via an external radio button, you can.

Note: there is a bug in Firefox 9 where, if the first element of the document body is a block element whose default style has a top margin, such as <p>, the annotation popup will insert an invisible monitor element which erroneously blocks the collapse of the top margin of that first block element. You can get around this by enclosing the entire body of the document in a <div>.

Details: the viewer object

When you create a viewer, there are a lot of parameters you can set; by far, the most important is how you tell the viewer about the annotations you want it to recognize. There are three possible ways of doing this, with increasing levels of power and complexity:

Choose the parameter that best suits your needs, but choose only one. You can use the MATAnnotationInfoToJSON tool to generate the simplified or expanded annotation set descriptors for the "atr" or "taskATRFragment" parameters.

The viewer is instantiated with a single argument, a Javascript object with the following keys and values:

key
value
description
tags
a tag table
see above and below. Either this, or atr, or taskATRFragment must be provided.
atr
a more complex tag table
the fomat of this parameter must be a simplified JSON annotation set descriptor. Either this, or tags, or taskATRFragment must be provided.
taskATRFragment
a most complex tag table
the format of this parameter must be an expanded JSON annotation set descriptor. Either this, or tags, or atr must be provided.
div
a Javascript DOM object
the DOM object corresponding to the DIV in which you'd like to view your output
taskName
a string
the name you want to use if the standalone viewer wants to display a task name. Optional. This may not be used anywhere.
annotatable
a boolean
if true, the viewer will be set up to permit hand annotation. Optional. Default is false. If true, you can then use the enableHandAnnotation() and disableHandAnnotation() methods.
textRightToLeft
a boolean
if true, the viewer will display text right to left. Optional. Use this to display documents in, e.g., Arabic or Hebrew.
legendDiv
a Javascript DOM object
the DOM object corresponding to the DIV in which you'd like to have the tag legend rendered. Optional.
callbacks
a Javascript object
Each key is the name of a callback, and each value is a function. Use this object to customize the behavior of the viewer when certain events occur. These function names and their arglists are:
  • uiError(msg):  a function which will report an error message string to your UI. If not defined, alert() will be used.
  • uiInform(msg):  a function which will report an status message string to your UI. If not defined, alert() will be used.
  • uiClearPane(div):  a function which will clear the DOM object argument. The default function removes every child.
  • mouseOverAnnotations(contentObj): a function which will display the content description object when the mouse hovers over an annotation. The default does nothing. The object has three key/value pairs: "type" (either "content" or "admin"), "labels" (a list of strings), "suffix" (basically, the initial from the entry in the document comparison invocation, if available).
  • cancelMouseOverAnnotations(): a function which is called when the mouse stops hovering over an annotation. The default does nothing.
There are a few more, but you'll never need them. Consult the source code if you're curious.
editorContainer
a Javascript object
Optional. A Javascript object which manages an editor div. You might want this if, e.g., you want the object to do something when the annotation is changed or deleted. This object should implement the methods getAnnotationDisplayDiv(), which should return a div into which the display is rendered, and notifyVisualDisplay(annot, disp), which notifies the container that a display is available. The container is now responsible for implementing the display API, namely calling annot.addVisualDisplay(disp) and annot.removeVisualDisplay(disp) at the appropriate times, and also forceDisplayResponse() and forceRemoveRedisplayResponse(), which should at least call those same methods on the disp. Only one of editorDiv and editorContainer can be specified.

Consult the code if you're curious about this parameter.
editorDiv
a Javascript DOM object
an HTML element in which any annotation editors/viewers can be rendered. They will be popped up otherwise. Optional.
uiSettings
a Javascript object
Optional. A Javascript object where each key is the name of a UI setting, and each value is a value appropriate for that setting.
extraGestures
an array of Javascript objects
If you want to take advantage of the new ability to add gestures to the annotation popup menu, you can pass them in here. Each object in the array should have a label attribute, and either a url_link or a function attribute, e.g.:

[{label: "Search Google", url_link: "http://www.google.com/search?q=$(_text)"}]

For instance, let's say that you have a tag table in the variable "Tags", as above; a div with the ID "docDiv", as above; a div with the ID "legDiv", where you want the legend rendered; and a div with the ID "updateDiv", where you want to display the annotation that's being hovered over. You'd instantiate the viewer as follows:

var viewer = new MAT.DocDisplay.StandaloneViewer({
tags: Tags,
taskName: "Named Entity",
div: document.getElementByID("docDiv"),
legendDiv: document.getElementByID("legDiv"),
callbacks: {
mouseOverAnnotations: function(contentObj) {
document.getElementByID("updateDiv").innerHTML = contentObj.labels.join(", ") + (contentObj.suffix || "");
},
cancelMouseOverAnnotations: function() {
document.getElementByID("updateDiv").innerHTML = "";
}
}
});

Viewer methods

enableHandAnnotation()
If the annotatable key is provided during configuration, you can turn on hand annotation with this method. Hand annotation will only be available with single documents, never with comparisons.
disableHandAnnotation()
Turn off hand annotation using this method.
newDocument(signal)
Create a new document with the specified signal. The result will be of type MAT.Annotation.AnnotatedDoc. See mat_core.js for how to interact with this object.
renderSingleDocument(doc)
Render a single document to the DIV configured for the viewer. The doc can either be the result of newDocument() above, or a Javascript object in MAT-JSON format, or a JSON string in that format.
renderDocumentAlignment(comps)
Render an alignment of multiple documents to the DIV configured for the viewer. See here for more details.
renderDocumentComparison(doc)
renderDocumentComparison(doc, details)
Render a comparison of multiple documents to the DIV configured for the viewer. See here for details.
getDocument()
Retrieve a document which has been displayed using renderSingleDocument(). You might want to use this method to retrieve the results of annotation, if you rendered the document using MAT-JSON instead of by creating a new document using the newDocument() method.
styleAnnotation(annot, params)
Allows you to assign special styling to particular annotations. If properly configured, it returns an undo function, which can be combined with other functionality to style and unstyle annotations in order, for instance. See the source code for details.

Details: the tag table

The tag table is a list of annotations which will be recognized and displayed. It is a Javascript array of objects with the following keys and values:

key
value
description
label
a string
an annotation label in the MAT JSON document. Required.
attrs
an array of two-element arrays
if you want to associate a visible label with an annotation label plus some attribute-value pairs (e.g., if you want ENAMEX TYPE="PERSON" to show up as PERSON in your display), you can do this by specifying the attribute-value pairs here as an array of two-element arrays, e.g., [["TYPE", "PERSON"]], and then specifying the effectiveLabel key.
effectiveLabel
a string
see the description of attrs immediately above. The visible label for a combination of an annotation label plus some attribute-value pairs.
css
a string
a CSS specification for your label (e.g., "background-color: blue"). Required.

If you choose to display an annotation legend (see below), the elements in the legend will appear in the same order you listed them in the tag table. Remember, the CSS will apply to every subspan of the marked text, and the text may be divided into subspans if annotations overlap, so using left and right borders is not recommended.