From f11960b2d3299be6e7bf94e063715ef78e84b993 Mon Sep 17 00:00:00 2001
From: David Rouquet <david.rouquet@tetras-libre.fr>
Date: Wed, 6 Jan 2021 16:32:05 +0100
Subject: [PATCH] allow svg pan-zoom in notebooks

---
 scripts/unlizeXmlNbSample.ipynb | 292 ++++++++++++++++++--------------
 1 file changed, 163 insertions(+), 129 deletions(-)

diff --git a/scripts/unlizeXmlNbSample.ipynb b/scripts/unlizeXmlNbSample.ipynb
index 5d32deb..a667c54 100644
--- a/scripts/unlizeXmlNbSample.ipynb
+++ b/scripts/unlizeXmlNbSample.ipynb
@@ -1,131 +1,165 @@
 {
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import tempfile\n",
-    "import os\n",
-    "import re\n",
-    "import requests\n",
-    "from subprocess import Popen, PIPE, STDOUT\n",
-    "from IPython.display import SVG, display, HTML"
-   ]
+  "cells": [
+    {
+      "cell_type": "code",
+      "source": [
+        "import tempfile\n",
+        "import os\n",
+        "import re\n",
+        "import requests\n",
+        "from subprocess import Popen, PIPE, STDOUT\n",
+        "from IPython.display import SVG, display, HTML"
+      ],
+      "outputs": [],
+      "execution_count": 1,
+      "metadata": {}
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "def unl2dot(text, path):\n",
+        "    with tempfile.NamedTemporaryFile() as temp:\n",
+        "        out_name = os.path.basename(temp.name)\n",
+        "        out_dir = os.path.dirname(temp.name)\n",
+        "    with tempfile.NamedTemporaryFile(mode=\"w\") as in_file:\n",
+        "        # Remove CRLF and flush output to avoid java errors\n",
+        "        in_file.write(text.replace(\"\\r\\n\", \"\\n\"))\n",
+        "        in_file.flush()\n",
+        "        # Run java parser\n",
+        "        cmd = ['java', '-jar', path,\n",
+        "               '--input-file', in_file.name,\n",
+        "               '--output-Dir', out_dir, '--output-file', out_name,\n",
+        "               '--output-type', 'dot']\n",
+        "        with Popen(cmd, stdout=PIPE, stderr=STDOUT) as p:\n",
+        "            p.wait()\n",
+        "            p.stdout.flush()\n",
+        "            if p.returncode != 0:\n",
+        "                print(\"Error in unl2rdf: \\n\\n\"+p.stdout.read().decode())\n",
+        "                print('UNL;')\n",
+        "                print(text)\n",
+        "    # generate dot output\n",
+        "    fname = '{}/{}.dot'.format(out_dir, out_name)\n",
+        "    cmd = ['dot', '-Tsvg', fname]\n",
+        "    with Popen(cmd, stdout=PIPE, stderr=PIPE) as p:\n",
+        "        p.wait()\n",
+        "        if p.returncode != 0:\n",
+        "            print(\"Error creating svg: \\n\\n\"+p.stderr.read().decode())\n",
+        "            print('UNL:')\n",
+        "            print(text)\n",
+        "            try:\n",
+        "                with open(fname) as f:\n",
+        "                    print('DOT:')\n",
+        "                    print(f.read())\n",
+        "            except FileNotFoundError:\n",
+        "                pass\n",
+        "        else:\n",
+        "            svg = p.stdout.read().decode()\n",
+        "            os.remove(fname)\n",
+        "            return svg\n",
+        "    return \"\"\n",
+        "\n",
+        "def unl2dotWeb(unldata) :\n",
+        "    data={'unl': unldata, 'outputs':['dot', 'svg']}\n",
+        "    try:\n",
+        "        r = requests.post('https://unl.demo.tetras-libre.fr/unl2rdf', data=data)\n",
+        "    except Exception as e:\n",
+        "        return 'Error calling https://unl.demo.tetras-libre.fr/unl2rdf : \"{error}\"'.format(error=e)\n",
+        "    html=r.text\n",
+        "    # On utilise une regex au lieu de parser le html car ce dernier est mal formé\n",
+        "    regex = re.compile('<svg.*svg>',re.MULTILINE|re.DOTALL)\n",
+        "    svg = regex.search(html).group()\n",
+        "    return(svg)\n",
+        "\n",
+        "def insert_in_html_template(svg):\n",
+        "    # We first create the html code for the download link\n",
+        "    b64 = base64.b64encode(svg.encode())\n",
+        "    payload = b64.decode()\n",
+        "    html_download = '<a href=\"data:image/svg+xml;base64,{payload}\" download=\"{filename}\">{title}</a>'\n",
+        "    html_download = html_download.format(payload=payload,title='Télécharger le SVG : clic droit + \"Enregistrer la cible du lien sous...\"',filename=\"unl.svg\")\n",
+        "\n",
+        "    html_template = '''\n",
+        "<body>\n",
+        "<script src=\"https://ariutta.github.io/svg-pan-zoom/dist/svg-pan-zoom.js\"></script>\n",
+        "<div id=\"container\" style=\"width:1030px; height: 570px; border:1px solid black; \">\n",
+        "<svg id=\"graph\" xmlns=\"http://www.w3.org/2000/svg\" style=\"display: inline; width: inherit; min-width: inherit; max-width: inherit; height: inherit; min-height: inherit; max-height: inherit; \" viewBox=\"0 0 900 900\">\n",
+        "##    \n",
+        "</svg>\n",
+        "</div>\n",
+        "    <script>\n",
+        "      // Don't use window.onLoad like this in production, because it can only listen to one function.\n",
+        "      window.onload = function() {\n",
+        "        // Expose to window namespase for testing purposes\n",
+        "        window.zoomGraph = svgPanZoom('#graph', {\n",
+        "          zoomEnabled: true,\n",
+        "          controlIconsEnabled: true,\n",
+        "          fit: true,\n",
+        "          center: true,\n",
+        "          // viewportSelector: document.getElementById('graph').querySelector('#g4') // this option will make library to misbehave. Viewport should have no transform attribute\n",
+        "        });\n",
+        "      };\n",
+        "    </script>\n",
+        "    @@\n",
+        "  </body>\n",
+        "    '''\n",
+        "    new_svg = svg.replace(\"<svg>\",\"\").replace(\"</svg>\",\"\")\n",
+        "    return (html_template.replace(\"##\",new_svg).replace(\"@@\",html_download))\n",
+        "\n",
+        "\n",
+        "def displayUnl(unldata) :\n",
+        "# We generate protoSVG because whent there are several sentences, \n",
+        "# a string composed of several concatenated SVG is produced (not a valid SVG).\n",
+        "# We must then split the string to obtain several valid SVG to display.\n",
+        "    sep = \"[/S]\\n\"\n",
+        "    unldataArray = [x+sep for x in unldata.split(sep)]\n",
+        "    unldataArray.pop()\n",
+        "    for unl in unldataArray :\n",
+        "        regex = re.compile('\\{org:..\\}\\n(.*)\\n{\\/org\\}',re.MULTILINE|re.DOTALL)\n",
+        "        text = regex.search(unl).group(1)\n",
+        "        print(\"\\n\"+text+\"\\n\")\n",
+        "        # Keep one of the two lines below depending if you want to use a local jar or a webservice for unltools\n",
+        "        try:\n",
+        "            svg = unl2dotWeb(unl)\n",
+        "            #svg = unl2dot(unl, \"unl2rdf-app-1.0-SNAPSHOT-jar-with-dependencies.jar\")\n",
+        "            display(HTML(insert_in_html_template(svg)))\n",
+        "            #return(insert_in_html_template(svg))\n",
+        "        except Exception as e :\n",
+        "            print(e)\n",
+        "\n"
+      ],
+      "outputs": [],
+      "execution_count": 1,
+      "metadata": {}
+    }
+  ],
+  "metadata": {
+    "kernelspec": {
+      "display_name": "Python 3",
+      "language": "python",
+      "name": "python3"
+    },
+    "language_info": {
+      "codemirror_mode": {
+        "name": "ipython",
+        "version": 3
+      },
+      "file_extension": ".py",
+      "mimetype": "text/x-python",
+      "name": "python",
+      "nbconvert_exporter": "python",
+      "pygments_lexer": "ipython3",
+      "version": "3.8.3"
+    },
+    "widgets": {
+      "application/vnd.jupyter.widget-state+json": {
+        "state": {},
+        "version_major": 2,
+        "version_minor": 0
+      }
+    },
+    "nteract": {
+      "version": "0.27.0"
+    }
   },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def unl2dot(text, path):\n",
