Commit 9484ca64fa3019727bd28d2a4beddc764913f2e4

Authored by Bartłomiej Nitoń
1 parent 29efb79e

Added facet attribute and popups for binary relations.

client/src/visualizer.js
... ... @@ -126,7 +126,7 @@ var Visualizer = (function($, window, undefined) {
126 126 return span;
127 127 };
128 128  
129   - var EventDesc = function(id, triggerId, roles, klass) {
  129 + var EventDesc = function(id, triggerId, roles, klass, facet="none") {
130 130 this.id = id;
131 131 this.triggerId = triggerId;
132 132 var roleList = this.roles = [];
... ... @@ -137,6 +137,7 @@ var Visualizer = (function($, window, undefined) {
137 137 this.equiv = true;
138 138 } else if (klass == "relation") {
139 139 this.relation = true;
  140 + this.facet = facet;
140 141 }
141 142 // this.leftSpans = undefined;
142 143 // this.rightSpans = undefined;
... ... @@ -176,6 +177,7 @@ var Visualizer = (function($, window, undefined) {
176 177 } else if (eventDesc.relation) {
177 178 this.relation = true;
178 179 this.eventDescId = eventNo;
  180 + this.facet = eventDesc.facet
179 181 }
180 182 // this.marked = undefined;
181 183 };
... ... @@ -647,8 +649,8 @@ var Visualizer = (function($, window, undefined) {
647 649 t2 = rel[2][1][1];
648 650 }
649 651 data.eventDescs[rel[0]] =
650   - // (id, triggerId, roles, klass)
651   - new EventDesc(t1, t1, [[rel[1], t2]], 'relation');
  652 + // (id, triggerId, roles, klass, facet)
  653 + new EventDesc(t1, t1, [[rel[1], t2]], 'relation', rel[3]);
652 654 });
653 655  
654 656 // attributes
... ... @@ -2929,21 +2931,15 @@ Util.profileStart('before render');
2929 2931 recGetRelatedEquivSpans(related, spans, data);
2930 2932 });
2931 2933 }
2932   - var getRelatedQuasiSpans = function(id, spans, data) {
2933   - spans[id] = true;
  2934 + var getRelatedBinarySpans = function(id, spans, data) {
2934 2935 var span = data.spans[id];
2935   - $.each(span.incoming, function(arcNo, arc) {
2936   - var related = arc.origin;
2937   - if (related in spans || arc.type != "Quasi")
2938   - return true;
2939   - spans[related] = true;
2940   - });
2941 2936 $.each(span.outgoing, function(arcNo, arc) {
2942 2937 var related = arc.target;
2943   - if (related in spans || arc.type != "Quasi")
  2938 + if (related in spans || !arc.relation)
2944 2939 return true;
2945   - spans[related] = true;
2946   - });
  2940 + spans[related] = arc;
  2941 +
  2942 + });
