Relations do not render in Safari for PDF files
**Describe the bug**
Relation annotations do not render in Safari, either during creation (drag/drop) nor after their creation.

**To Reproduce**
Steps to reproduce the behavior:
1. Open PDF editor in Safari
2. Try creating a relation
3. Note that it is possible to create a relation, but it does not show on screen.

**Expected behavior**
Relations should be visible.

**Please complete the following information:**
 - Version and build ID: c2ded0195ea6f1eafb61f79dabc9339e7a7d7632

Upstream issue: https://github.com/paperai/pdfanno/issues/196
diff --git a/inception-pdf-editor/src/main/java/de/tudarmstadt/ukp/inception/pdfeditor/PdfAnnotationEditor.java b/inception-pdf-editor/src/main/java/de/tudarmstadt/ukp/inception/pdfeditor/PdfAnnotationEditor.java
index b3ef8c6ba1..322d6897ca 100644
--- a/inception-pdf-editor/src/main/java/de/tudarmstadt/ukp/inception/pdfeditor/PdfAnnotationEditor.java
+++ b/inception-pdf-editor/src/main/java/de/tudarmstadt/ukp/inception/pdfeditor/PdfAnnotationEditor.java
@@ -17,11 +17,15 @@
  */
 package de.tudarmstadt.ukp.inception.pdfeditor;
 
+import static de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.selectByAddr;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.feedback.IFeedback;
@@ -29,6 +33,7 @@ import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.request.IRequestParameters;
 import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.apache.wicket.util.string.StringValueConversionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -82,33 +87,11 @@ public class PdfAnnotationEditor
             Selection selection = getModelObject().getSelection();
             File pdfFile = documentService.getSourceDocumentFile(getModelObject().getDocument());
             String pdftext = PDFExtractor.processFileToString(pdfFile, false);
-            // if something is selected care for existing selections, else throw them away
-            if (selection.getBegin() != -1 && selection.getEnd() != -1) {
-                // save existing selections before destroying them for rerendering
-                String saveSelections = String.join("",
-                    "var selectedAnnotations = [];",
-                    "pdfanno.contentWindow.annoPage.getAllAnnotations().forEach(function(a) {",
-                    "  if(a.selected) {",
-                    "    selectedAnnotations.push(a.uuid);",
-                    "  }",
-                    "});",
-                    "pdfanno.contentWindow.selectedAnnotations = selectedAnnotations;"
-                );
-                aTarget.appendJavaScript(saveSelections);
-                // rerender existing annotations
-                renderPdfAnnoModel(aTarget, pdftext);
-                // restore selections
-                String restoreSelections = String.join("",
-                    "pdfanno.contentWindow.selectedAnnotations.forEach(function(uuid) {",
-                    "  var annotation = pdfanno.contentWindow.annoPage.findAnnotationById(uuid);",
-                    "  if (annotation !== null) {",
-                    "    annotation.toggleSelect();",
-                    "  }",
-                    "});"
-                );
-                aTarget.appendJavaScript(restoreSelections);
-            } else {
-                renderPdfAnnoModel(aTarget, pdftext);
+            renderPdfAnnoModel(aTarget, pdftext);
+            if (selection.getAnnotation() != null) {
+                aTarget.appendJavaScript("var anno = pdfanno.contentWindow.annoPage.findAnnotationById("
+                    + selection.getAnnotation().toString() + ");"
+                    + "anno && anno.select();");
             }
         }
         catch (IOException e)
@@ -170,46 +153,38 @@ public class PdfAnnotationEditor
         renderPdfAnnoModel(aTarget, new PdfExtractFile(aPdftxt));
     }
 