-    "    with tempfile.NamedTemporaryFile() as temp:\n",
-    "        out_name = os.path.basename(temp.name)\n",
-    "        out_dir = os.path.dirname(temp.name)\n",
-    "    with tempfile.NamedTemporaryFile(mode=\"w\") as in_file:\n",
-    "        # Remove CRLF and flush output to avoid java errors\n",
-    "        in_file.write(text.replace(\"\\r\\n\", \"\\n\"))\n",
-    "        in_file.flush()\n",
-    "        # Run java parser\n",
-    "        cmd = ['java', '-jar', path,\n",
-    "               '--input-file', in_file.name,\n",
-    "               '--output-Dir', out_dir, '--output-file', out_name,\n",
-    "               '--output-type', 'dot']\n",
-    "        with Popen(cmd, stdout=PIPE, stderr=STDOUT) as p:\n",
-    "            p.wait()\n",
-    "            p.stdout.flush()\n",
-    "            if p.returncode != 0:\n",
-    "                print(\"Error in unl2rdf: \\n\\n\"+p.stdout.read().decode())\n",
-    "                print('UNL;')\n",
-    "                print(text)\n",
-    "    # generate dot output\n",
-    "    fname = '{}/{}.dot'.format(out_dir, out_name)\n",
-    "    cmd = ['dot', '-Tsvg', fname]\n",
-    "    with Popen(cmd, stdout=PIPE, stderr=PIPE) as p:\n",
-    "        p.wait()\n",
-    "        if p.returncode != 0:\n",
-    "            print(\"Error creating svg: \\n\\n\"+p.stderr.read().decode())\n",
-    "            print('UNL:')\n",
-    "            print(text)\n",
-    "            try:\n",
-    "                with open(fname) as f:\n",
-    "                    print('DOT:')\n",
-    "                    print(f.read())\n",
-    "            except FileNotFoundError:\n",
-    "                pass\n",
-    "        else:\n",
-    "            svg = p.stdout.read().decode()\n",
-    "            os.remove(fname)\n",
-    "            return svg\n",
-    "    return \"\"\n",
-    "\n",
-    "def unl2dotWeb(unldata) :\n",
-    "    data={'unl': unldata, 'outputs':['dot', 'svg']}\n",
-    "    try:\n",
-    "        r = requests.post('https://unl.demo.tetras-libre.fr/unl2rdf', data=data)\n",
-    "    except Exception as e:\n",
-    "        return 'Error calling https://unl.demo.tetras-libre.fr/unl2rdf : \"{error}\"'.format(error=e)\n",
-    "    html=r.text\n",
-    "    # On utilise une regex au lieu de parser le html car ce dernier est mal formé\n",
-    "    regex = re.compile('<svg.*svg>',re.MULTILINE|re.DOTALL)\n",
-    "    svg = regex.search(html).group()\n",
-    "    return(svg)\n",
-    "\n",
-    "def svg_to_fixed_width_html_image(svg, width=\"100%\"):\n",
-    "    html_template='<img width=\"{}\">{}</img>'\n",
-    "    text = html_template.format(width, svg)\n",
-    "    return HTML(text)\n",
-    "\n",
-    "\n",
-    "def displayUnl(unldata) :\n",
-    "# We generate protoSVG because whent there are several sentences, \n",
-    "# a string composed of several concatenated SVG is produced (not a valid SVG).\n",
-    "# We must then split the string to obtain several valid SVG to display.\n",
-    "    sep = \"[/S]\\n\"\n",
-    "    unldataArray = [x+sep for x in unldata.split(sep)]\n",
-    "    unldataArray.pop()\n",
-    "    for unl in unldataArray :\n",
-    "        regex = re.compile('\\{org:..\\}\\n(.*)\\n{\\/org\\}',re.MULTILINE|re.DOTALL)\n",
-    "        text = regex.search(unl).group(1)\n",
-    "        print(\"\\n\"+text+\"\\n\")\n",
-    "        # Keep one of the two lines below depending if you want to use a local jar or a webservice for unltools\n",
-    "        try:\n",
-    "            #svg = unl2dotWeb(unl)\n",
-    "            svg = unl2dot(unl, \"unl2rdf-app-1.0-SNAPSHOT-jar-with-dependencies.jar\")\n",
-    "            display(svg_to_fixed_width_html_image(svg))\n",
-    "        except Exception as e :\n",
-    "            print(e)"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.3"
-  },
-  "widgets": {
-   "application/vnd.jupyter.widget-state+json": {
-    "state": {},
-    "version_major": 2,
-    "version_minor": 0
-   }
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
+  "nbformat": 4,
+  "nbformat_minor": 4
+}
\ No newline at end of file
-- 
GitLab