PlantUMLサーバとリアルタイム編集ツールの作成

環境

※本環境では、Webサーバ及び、PlantUMLサーバを、ubuntu上のDockerコンテナとして起動しています。

完成イメージ

dockerコンテナでplantuml-serverを起動する

% sudo docker run -d --rm \
         -p 8080:8080 \
         --name plantuml-server \
         plantuml/plantuml-server:jetty

dockerコンテナでWebサーバを起動する

dockerコンテナのnginxのDocumentRoot(/usr/share/nginx/html)を、ホストの ${HOME}/web/ で見えるようにする。

% mkdir ${HOME}/web
% sudo docker run -d --rm \
         --name plantuml-web \
         -p 80:80 \
         -v ${HOME}/web:/usr/share/nginx/html \
         nginx

ツールを配置する

このサイトから、Javascript製の圧縮・解凍ツールを ${HOME}/web 以下にダウンロードする

% cd ${HOME}/web

% wget -O inflate.js \
  http://www33146ue.sakura.ne.jp/staff/iz/amuse/javascript/expert/inflate.txt

% wget -O deflate.js \
  http://www33146ue.sakura.ne.jp/staff/iz/amuse/javascript/expert/deflate.txt

${HOME}/web/ に以下を index.html として作成してアクセスする。http://localhost/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
    <script src="./inflate.js" type="text/javascript"></script>
    <script src="./deflate.js" type="text/javascript"></script>
    <title>PlantUML realtime editor</title>
  </head>
  <body>
    <table>
    <tr><td colspan=2><a href="http://pdf.plantuml.net/PlantUML_Language_Reference_Guide_ja.pdf" target=_>Manual</a></td></tr>
    <tr><td colspan=2>
      <textarea id="inputUrl" cols="80%">http://localhost:8080/svg/Iyp9J4xLjKlAJm80</textarea>
      <input type="submit" name="decode" value="decode" onClick="urlToText()">
      <input type="submit" name="copy" value="copy" onClick="copyBuffer()">
    </td></tr>
    <tr>
      <td>
        <textarea id="editorArea" rows="30" cols="80" onchange="textToUrl(this)" onkeyup="textToUrl(this)"></textarea>
      </td>
      <td>
        <img id="outputArea" src="" />
      </td>
    </tr>
    </table>
    <script>
    function copyBuffer(){
      $("#inputUrl").select();
      document.execCommand('copy');
    }

    // text to url
    function textToUrl(){
      var s = $('#editorArea').val();
      s = encodeURIComponent(s);
      s = unescape(s);
      s = zip_deflate(s, 9);
      s = encode64(s);
      $('#inputUrl').val("http://localhost:8080/svg/" + s);
      $('#outputArea').attr("src", "http://localhost:8080/svg/" + s);
    }

    // url to text
    function urlToText(){
      var s = $('#inputUrl').val();
      a = s.split('/');
      url = a[a.length-1];
      s = decode64(url);
      s = zip_inflate(s);
      s = escape(s);
      s = decodeURIComponent(s);
      $('#editorArea').val(s);
      $('#outputArea').attr("src", "http://localhost:8080/svg/" + url);
    }

    // functions
    //  http://plantuml.com/ja/code-javascript-synchronous

    // encode -------------------------------------------------
    function encode64(data) {
      r = "";
      for (i=0; i<data.length; i+=3) {
        if (i+2==data.length) {
          r +=append3bytes(data.charCodeAt(i), data.charCodeAt(i+1), 0);
        }
        else if (i+1==data.length) {
          r += append3bytes(data.charCodeAt(i), 0, 0);
        }
        else {
          r += append3bytes(data.charCodeAt(i), data.charCodeAt(i+1),
               data.charCodeAt(i+2));
        }
     }
     return r;
    }

    function append3bytes(b1, b2, b3) {
      c1 = b1 >> 2;
      c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
      c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
      c4 = b3 & 0x3F;
      r = "";
      r += encode6bit(c1 & 0x3F);
      r += encode6bit(c2 & 0x3F);
      r += encode6bit(c3 & 0x3F);
      r += encode6bit(c4 & 0x3F);
      return r;
    }

    function encode6bit(b) {
      if (b < 10) {
        return String.fromCharCode(48 + b);
      }
      b -= 10;
      if (b < 26) {
        return String.fromCharCode(65 + b);
      }
      b -= 26;
      if (b < 26) {
        return String.fromCharCode(97 + b);
      }
      b -= 26;
      if (b == 0) {
        return '-';
      }
      if (b == 1) {
        return '_';
      }
      return '?';
    }

    // decode -------------------------------------------------
    function decode64(data) {
      var r = ''
      var i = 0
      for (i = 0; i < data.length; i += 4) {
        var t = extract3bytes(data.substring(i, i + 4))
        r = r + String.fromCharCode(t[0])
        r = r + String.fromCharCode(t[1])
        r = r + String.fromCharCode(t[2])
      }
      return r
    }

    function decode6bit (cc) {
      var c = cc.charCodeAt(0)
      if (cc === '_') return 63
      if (cc === '-') return 62
      if (c >= 97) return c - 61 // - 97 + 26 + 10
      if (c >= 65) return c - 55 // - 65 + 10
      if (c >= 48) return c - 48
      return '?'
    }

    function extract3bytes (data) {
      var c1 = decode6bit(data[0])
      var c2 = decode6bit(data[1])
      var c3 = decode6bit(data[2])
      var c4 = decode6bit(data[3])
      var b1 = c1 << 2 | (c2 >> 4) & 0x3F
      var b2 = (c2 << 4) & 0xF0 | (c3 >> 2) & 0xF
      var b3 = (c3 << 6) & 0xC0 | c4 & 0x3F
      return [b1, b2, b3]
    }
    </script>
  </body>
</html>

※本例では、URLをlocalhostとしましたが、別PCからアクセスする場合は、index.html内のlocalhostを、修正する必要があります。完成イメージのアニメーションでは、家のUbuntuがインストールされたノートPCのIPアドレス192.168.1.122 となっています。