-    public void createSpanAnnotation(AjaxRequestTarget aTarget, JCas aJCas,
-                                        PdfExtractFile aPdfExtractFile, Offset aOffset)
+    public void createSpanAnnotation(AjaxRequestTarget aTarget, IRequestParameters aParams,
+                                     JCas aJCas, PdfExtractFile aPdfExtractFile)
     {
         try
         {
+            Offset offset = new Offset(aParams);
             Offset docOffset = PdfAnnoRenderer
-                .convertToDocumentOffset(aJCas.getDocumentText(), aPdfExtractFile, aOffset);
+                .convertToDocumentOffset(aJCas.getDocumentText(), aPdfExtractFile, offset);
             if (docOffset != null) {
                 getModelObject().getSelection()
                     .selectSpan(aJCas, docOffset.getBegin(), docOffset.getEnd());
                 getActionHandler().actionCreateOrUpdate(aTarget, aJCas);
                 renderPdfAnnoModel(aTarget, aPdfExtractFile.getPdftxt());
-                // select the annotation where annotation offset overlaps with selection offset
-                String selectAnnotation = String.join("",
-                    "pdfanno.contentWindow.annoPage.getAllAnnotations().forEach(function(a) {",
-                    "  if (a.textRange && a.textRange[0] <= " + aOffset.getEnd(),
-                    " && " + aOffset.getBegin() + " <= a.textRange[1]) {",
-                    "    a.toggleSelect();",
-                    "  }",
-                    "});"
-                );
-                aTarget.appendJavaScript(selectAnnotation);
             } else {
-                handleError("Unable to create annotation: No match was found", aTarget);
+                handleError("Unable to create span annotation: No match was found", aTarget);
             }
         }
         catch (IOException | AnnotationException e)
         {
-            handleError("Unable to create annotation", e, aTarget);
+            handleError("Unable to create span annotation", e, aTarget);
         }
     }
 
     private void selectSpanAnnotation(AjaxRequestTarget aTarget, IRequestParameters aParams,
-                                      JCas aJCas, PdfExtractFile aPdfExtractFile, Offset aOffset)
+                                      JCas aJCas, PdfExtractFile aPdfExtractFile)
     {
         try
         {
             VID paramId = VID.parseOptional(aParams.getParameterValue("id").toString());
+            Offset offset = new Offset(aParams);
             Offset docOffset = PdfAnnoRenderer
-                .convertToDocumentOffset(aJCas.getDocumentText(), aPdfExtractFile, aOffset);
+                .convertToDocumentOffset(aJCas.getDocumentText(), aPdfExtractFile, offset);
             if (docOffset != null) {
                 if (paramId.isSynthetic()) {
                     extensionRegistry.fireAction(getActionHandler(), getModelObject(),
@@ -221,12 +196,52 @@ public class PdfAnnotationEditor
                     getActionHandler().actionSelect(aTarget, aJCas);
                 }
             } else {
-                handleError("Unable to select annotation: No match was found", aTarget);
+                handleError("Unable to select span annotation: No match was found", aTarget);
             }
         }
         catch (AnnotationException | IOException e)
         {
-            handleError("Unable to select annotation", e, aTarget);
+            handleError("Unable to select span annotation", e, aTarget);
+        }
+    }
+
+    private void createRelationAnnotation(AjaxRequestTarget aTarget, IRequestParameters aParams,
+                                          JCas aJCas, PdfExtractFile aPdfExtractFile)
+        throws IOException
+    {
+        try {
+            AnnotationFS originFs = selectByAddr(aJCas,
+                aParams.getParameterValue("origin").toInt());
+            int target = aParams.getParameterValue("target").toInt();
+            if (target == -1) {
+                // if -1 return, relation drawing was not stopped over a target
+                return;
+            }
+            AnnotationFS targetFs = selectByAddr(aJCas,
+                target);
+
+            AnnotatorState state = getModelObject();
+            Selection selection = state.getSelection();
+            selection.selectArc(VID.NONE_ID, originFs, targetFs);
+
+            if (selection.getAnnotation().isNotSet()) {
+                getActionHandler().actionCreateOrUpdate(aTarget, aJCas);
+            }
+        }
+        catch (AnnotationException | CASRuntimeException e)
+        {
+            handleError("Unable to create relation annotation", e, aTarget);
+        }
+        catch (StringValueConversionException e)
+        {
+            handleError("Unable to create relations on recommendations", aTarget);
+        }
+        finally
+        {
+            // workaround to enable further creation of relations in PDFAnno
+            // if existing annotations are not rerendered after an attempt to create a relation.
+            // it can happen that mouse will hang when leaving annotation knob while dragging
+            renderPdfAnnoModel(aTarget, aPdfExtractFile.getPdftxt());
         }
     }
 
@@ -236,16 +251,19 @@ public class PdfAnnotationEditor
         try
         {
             JCas jCas = getJCasProvider().get();
-            final Offset offset = new Offset(aParams);
             PdfExtractFile pdfExtractFile = new PdfExtractFile(aPdftxt);
             String action = aParams.getParameterValue("action").toString();
 
             switch (action)
             {
-            case "createSpan": createSpanAnnotation(aTarget, jCas, pdfExtractFile, offset);
-                               break;
-            case "selectSpan": selectSpanAnnotation(aTarget, aParams, jCas, pdfExtractFile, offset);
-                               break;
+            case "createSpan": createSpanAnnotation(aTarget, aParams, jCas, pdfExtractFile);
+                break;
+            case "selectSpan": selectSpanAnnotation(aTarget, aParams, jCas, pdfExtractFile);
+                break;
+            case "createRelation": createRelationAnnotation(aTarget, aParams, jCas, pdfExtractFile);
+                break;
+            case "selectRelation":
+                break;
             default: handleError("Unkown action: " + action, aTarget);
             }
         }
diff --git a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/relation.js b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/relation.js
index 9a228b2717..a06c9d07ab 100644
--- a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/relation.js
+++ b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/relation.js
@@ -1,5 +1,8 @@
 import * as textInput from '../utils/textInput'
 import RelationAnnotation from '../annotation/relation'
+// BEGIN INCEpTION EXTENSION - #839 - Creation of rleations in PDF editor
+import { scaleDown } from './utils'
+// END INCEpTION EXTENSION
 
 /**
  * Create a new Relation annotation.
@@ -38,3 +41,75 @@ export function createRelation ({ type, anno1, anno2, text, color }) {
 
   return annotation
 }
+
+// BEGIN INCEpTION EXTENSION - #839 - Creation of relations in PDF editor
+window.addEventListener('DOMContentLoaded', () => {
+
+  const $viewer = $('#viewer')
+
+  window.addEventListener('annotationHoverIn', (e) => {
+    hoveredAnnotation = e.detail
+  })
+
+  window.addEventListener('annotationHoverOut', () => {
+    hoveredAnnotation = null
+  })
+
+  $viewer.on('mousedown', '.anno-knob', () => {
+    mousedownFired = true
+    if (hoveredAnnotation) {
+      onAnnotation = true
+      relationAnnotation = new RelationAnnotation()
+      relationAnnotation.rel1Annotation = hoveredAnnotation
+      relationAnnotation.direction = 'relation'
+      relationAnnotation.readOnly = false
+    }
+  })
+
+  $viewer.on('mousemove', (e) => {
+    if (mousedownFired && onAnnotation) {
+      drawing = true
+      let p = scaleDown(getClientXY(e))
+      relationAnnotation.x2 = p.x
+      relationAnnotation.y2 = p.y
+      relationAnnotation.render()
+    }
+  })
+
+  $viewer.on('mouseup', () => {
+    if (mousedownFired && onAnnotation && drawing) {
+      var data = {
+        "action": "createRelation",
+        "origin": relationAnnotation.rel1Annotation.uuid,
+        "target": hoveredAnnotation ? hoveredAnnotation.uuid : -1,
+      }
+      parent.Wicket.Ajax.ajax({
+        "m": "POST",
+        "ep": data,
+        "u": window.apiUrl,
+        "sh": [],
+        "fh": [function () {
+          console.log('Something went wrong on creating new relation for: ' + data)
+        }]
+      });
+    }
+    drawing = false
+    onAnnotation = false
+    mousedownFired = false
+    relationAnnotation = null
+  })
+})
+
+function getClientXY(e) {
+  let rect = document.getElementById('annoLayer').getBoundingClientRect()
+  let x = e.clientX - rect.left
+  let y = e.clientY - rect.top
+  return {x, y}
+}
+
+let relationAnnotation = null
+let hoveredAnnotation = null
+let mousedownFired = false
+let onAnnotation = false
+let drawing = false
+// END INCEpTION EXTENSION
\ No newline at end of file
diff --git a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/span.js b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/span.js
index c1634c3c7f..4cdbf09378 100644
--- a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/span.js
+++ b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/span.js
@@ -274,35 +274,34 @@ window.addEventListener('DOMContentLoaded', () => {
       if (spanAnnotation) {
         spanAnnotation.deselect()
       }
-    }
-    mouseDown = false
 // BEGIN INCEpTION EXTENSION - #838 - Creation of spans in PDF editor
-    if (startPosition !== null && endPosition !== null) {
-      var data = {
-        "action" : "createSpan",
-        "page" : currentPage,
-        "begin": startPosition,
-        "end" : endPosition
+      if (startPosition !== null && endPosition !== null) {
+        var data = {
+          "action": "createSpan",
+          "page": currentPage,
+          "begin": startPosition,
+          "end": endPosition
+        }
+        parent.Wicket.Ajax.ajax({
+          "m": "POST",
+          "ep": data,
+          "u": window.apiUrl,
+          "sh": [function () {
+            // wait a second before destroying selection for better user experience
+            setTimeout(function () {
+              if (spanAnnotation) {
+                spanAnnotation.destroy()
+              }
+            }, 1000)
+          }],
+          "fh": [function () {
+              console.log('Something went wrong on creating new annotation for: ' + data)
+          }]
+        });
       }
-      console.log(endPosition)
-      parent.Wicket.Ajax.ajax({
-        "m" : "POST",
-        "ep" : data,
-        "u" : window.apiUrl,
-        "sh" : [function() {
-          // wait a second before destroying selection for better user experience
-          setTimeout(function() {
-            if (spanAnnotation) {
-              spanAnnotation.destroy()
-            }
-          }, 1000)
-        }],
-        "fh": [function() {
-          console.log('Something went wrong on creating new annotation for: ' + data)
-        }]
-      });
-    }
 // END INCEpTION EXTENSION
+    }
+    mouseDown = false
   })
 
   let otherAnnotationTreating = false
diff --git a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/render/renderRelation.js b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/render/renderRelation.js
index 32b0a80a17..dd7cbd0c4e 100644
--- a/inception-pdf-editor/src/main/js/pdfanno/src/core/src/render/renderRelation.js
+++ b/inception-pdf-editor/src/main/js/pdfanno/src/core/src/render/renderRelation.js
@@ -13,7 +13,15 @@ export function renderRelation (a) {
   a.color = a.color || '#F00'
 
   // Adjust the start/end points.
+// BEGIN INCEpTION EXTENSION - #839 - Creation of relations in PDF editor
+/*
   let theta = Math.atan((a.y1 - a.y2) / (a.x1 - a.x2))
+*/
+  let xDiff = a.x1 - a.x2
+  let yDiff = a.y1 - a.y2
+  // if difference of x and difference of y is both 0 use 0 for atan
+  let theta = Math.atan(xDiff === 0 && yDiff === 0 ? 0 : (yDiff / xDiff))
+// END INCEpTION EXTENSION
   let sign = (a.x1 < a.x2 ? 1 : -1)
   a.x1 += DEFAULT_RADIUS * Math.cos(theta) * sign
   a.x2 -= DEFAULT_RADIUS * Math.cos(theta) * sign
['inception-pdf-editor/src/main/java/de/tudarmstadt/ukp/inception/pdfeditor/PdfAnnotationEditor.java', 'inception-pdf-editor/src/main/js/pdfanno/src/core/src/render/renderRelation.js', 'inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/relation.js', 'inception-pdf-editor/src/main/js/pdfanno/src/core/src/UI/span.js']