2947 2943 }
2948 2944  
2949 2945 var highlightSpan = function(span, highlight, highlightGroup, bgColor, highlightRounding) {
... ... @@ -2976,7 +2972,6 @@ Util.profileStart('before render');
2976 2972 // (spanTypes.SPAN_DEFAULT && spanTypes.SPAN_DEFAULT.bgColor) ||
2977 2973 // '#ffffff');
2978 2974 var bgColor = "#99FF66";
2979   - var bgColor2 = '#FF66FF';
2980 2975  
2981 2976 highlight = [];
2982 2977 highlightSpan(span, highlight, highlightGroup, bgColor, highlightRounding);
... ... @@ -2990,31 +2985,24 @@ Util.profileStart('before render');
2990 2985  
2991 2986 var related = {};
2992 2987 recGetRelatedEquivSpans(id, related, data);
2993   -
2994   - var spanIds = [];
  2988 +
2995 2989 $.each(related, function(spanId, dummy) {
2996   - spanIds.push('rect[data-span-id="' + spanId + '"]');
2997 2990 var relatedSpan = data.spans[spanId];
2998 2991 highlightSpan(relatedSpan, highlight, highlightGroup, bgColor, highlightRounding);
2999 2992 });
3000   -
3001   - //hack to higlight quasi identity
3002   - var quasi = {};
3003   - getRelatedQuasiSpans(id, quasi, data);
3004   - var count = 0;
3005   - for(var prop in quasi) {
3006   - if(quasi.hasOwnProperty(prop))
3007   - ++count;
3008   - }
3009   - if (count > 1) {
3010   - $.each(quasi, function(spanId, dummy) {
3011   - spanIds.push('rect[data-span-id="' + spanId + '"]');
3012   - var relatedSpan = data.spans[spanId];
3013   - highlightSpan(relatedSpan, highlight, highlightGroup, bgColor2, highlightRounding);
3014   - });
3015   - }
3016   -
3017   - highlightSpans = $svg.find(spanIds.join(', ')).parent().addClass('highlight');
  2993 +
  2994 + // hack to highlight relations
  2995 + var binary = {};
  2996 + getRelatedBinarySpans(id, binary, data);
  2997 + $.each(binary, function(spanId, arc) {
  2998 + var relatedSpan = data.spans[spanId];
  2999 + var color = relationTypesHash['SPAN_DEFAULT'].color;
  3000 + if (relationTypesHash[arc.type] != null) {
  3001 + color = relationTypesHash[arc.type].color;
  3002 + }
  3003 + highlightSpan(relatedSpan, highlight, highlightGroup, color, highlightRounding);
  3004 + });
  3005 + dispatcher.post('displayRelationsComments', [id, data, relationTypesHash]);
3018 3006 }
3019 3007 forceRedraw();
3020 3008 } else if (!that.arcDragOrigin && (id = target.attr('data-arc-role'))) {
... ...
client/src/visualizer_ui.js
... ... @@ -259,12 +259,45 @@ var VisualizerUI = (function($, window, undefined) {
259 259 element.css({ top: y, left: x });
260 260 };
261 261  
  262 + var adjustToSpan = function(spanId, element, offset, top, right) {
  263 + var span = $(spanId);
  264 + var spanX = span.position().left;
  265 + var spanY = span.position().top;
  266 + // get the real width, without wrapping
  267 + element.css({ left: 0, top: 0 });
  268 + var screenHeight = $(window).height();
  269 + var screenWidth = $(window).width();
  270 + // FIXME why the hell is this 22 necessary?!?
  271 + var elementHeight = element.height() + 22;
  272 + var elementWidth = element.width() + 22;
  273 + var x, y;
  274 + offset = offset || 0;
  275 + if (top) {
  276 + y = spanY - elementHeight - offset;
  277 + if (y < 0) top = false;
  278 + }
  279 + if (!top) {
  280 + y = spanY + offset;
  281 + }
  282 + if (right) {
  283 + x = spanX + offset;
  284 + if (x >= screenWidth - elementWidth) right = false;
  285 + }
  286 + if (!right) {
  287 + x = x = spanX - elementWidth - offset;
  288 + }
  289 + if (y < 0) y = 0;
  290 + if (x < 0) x = 0;
  291 + element.css({ top: y, left: x });
  292 + };
  293 +
262 294 var commentPopup = $('#commentpopup');
263 295 var commentDisplayed = false;
264 296  
265 297 var displayCommentTimer = null;
266 298 var displayComment = function(evt, target, comment, commentText, commentType, immediately) {
267 299 var idtype;
  300 +
268 301 if (commentType) {
269 302 // label comment by type, with special case for default note type
270 303 var commentLabel;
... ... @@ -468,8 +501,58 @@ var VisualizerUI = (function($, window, undefined) {
468 501 });
469 502 };
470 503  
  504 + var displayRelationCommentTimers = [];
  505 + var relationsPopupsContainer = $('#relationspopups');
  506 + var displayRelationsComments = function(sourceId, data, relationTypesHash) {
  507 +
  508 + for (timer in displayRelationCommentTimers) {
  509 + clearTimeout(timer);
  510 + }
  511 + displayRelationCommentTimers = [];
  512 +
  513 + var span = data.spans[sourceId];
  514 + $.each(span.outgoing, function(arcNo, arc) {
  515 + var related = arc.target;
  516 + if (!arc.relation)
  517 + return true;
  518 +
  519 + var relType = "Unknown Relation";
  520 + if (relationTypesHash[arc.type] != null) {
  521 + relType = relationTypesHash[arc.type].labels[1];
  522 + }
  523 + var targetId = arc.target;
  524 + var comment = ('<div class="comment_text">' +
  525 + Util.escapeHTML(relType) +
  526 + '</div>');
  527 + var targetFullId = 'rect[data-span-id="' + targetId + '"]';
  528 +
  529 + // display initial comment HTML
  530 + commentLabel = '<b>Facet:</b> ';
  531 + comment += commentLabel + Util.escapeHTMLwithNewlines(arc.facet);
  532 +
  533 + relationsPopupsContainer.append("<div id='relationpopup' class='relTo"+targetId+"'></div>")
  534 + var popup = relationsPopupsContainer.children().last();
  535 +
  536 + var idtype = 'comment_relation';
  537 + popup[0].className = idtype;
  538 + popup.html(comment);
  539 + adjustToSpan(targetFullId, popup, 10, true, true);
  540 +
  541 + /* slight "tooltip" delay to allow highlights to be seen
  542 + before the popup obstructs them. */
  543 + var displayRelationCommentTimer = setTimeout(function() {
  544 +
  545 + popup.stop(true, true).fadeIn();
  546 +
  547 + }, 500);
  548 + displayRelationCommentTimers.push(displayRelationCommentTimer);
  549 +
  550 + });
  551 + };
  552 +
471 553 var onDocChanged = function() {
472 554 commentPopup.hide();
  555 + relationsPopupsContainer.empty();
473 556 commentDisplayed = false;
474 557 };
475 558  
... ... @@ -518,6 +601,7 @@ var VisualizerUI = (function($, window, undefined) {
518 601  
519 602 var hideComment = function() {
520 603 clearTimeout(displayCommentTimer);
  604 + relationsPopupsContainer.empty();
521 605 if (commentDisplayed) {
522 606 commentPopup.stop(true, true).fadeOut(function() { commentDisplayed = false; });
523 607 }
... ... @@ -2284,6 +2368,7 @@ var VisualizerUI = (function($, window, undefined) {
2284 2368 on('annotationIsAvailable', annotationIsAvailable).
2285 2369 on('messages', displayMessages).
2286 2370 on('displaySpanComment', displaySpanComment).
  2371 + on('displayRelationsComments', displayRelationsComments).
2287 2372 on('displayArcComment', displayArcComment).
2288 2373 on('displaySentComment', displaySentComment).
2289 2374 on('docChanged', onDocChanged).
... ...
diff.xhtml
... ... @@ -143,6 +143,7 @@
143 143 <div id="messages" class="messages"/>
144 144 <div id="pulluptrigger"/>
145 145 <div id="commentpopup"/>
  146 + <div id="relationspopups"/>
146 147 <div id="header" class="ui-widget">
147 148 <div id="mainHeader" class="ui-widget-header">
148 149 <div id="mainlogo" class="logo unselectable">brat</div>
... ...
index.xhtml
... ... @@ -105,6 +105,7 @@
105 105 <div id="messages" class="messages"/>
106 106 <div id="pulluptrigger"/>
107 107 <div id="commentpopup"/>
  108 + <div id="relationspopups"/>
108 109 <div id="header" class="ui-widget">
109 110 <div id="mainHeader" class="ui-widget-header">
110 111 <div id="mainlogo" class="logo unselectable">brat</div>
... ...
offline.xhtml
... ... @@ -48,6 +48,7 @@
48 48 <img id="spinner" src="static/img/spinner.gif"/>
49 49 <div id="messages"/>
50 50 <div id="commentpopup"/>
  51 + <div id="relationspopups"/>
51 52 <div id="header" class="ui-widget">
52 53 <div id="mainHeader" class="ui-widget-header">
53 54 <div id="mainlogo" class="logo unselectable">brat</div>
... ...
server/src/annotation.py
... ... @@ -756,18 +756,22 @@ class Annotations(object):
756 756 except ValueError:
757 757 raise IdedAnnotationLineSyntaxError(id, self.ann_line, self.ann_line_num+1, input_file_path)
758 758  
759   - if len(args) != 2:
760   - Messager.error('Error parsing relation: must have exactly two arguments')
  759 + if len(args) < 2:
  760 + Messager.error('Error parsing relation: must be Arg1 Arg2 (optional)Facet')
761 761 raise IdedAnnotationLineSyntaxError(id, self.ann_line, self.ann_line_num+1, input_file_path)
762 762  
  763 + facet = "none"
  764 + if len(args) == 3:
  765 + facet = args[2][0]
  766 +
763 767 if args[0][0] == args[1][0]:
764   - Messager.error('Error parsing relation: arguments must not be identical')
  768 + Messager.error('Error parsing relation: related entities must not be identical')
765 769 raise IdedAnnotationLineSyntaxError(id, self.ann_line, self.ann_line_num+1, input_file_path)
766 770  
767 771 return BinaryRelationAnnotation(id, type,
768 772 args[0][0], args[0][1],
769 773 args[1][0], args[1][1],
770   - data_tail, source_id=input_file_path)
  774 + data_tail, facet, source_id=input_file_path)
771 775  
772 776 def _parse_equiv_annotation(self, dummy, data, data_tail, input_file_path):
773 777 # NOTE: first dummy argument to have a uniform signature with other
... ... @@ -1541,25 +1545,27 @@ class BinaryRelationAnnotation(IdedAnnotation):
1541 1545  
1542 1546 Represented in standoff as
1543 1547  
1544   - ID\tTYPE ARG1:ID1 ARG2:ID2
  1548 + ID\tTYPE ARG1:ID1 ARG2:ID2 Facet(optional)
1545 1549  
1546 1550 Where ARG1 and ARG2 are arbitrary (but not identical) labels.
1547 1551 """
1548   - def __init__(self, id, type, arg1l, arg1, arg2l, arg2, tail, source_id=None):
  1552 + def __init__(self, id, type, arg1l, arg1, arg2l, arg2, tail, facet="none", source_id=None):
1549 1553 IdedAnnotation.__init__(self, id, type, tail, source_id=source_id)
1550 1554 self.arg1l = arg1l
1551 1555 self.arg1 = arg1
1552 1556 self.arg2l = arg2l
1553 1557 self.arg2 = arg2
  1558 + self.facet = facet
1554 1559  
1555 1560 def __str__(self):
1556   - return u'%s\t%s %s:%s %s:%s%s' % (
  1561 + return u'%s\t%s %s:%s %s:%s %s%s' % (
1557 1562 self.id,
1558 1563 self.type,
1559 1564 self.arg1l,
1560 1565 self.arg1,
1561 1566 self.arg2l,
1562 1567 self.arg2,
  1568 + self.facet,
1563 1569 self.tail
1564 1570 )
1565 1571  
... ...
server/src/document.py
... ... @@ -684,7 +684,7 @@ def _enrich_json_with_data(j_dic, ann_obj):
684 684 j_dic['relations'].append(
685 685 [unicode(rel_ann.id), unicode(rel_ann.type),
686 686 [(rel_ann.arg1l, rel_ann.arg1),
687   - (rel_ann.arg2l, rel_ann.arg2)]]
  687 + (rel_ann.arg2l, rel_ann.arg2)], rel_ann.facet]
688 688 )
689 689  
690 690 for tb_ann in ann_obj.get_textbounds():
... ...
style-vis.css
... ... @@ -393,6 +393,28 @@ fieldset legend {
393 393 border-radius: 3px;
394 394 max-width: 80%;
395 395 }
  396 +#relationpopup {
  397 + font-family: 'Liberation Sans', Verdana, Arial, Helvetica, sans-serif;
  398 + position: fixed;
  399 + top: 0;
  400 + left: 0;
  401 + opacity: 0.95;
  402 + padding: 10px;
  403 + display: none;
  404 + border: 1px outset #000000;
  405 + background-color: #f5f5f9;
  406 + /* background-color: #d7e7ee; */
  407 + /* background-color: #eeeeee; */
  408 + color: #000000;
  409 + z-index: 20;
  410 + -moz-box-shadow: 5px 5px 5px #aaaaaa;
  411 + -webkit-box-shadow: 5px 5px 5px #aaaaaa;
  412 + box-shadow: 5px 5px 5px #aaaaaa;
  413 + -moz-border-radius: 3px;
  414 + -webkit-border-radius: 3px;
  415 + border-radius: 3px;
  416 + max-width: 80%;
  417 +}
396 418 #more_info_readme {
397 419 height: 350px;
398 420 }
... ...