2020年9月27日

简单的draw.io嵌入演练

您可以将draw.io作为应用程序嵌入另一个应用程序中,在该应用程序中将图表数据存储在主机应用程序中。一个基本的示例运行大约需要15分钟。

以一个示例Stack Overflow页面作为模板,我们创建了自己的问题的稍微改动的版本。双击该图以在新窗口中打开diagrams.net,进行一些图编辑,然后单击“ 保存”将更改后的图保存回该页面。

您可以重复此过程以在以后继续编辑图。让我们看一下该过程的流程和页面上允许发生这种情况的代码。如果您查看页面源,则会在第1695行看到:

<img class="drawio" style="cursor:default;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhE....

图像本身作为base64编码的dataURI放置在页面中。我们这样做是因为在此示例中没有实际的后端(刷新后您将丢失所做的更改),我们无处可写图像来保留它。

图表数据本身嵌入在PNG的压缩文本部分中。当您双击图像时,我们打开一个新窗口,并在该窗口中以嵌入式模式加载diagrams.net:

<script>
  // Edits an image with drawio class on double click
  document.addEventListener('dblclick', function(evt)
  {
    var url = 'https://embed.diagrams.net/?embed=1&ui=atlas&spin=1&modified=unsavedChanges&proto=json';
    var source = evt.srcElement || evt.target;

    if (source.nodeName == 'IMG' && source.className == 'drawio')
    {
      if (source.drawIoWindow == null || source.drawIoWindow.closed)
      {
        // Implements protocol for loading and exporting with embedded XML
        var receive = function(evt)
        {
          if (evt.data.length > 0 && evt.source == source.drawIoWindow)
          {
            var msg = JSON.parse(evt.data);

            // Received if the editor is ready
            if (msg.event == 'init')
            {
              // Sends the data URI with embedded XML to editor
              source.drawIoWindow.postMessage(JSON.stringify
                {action: 'load', xmlpng: source.getAttribute('src')}), '*');
            }
            // Received if the user clicks save
            else if (msg.event == 'save')
            {
              // Sends a request to export the diagram as XML with embedded PNG
              source.drawIoWindow.postMessage(JSON.stringify(
                {action: 'export', format: 'xmlpng', spinKey: 'saving'}), '*');
            }
            // Received if the export request was processed
            else if (msg.event == 'export')
            {
              // Updates the data URI of the image
              source.setAttribute('src', msg.data);
            }

            // Received if the user clicks exit or after export
            if (msg.event == 'exit' || msg.event == 'export')
            {
              // Closes the editor
              window.removeEventListener('message', receive);
              source.drawIoWindow.close();
              source.drawIoWindow = null;
            }
          }
        };

        // Opens the editor
        window.addEventListener('message', receive);
        source.drawIoWindow = window.open(url);
      }
      else
      {
        // Shows existing editor window
        source.drawIoWindow.focus();
      }
    }
  });
</script>

embed=1URL参数告诉diagrams.net在嵌入模式和经营protocol=json手段,我们正在使用的消息传递的JSON协议(总是使用这种模式现在)。然后,窗口用于postMessage通过其通信图数据。请注意,您可以在iFrame中打开而不是在新窗口中打开,这可能会使用户的流程更清晰。在这种情况下,您可以在函数的开头创建一个iFrame:

var iframe = document.createElement('iframe');
iframe.setAttribute('frameborder', '0');

var close = function()
{
    window.removeEventListener('message', receive);
    document.body.removeChild(iframe);
};

开始侦听消息后,将iFrame附加到函数末尾的窗口中:

window.addEventListener('message', receive);
iframe.setAttribute('src', editor);
document.body.appendChild(iframe);

您可能还希望通过CSS使iFrame完全覆盖初始页面:

iframe {
        border:0;
        position:fixed;
        top:0;
        left:0;
        right:0;
        bottom:0;
        width:100%;
        height:100%
    }

当diagrams.net应用程序加载到新窗口/ iFrame中时,它只是静态应用程序,没有数据。在收到来自diagrams.net的“ init”消息告诉我们数据准备就绪后,我们使用消息传递协议将数据加载到diagrams.net。

时序图示例

然后,在编辑器中编辑该图,完成后单击“ 保存”。保存后的其他消息是为请求其他格式提供粒度,在这种情况下,是通过Export要求PNG + XML格式。在我们的情况下,导出完成后我们也退出编辑器,但是您可以将其保持打开状态,并等待用户明确退出编辑器再关闭它。

XML嵌入的PNG作为base64 dataURI被保存回src图像属性的顶部,这导致页面被新图像更新。

最后,区分静态diagrams.net应用程序和嵌入式模式下的数据流非常重要。diagrams.net是作为静态应用程序加载到diagrams.net窗口中的,但是关系图数据是完全在客户端之间在窗口之间传递的,它永远不会发送回来或源于diagrams.net应用程序服务器。这意味着您可以控制和存储数据,并且仅使用diagrams.net在该数据上提供图表功能。