PlantUML

PlantUML is a server which takes PlantUML text (see below) and converts it to a diagram, which can be saved as PNG or SVG. Full details of the server and the syntax can be found at https://plantuml.com/

I have installed it locally on pi1, so it can be accessed at http://pi1.brusch.co.uk:8778/plantuml/.

VS Code

Using the jebbs.plantuml extension, diagrams can be edited in VSCode and automatically previewed. The extension settings must include the above URL.

Hugo

Given that a PlantUML server is running on pi1 at port 8778, then hugo support has been addded by:

  1. download rawdeflate.js from https://github.com/dankogai/js-deflate into static/js
  2. download the code from below into layouts/shortcodes/plantuml.html, ensuring the URL at line 67 is correct.

PlantUML diagrams can now be added using the escaped <plantuml> tag, eg.

{{< plantuml id="test" >}}
Alice -> Bob : here is my secret
Bob --> Alice : So I see
{{< /plantuml >}}

produces:



What happens on upgrade? Should be OK, but need to check. “/home/baz/WebDev/BaziCloudDocs:/src:rw” shows that the BaziCloudDocs folder is mounted rw into the container as /src. This should mean that static files and layouts are unaffected during upgrades.

plantuml.html

<img id="plantuml-{{ .Get "id" }}"/>
<script src="/js/rawdeflate.js"></script>
<script>
  // Based on https://plantuml.com/code-javascript-asynchronous

  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 '?';
  }

  var deflater = window.SharedWorker && new SharedWorker('/js/rawdeflate.js');
  if (deflater) {
    deflater.port.addEventListener('message', done_deflating, false);
    deflater.port.start();
  } else if (window.Worker) {
    deflater = new Worker('/js/rawdeflate.js');
    deflater.onmessage = done_deflating;
  }

  function done_deflating(e) {
    const img = document.getElementById("plantuml-{{ .Get "id" }}");
    img.src = "http://192.168.182.2:8778/plantuml/img/"+encode64(e.data);
  }

  function compress(s) {
    //UTF8
    s = unescape(encodeURIComponent(s));
  
    if (deflater) {
      if (deflater.port && deflater.port.postMessage) {
        deflater.port.postMessage(s);
      } else {
        deflater.postMessage(s);
      }
    } else {
      setTimeout(function() {
          done_deflating({ data: deflate(s) });
          }, 100);
    }
  }

  compress("{{ .Inner }}")
</script>