Open emacsen opened 4 years ago
Lets not allow this issue to die, a new one will be created with the same request in time, like it has already happened with #820 #548 #274
Adding a feature like this would increase the creative freedom of the users. For example, you could create an SVG with Tikz or with Matplotlib, and then use that as a shape of a flowchart in Mermaid. In this way Mermaid would not need to implement the drawing capabilities of Tikz or Matplotlib, because you would draw there, and then use the drawing in Mermaid.
One of the main powers of Mermaid, which is one of the main reasons why some of us even use Mermaid in the first place, is that Mermaid does the layout of shapes in space. Using this definition, "Mermaid does the layout of shapes in space", it would be useful to give custom shapes to Mermaid and have Mermaid then lay them out in space.
This would make Mermaid even more awesome. In general, I appreciate the styling, syntax, and documentation of Mermaid more than PlantUML, but beyond PlantUML's awkward syntax it has wide support for this already. It's not so pretty, but you can easily incorporate "sprites" into your diagrams. It would be really nice if Mermaid also had this feature.
Any update? The basic shapes offered by Mermaid are extremely limited, specifically for flowcharts which can be used for many different applications. If "custom shapes" features is a painful feature to implement, may be enriching Mermaid shapes library based on users' requests could be an simple solution?
I came up with an example, kind of complicated, but it seems to work in the Online Editor/Mermaid Live Editor; since this is the open issue, I'll post it here. References:
Basically, now that I've found a hoster for SVG (svgur.com), I've uploaded an SVG "cloud" vector image, and I'm using it in an <img>
html tag inside a node. This is a screenshot of what I'm seeing in the Online Editor:
Here it should be rendered via Github's Mermaid diagrams - and unfortunately, the https://svgshare.com/i/q2Q.svg here is not visible, and the same problem remains if that link is replaced with the cloud_scalable.svg version I uploaded here (and the same problem occurs if you click on Actions/(Download PNG) in Mermaid Live Editor):
%%{init: {'theme':'base'}}%%
flowchart LR
%% DummyNode("") crashes the parser, must have at least one character
%%DummyNode("A")
subgraph Border
direction LR
M1["Machine 1"]:::wht;
subgraph CloudContainer[ ]
direction LR
%%CloudImgNode("<img class='BgImgClass' src='https://user-images.githubusercontent.com/48317456/216860238-ada65abe-43e7-45ca-8901-60aa95035eb9.svg' /> <div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>")
%% text with <br> does not render with position:absolute
%% use img top and div padding to center text in image
CloudImgNode("<img style='position:absolute;left:0;top:7px;color:#fff;' src='https://svgshare.com/i/q2Q.svg' /> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
end
M2["Machine 2"]:::wht;
M1 --> CloudImgNode;
CloudImgNode --> M2;
end
%% Defining Class Styles
%% background-image:"" passes, but not with any text inside quotes
%% node that classes here get defined with "#graph-div " prepended!
%% however, seemingly <img> and such are included via foreignObject, so cannot refer to these classes
classDef BorderClass fill:#fff,stroke:#fff,stroke-width:4px,color:#fff,stroke-dasharray: 5 5,margin:0,padding:0;
classDef ContainerClass position:relative,padding:0,margin:0,fill:#fff,color:#000,stroke:none;
classDef ImgNodeClass fill:#fff,padding:0,margin:0,stroke:none,margin:0;
classDef wht fill:#fff,color:black,stroke:#000;
%%classDef BgImgClass display:block,position:absolute,left:0,top:0,width:100%;
%%classDef TxtClass display:block,position:absolute,z-index:100,left:0,top:0;
%%classDef InvisibleClass display:none;
%% Custom Styles
%% NOTE: this gets applied to <rect class="basic label-container",
%% not to the sigbling g<g class="label" or the enclosing <g id="flowchart-CloudImgNode-9174"
%% classdef node class; does however apply the class to the enclosing <g id="flowchart-CloudImgNode-9174" element
%%style CloudImgNode fill:#fff,padding:0,margin:0,stroke:none;
%%style CloudImgNode padding:100px,margin:100px;
%%<div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>
%% Assigning Nodes to Classes
class Border BorderClass;
%% Cannot add multiple classes separated with , (end up as single word)
%% or space (parser crashes)
%% but thankfully, multiple commands work: they do append classes
%%class DummyNode BgImgClass;
%%class DummyNode TxtClass;
%%class DummyNode InvisibleClass;
class CloudContainer ContainerClass;
%%class CloudImgNode BgImgClass;
%%class CloudImgNode TxtClass;
%% gets applied to all childer, too!
class CloudImgNode ImgNodeClass;
This should be the rendered .png right from the Mermaid Live Editor - also here the svg is missing:
Note that:
background-image:url("https://some.url.here.com/image.svg")
as a classDef
in Mermaid, otherwise things would have been easierclassDef
to HTML elements written inside a node, possibly because class definitions end up prefixed with #graph-div
in the finally generated HTML- otherwsie things would have been easierAnother thing that would have made things easier:
\
but it didn't work$myvar = "url(\"https://some.url.here.com/image.svg\")"
, - and use it in, say, classDef ImgNodeClass background-image:$myvar,stroke:none;
?Here is the code:
%%{init: {'theme':'base'}}%%
flowchart LR
%% DummyNode("") crashes the parser, must have at least one character
%%DummyNode("A")
subgraph Border
direction LR
M1["Machine 1"]:::wht;
subgraph CloudContainer[ ]
direction LR
%%CloudImgNode("<img class='BgImgClass' src='https://svgshare.com/i/q24.svg' /> <div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>")
%% text with <br> does not render with position:absolute
%% use img top and div padding to center text in image
CloudImgNode("<img style='position:absolute;left:0;top:7px;color:#fff;' src='https://svgshare.com/i/q2Q.svg' /> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
end
M2["Machine 2"]:::wht;
M1 --> CloudImgNode;
CloudImgNode --> M2;
end
%% Defining Class Styles
%% background-image:"" passes, but not with any text inside quotes
%% node that classes here get defined with "#graph-div " prepended!
%% however, seemingly <img> and such are included via foreignObject, so cannot refer to these classes
classDef BorderClass fill:#fff,stroke:#fff,stroke-width:4px,color:#fff,stroke-dasharray: 5 5,margin:0,padding:0;
classDef ContainerClass position:relative,padding:0,margin:0,fill:#fff,color:#000,stroke:none;
classDef ImgNodeClass fill:#fff,padding:0,margin:0,stroke:none,margin:0;
classDef wht fill:#fff,color:black,stroke:#000;
%%classDef BgImgClass display:block,position:absolute,left:0,top:0,width:100%;
%%classDef TxtClass display:block,position:absolute,z-index:100,left:0,top:0;
%%classDef InvisibleClass display:none;
%% Custom Styles
%% NOTE: this gets applied to <rect class="basic label-container",
%% not to the sigbling g<g class="label" or the enclosing <g id="flowchart-CloudImgNode-9174"
%% classdef node class; does however apply the class to the enclosing <g id="flowchart-CloudImgNode-9174" element
%%style CloudImgNode fill:#fff,padding:0,margin:0,stroke:none;
%%style CloudImgNode padding:100px,margin:100px;
%%<div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>
%% Assigning Nodes to Classes
class Border BorderClass;
%% Cannot add multiple classes separated with , (end up as single word)
%% or space (parser crashes)
%% but thankfully, multiple commands work: they do append classes
%%class DummyNode BgImgClass;
%%class DummyNode TxtClass;
%%class DummyNode InvisibleClass;
class CloudContainer ContainerClass;
%%class CloudImgNode BgImgClass;
%%class CloudImgNode TxtClass;
%% gets applied to all childer, too!
class CloudImgNode ImgNodeClass;
Well, in relation to previous post - tried image base64 inline embedding instead (https://www.base64-image.de/); and with that, now it is possible to download a correct PNG from Mermaid Live editor... However, Github will unfortunately not render even this kind of svg in the mermaid diagram code:
%%{init: {'theme':'base'}}%%
flowchart LR
%% DummyNode("") crashes the parser, must have at least one character
%%DummyNode("A")
subgraph Border
direction LR
M1["Machine 1"]:::wht;
subgraph CloudContainer[ ]
direction LR
%%CloudImgNode("<img class='BgImgClass' src='https://svgshare.com/i/q24.svg' /> <div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>")
%% text with <br> does not render with position:absolute
%% use img top and div padding to center text in ima
CloudImgNode("<img style='position:absolute;left:0;top:7px;color:#fff;' src=' data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICBpZD0ic3ZnMiIKICAgc29kaXBvZGk6ZG9jbmFtZT0iY2xvdWQuc3ZnIgogICB2aWV3Qm94PSIwIDAgNTY1LjQwOTk1IDMxNi44NDM5OSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjEuMiAoMToxLjErMjAyMjAyMDUwODUyKzBhMDBjZjUzMzkpIgogICB3aWR0aD0iMTAwJSIKICAgaGVpZ2h0PSIxMDAlIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzNCI+CiAgICA8ZmlsdGVyCiAgICAgICBpZD0iZmlsdGVyMzMwMSIKICAgICAgIGlua3NjYXBlOm1lbnU9IkFCQ3MiCiAgICAgICBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiCiAgICAgICB3aWR0aD0iMS4wODAxNTgxIgogICAgICAgeT0iLTAuMDcyOTc0ODY4IgogICAgICAgeD0iLTAuMDQwMDc5MDY4IgogICAgICAgaW5rc2NhcGU6bWVudS10b29sdGlwPSJCdWxnaW5nLCBtYXR0ZSBqZWxseSBjb3ZlcmluZyIKICAgICAgIGhlaWdodD0iMS4xNDU5NDk3IgogICAgICAgaW5rc2NhcGU6bGFiZWw9Ik1hdHRlIGplbGx5Ij4KICAgICAgPGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjMzMDMiCiAgICAgICAgIHJlc3VsdD0icmVzdWx0MCIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIyIgogICAgICAgICBpbj0iU291cmNlQWxwaGEiIC8+CiAgICAgIDxmZUNvbXBvc2l0ZQogICAgICAgICBpZD0iZmVDb21wb3NpdGUzMzA1IgogICAgICAgICBrMz0iMTAiCiAgICAgICAgIGsyPSIxIgogICAgICAgICByZXN1bHQ9InJlc3VsdDMiCiAgICAgICAgIGluPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0iYXJpdGhtZXRpYyIKICAgICAgICAgaW4yPSJyZXN1bHQwIgogICAgICAgICBrMT0iMCIKICAgICAgICAgazQ9IjAiIC8+CiAgICAgIDxmZUNvbXBvc2l0ZQogICAgICAgICBpZD0iZmVDb21wb3NpdGUzMzA3IgogICAgICAgICBpbjI9InJlc3VsdDMiCiAgICAgICAgIHJlc3VsdD0iZmJTb3VyY2VHcmFwaGljIgogICAgICAgICBpbj0icmVzdWx0MyIKICAgICAgICAgb3BlcmF0b3I9ImluIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDM3MjIiCiAgICAgICAgIGluPSJmYlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIHZhbHVlcz0iMSAwIDAgMCAwIDAgMSAwIDAgMCAwIDAgMSAwIDAgMCAwIDAgMC44NSAwIgogICAgICAgICByZXN1bHQ9InJlc3VsdDAiIC8+CiAgICAgIDxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXIzNzI0IgogICAgICAgICBzdGREZXZpYXRpb249IjciCiAgICAgICAgIGluPSJmYlNvdXJjZUdyYXBoaWNBbHBoYSIgLz4KICAgICAgPGZlU3BlY3VsYXJMaWdodGluZwogICAgICAgICBpZD0iZmVTcGVjdWxhckxpZ2h0aW5nMzcyNiIKICAgICAgICAgcmVzdWx0PSJyZXN1bHQ0IgogICAgICAgICBzcGVjdWxhckNvbnN0YW50PSIwLjg5OTk5OTk4IgogICAgICAgICBzcGVjdWxhckV4cG9uZW50PSIyNSIKICAgICAgICAgc3VyZmFjZVNjYWxlPSI1Ij4KICAgICAgICA8ZmVEaXN0YW50TGlnaHQKICAgICAgICAgICBpZD0iZmVEaXN0YW50TGlnaHQzNzI4IgogICAgICAgICAgIGVsZXZhdGlvbj0iNjAiCiAgICAgICAgICAgYXppbXV0aD0iMjI1IiAvPgogICAgICA8L2ZlU3BlY3VsYXJMaWdodGluZz4KICAgICAgPGZlQ29tcG9zaXRlCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTM3MzAiCiAgICAgICAgIG9wZXJhdG9yPSJhdG9wIgogICAgICAgICBpbjI9InJlc3VsdDAiIC8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI4IgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3MTIiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTp6b29tPSIwLjciCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjAiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6Y3g9IjIyNS43MTQyOSIKICAgICBpbmtzY2FwZTpjeT0iMjYwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM2NiIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIwIgogICAgIGZpdC1tYXJnaW4tdG9wPSI0IgogICAgIGZpdC1tYXJnaW4tbGVmdD0iNCIKICAgICBmaXQtbWFyZ2luLXJpZ2h0PSI0IgogICAgIGZpdC1tYXJnaW4tYm90dG9tPSI0IiAvPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC03MC4xNTI3LC0zMTMuOTM5KSI+CiAgICA8ZwogICAgICAgaWQ9ImcyMzkzIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMjAyIgogICAgICAgICBkPSJtIDQwMC4yMiwzMjAuOTQgYyAtNDkuMDE4LDAgLTkwLjYzOSwzMS4xMjYgLTEwNS42Niw3NC40MDYgLTEyLjc4MiwtNS42MzQ3IC0yNy4wMSwtOC42ODc1IC00MS43MTksLTguNjg3NSAtNTIuODYyLDAgLTk1LjY4OCwzOC45OTcgLTk1LjY4OCw4Ny4xMjUgMCwwLjU4NDkyIDAuMDE4NywxLjE2NzggMC4wMzEyLDEuNzUgLTIuMzY4MiwtMC4yMTg2MiAtNC43NTgyLC0wLjMxMjUgLTcuMTg3NSwtMC4zMTI1IC00MC4yMzgsMCAtNzIuODQ0LDMwLjY5MiAtNzIuODQ0LDY4LjU2MiAwLDM3Ljg3MSAzMi42MDYsNjguNTk0IDcyLjg0NCw2OC41OTQgMjAuMTAzLDAgMzguMzE4LC03LjY3MTIgNTEuNSwtMjAuMDYyIDIwLjE2NCwxMy45NTkgNTEuMDQsMjIuOTA2IDg1LjY1NiwyMi45MDYgMzcuMzg0LDAgNzAuMzczLC0xMC40MjcgOTAuMjUsLTI2LjM0NCAxNC4wNTQsMjAuOTM4IDM5LjM5NCwzNC45MDYgNjguMzEyLDM0LjkwNiAzMi40ODQsMCA2MC40MDcsLTE3LjY0IDcyLjkzOCwtNDIuOTY5IDYxLjIxMywtMi42MTA5IDEwOS45MSwtNDYuMzI3IDEwOS45MSwtOTkuODc1IDAsLTU1LjIyOCAtNTEuODEyLC0xMDAgLTExNS43MiwtMTAwIC00LjM0OSwwIC04LjYxOTMsMC4yMjExMyAtMTIuODQ0LDAuNjI1IC0xOC4zNjQsLTM1Ljk1NiAtNTYuMTM5LC02MC42MjUgLTk5Ljc4MSwtNjAuNjI1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjk5OSIKICAgICAgICAgc29kaXBvZGk6cng9Ijk1LjcxNDI4NyIKICAgICAgICAgc29kaXBvZGk6cnk9Ijg3LjE0Mjg2IgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHgiCiAgICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjQ3My43OTIxOCIKICAgICAgICAgc29kaXBvZGk6Y3g9IjI1Mi44NTc0MiIKICAgICAgICAgc29kaXBvZGk6ZW5kPSI1Ljc4ODg3NyIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjIuOTMyMTI1IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJtIDE1OS4yMzUyOCw0OTEuOTEyNTkgYSA5NS43MTQyODcsODcuMTQyODYgMCAwIDEgNjAuNjMyMjMsLTk5LjkyMzQ4IDk1LjcxNDI4Nyw4Ny4xNDI4NiAwIDAgMSAxMTcuMjQ2OTIsNDAuNDYwNSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMDAzIgogICAgICAgICBzb2RpcG9kaTpyeD0iMTEwIgogICAgICAgICBzb2RpcG9kaTpyeT0iNjEuNDI4NTciCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNTUzLjc5MDc3IgogICAgICAgICBzb2RpcG9kaTpjeD0iMjg3LjE0Mjg1IgogICAgICAgICBzb2RpcG9kaTplbmQ9IjMuMDk1MzIyNiIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjAiCiAgICAgICAgIHNvZGlwb2RpOmFyYy10eXBlPSJhcmMiCiAgICAgICAgIGQ9Ik0gMzk3LjE0Mjg1LDU1My43OTA3NyBBIDExMCw2MS40Mjg1NyAwIDAgMSAyODkuNjg3NDgsNjE1LjIwMjkgMTEwLDYxLjQyODU3IDAgMCAxIDE3Ny4yNjA1OCw1NTYuNjMyMDYiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjk5NyIKICAgICAgICAgc29kaXBvZGk6cng9IjcyLjg1NzE0IgogICAgICAgICBzb2RpcG9kaTpyeT0iNjguNTcxNDI2IgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHgiCiAgICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjU0My43OTA3NyIKICAgICAgICAgc29kaXBvZGk6Y3g9IjE1MCIKICAgICAgICAgc29kaXBvZGk6ZW5kPSI1LjI3NTcwNTciCiAgICAgICAgIHNvZGlwb2RpOnN0YXJ0PSI2LjA4ODY2MiIKICAgICAgICAgc29kaXBvZGk6YXJjLXR5cGU9ImFyYyIKICAgICAgICAgZD0ibSAyMjEuNDgzMDUsNTMwLjUzNTk5IGEgNzIuODU3MTQsNjguNTcxNDI2IDAgMCAxIC00My4yNjEzNyw3Ni40NzI4NCA3Mi44NTcxNCw2OC41NzE0MjYgMCAwIDEgLTg4LjMxMjA0NCwtMjQuNDQzMDYgNzIuODU3MTQsNjguNTcxNDI2IDAgMCAxIDcuNjExMDcyLC04Ni4zNDAxNSA3Mi44NTcxNCw2OC41NzE0MjYgMCAwIDEgOTEuMzg0NTIyLC0xMC40MTEyMSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMDA1IgogICAgICAgICBzb2RpcG9kaTpyeD0iODAiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSI3Mi44NTcxNCIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MXB4IgogICAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICAgIHNvZGlwb2RpOm9wZW49InRydWUiCiAgICAgICAgIHNvZGlwb2RpOmN5PSI1NTAuOTMzNTkiCiAgICAgICAgIHNvZGlwb2RpOmN4PSI0NDUuNzE0MjkiCiAgICAgICAgIHNvZGlwb2RpOmVuZD0iNC4xNjQ4NjQ3IgogICAgICAgICBzb2RpcG9kaTpzdGFydD0iNS44Mzk2NDQ3IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJNIDUxNy45NzMzMyw1MTkuNjY3NjcgQSA4MCw3Mi44NTcxNCAwIDAgMSA0ODIuNTI4OTcsNjE1LjYxNzkgODAsNzIuODU3MTQgMCAwIDEgMzc2LjAwNjgzLDU4Ni42ODI2OSA4MCw3Mi44NTcxNCAwIDAgMSA0MDQuMDY4MjksNDg4LjcyNzAxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0icGF0aDMwMDciCiAgICAgICAgIHNvZGlwb2RpOnJ4PSIxMTEuNjUzOTIiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSIxMTAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNDMwLjkzMzYyIgogICAgICAgICBzb2RpcG9kaTpjeD0iNDAwLjIyNjM1IgogICAgICAgICBzb2RpcG9kaTplbmQ9IjYuMTE0MDA2OSIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjIuNzgxNjI2OSIKICAgICAgICAgc29kaXBvZGk6YXJjLXR5cGU9ImFyYyIKICAgICAgICAgZD0ibSAyOTUuNzI4NDUsNDY5LjY4MDI2IGEgMTExLjY1MzkyLDExMCAwIDAgMSAyMi44NjQ5OCwtMTEzLjc5MzQ4IDExMS42NTM5MiwxMTAgMCAwIDEgMTEzLjY0ODgyLC0zMC4zMzQwMSAxMTEuNjUzOTIsMTEwIDAgMCAxIDc4LjA0Mzk5LDg2Ljg1OTg3IiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0icGF0aDMwMDkiCiAgICAgICAgIHNvZGlwb2RpOnJ4PSIxMTUuNzE0MjkiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSIxMDAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNDgwLjkzMzYyIgogICAgICAgICBzb2RpcG9kaTpjeD0iNTEyLjg1NzEyIgogICAgICAgICBzb2RpcG9kaTplbmQ9IjIuMTU1NzExMiIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjMuODQ1MTc1IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJNIDQyNC42MjE1Niw0MTYuMjM4MjggQSAxMTUuNzE0MjksMTAwIDAgMCAxIDU4NC4xNzEsNDAyLjE4MTkxIDExNS43MTQyOSwxMDAgMCAwIDEgNjA2LjczMjk2LDUzOS40MDA0MiAxMTUuNzE0MjksMTAwIDAgMCAxIDQ0OC45Njc5Nyw1NjQuMzA5NTMiIC8+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTIzIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yaz4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL3B1YmxpY2RvbWFpbi96ZXJvLzEuMC8iIC8+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudAogICAgICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vb3BlbmNsaXBhcnQub3JnLyI+CiAgICAgICAgICAgIDxkYzp0aXRsZT5PcGVuY2xpcGFydDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICA8L2NjOldvcms+CiAgICAgIDxjYzpMaWNlbnNlCiAgICAgICAgIHJkZjphYm91dD0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvcHVibGljZG9tYWluLyI+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI1JlcHJvZHVjdGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjRGlzdHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNEZXJpdmF0aXZlV29ya3MiIC8+CiAgICAgIDwvY2M6TGljZW5zZT4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K' /> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
end
M2["Machine 2"]:::wht;
M1 --> CloudImgNode;
CloudImgNode --> M2;
end
%% Defining Class Styles
%% background-image:"" passes, but not with any text inside quotes
%% node that classes here get defined with "#graph-div " prepended!
%% however, seemingly <img> and such are included via foreignObject, so cannot refer to these classes
classDef BorderClass fill:#fff,stroke:#fff,stroke-width:4px,color:#fff,stroke-dasharray: 5 5,margin:0,padding:0;
classDef ContainerClass position:relative,padding:0,margin:0,fill:#fff,color:#000,stroke:none;
classDef ImgNodeClass fill:#fff,padding:0,margin:0,stroke:none,margin:0;
classDef wht fill:#fff,color:black,stroke:#000;
%%classDef BgImgClass display:block,position:absolute,left:0,top:0,width:100%;
%%classDef TxtClass display:block,position:absolute,z-index:100,left:0,top:0;
%%classDef InvisibleClass display:none;
%% Custom Styles
%% NOTE: this gets applied to <rect class="basic label-container",
%% not to the sigbling g<g class="label" or the enclosing <g id="flowchart-CloudImgNode-9174"
%% classdef node class; does however apply the class to the enclosing <g id="flowchart-CloudImgNode-9174" element
%%style CloudImgNode fill:#fff,padding:0,margin:0,stroke:none;
%%style CloudImgNode padding:100px,margin:100px;
%%<div class='TxtClass'>Subnet <br /> 10.1.1.0/24</div>
%% Assigning Nodes to Classes
class Border BorderClass;
%% Cannot add multiple classes separated with , (end up as single word)
%% or space (parser crashes)
%% but thankfully, multiple commands work: they do append classes
%%class DummyNode BgImgClass;
%%class DummyNode TxtClass;
%%class DummyNode InvisibleClass;
class CloudContainer ContainerClass;
%%class CloudImgNode BgImgClass;
%%class CloudImgNode TxtClass;
%% gets applied to all childer, too!
class CloudImgNode ImgNodeClass;
However, the PNG export from the Mermaid Live editor works - unfortunately, Github refuses to render the Markdown link from Mermaid Live editor works (probably because it is too long?):
... and Github even refuses to parse the standalone PNG link as an URL.
In any case, I'll just post the changed line, just to point out how less readable everything becomes with each approach:
CloudImgNode("<img style='position:absolute;left:0;top:7px;color:#fff;' src=' data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICBpZD0ic3ZnMiIKICAgc29kaXBvZGk6ZG9jbmFtZT0iY2xvdWQuc3ZnIgogICB2aWV3Qm94PSIwIDAgNTY1LjQwOTk1IDMxNi44NDM5OSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjEuMiAoMToxLjErMjAyMjAyMDUwODUyKzBhMDBjZjUzMzkpIgogICB3aWR0aD0iMTAwJSIKICAgaGVpZ2h0PSIxMDAlIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzNCI+CiAgICA8ZmlsdGVyCiAgICAgICBpZD0iZmlsdGVyMzMwMSIKICAgICAgIGlua3NjYXBlOm1lbnU9IkFCQ3MiCiAgICAgICBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiCiAgICAgICB3aWR0aD0iMS4wODAxNTgxIgogICAgICAgeT0iLTAuMDcyOTc0ODY4IgogICAgICAgeD0iLTAuMDQwMDc5MDY4IgogICAgICAgaW5rc2NhcGU6bWVudS10b29sdGlwPSJCdWxnaW5nLCBtYXR0ZSBqZWxseSBjb3ZlcmluZyIKICAgICAgIGhlaWdodD0iMS4xNDU5NDk3IgogICAgICAgaW5rc2NhcGU6bGFiZWw9Ik1hdHRlIGplbGx5Ij4KICAgICAgPGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjMzMDMiCiAgICAgICAgIHJlc3VsdD0icmVzdWx0MCIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIyIgogICAgICAgICBpbj0iU291cmNlQWxwaGEiIC8+CiAgICAgIDxmZUNvbXBvc2l0ZQogICAgICAgICBpZD0iZmVDb21wb3NpdGUzMzA1IgogICAgICAgICBrMz0iMTAiCiAgICAgICAgIGsyPSIxIgogICAgICAgICByZXN1bHQ9InJlc3VsdDMiCiAgICAgICAgIGluPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0iYXJpdGhtZXRpYyIKICAgICAgICAgaW4yPSJyZXN1bHQwIgogICAgICAgICBrMT0iMCIKICAgICAgICAgazQ9IjAiIC8+CiAgICAgIDxmZUNvbXBvc2l0ZQogICAgICAgICBpZD0iZmVDb21wb3NpdGUzMzA3IgogICAgICAgICBpbjI9InJlc3VsdDMiCiAgICAgICAgIHJlc3VsdD0iZmJTb3VyY2VHcmFwaGljIgogICAgICAgICBpbj0icmVzdWx0MyIKICAgICAgICAgb3BlcmF0b3I9ImluIiAvPgogICAgICA8ZmVDb2xvck1hdHJpeAogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDM3MjIiCiAgICAgICAgIGluPSJmYlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIHZhbHVlcz0iMSAwIDAgMCAwIDAgMSAwIDAgMCAwIDAgMSAwIDAgMCAwIDAgMC44NSAwIgogICAgICAgICByZXN1bHQ9InJlc3VsdDAiIC8+CiAgICAgIDxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXIzNzI0IgogICAgICAgICBzdGREZXZpYXRpb249IjciCiAgICAgICAgIGluPSJmYlNvdXJjZUdyYXBoaWNBbHBoYSIgLz4KICAgICAgPGZlU3BlY3VsYXJMaWdodGluZwogICAgICAgICBpZD0iZmVTcGVjdWxhckxpZ2h0aW5nMzcyNiIKICAgICAgICAgcmVzdWx0PSJyZXN1bHQ0IgogICAgICAgICBzcGVjdWxhckNvbnN0YW50PSIwLjg5OTk5OTk4IgogICAgICAgICBzcGVjdWxhckV4cG9uZW50PSIyNSIKICAgICAgICAgc3VyZmFjZVNjYWxlPSI1Ij4KICAgICAgICA8ZmVEaXN0YW50TGlnaHQKICAgICAgICAgICBpZD0iZmVEaXN0YW50TGlnaHQzNzI4IgogICAgICAgICAgIGVsZXZhdGlvbj0iNjAiCiAgICAgICAgICAgYXppbXV0aD0iMjI1IiAvPgogICAgICA8L2ZlU3BlY3VsYXJMaWdodGluZz4KICAgICAgPGZlQ29tcG9zaXRlCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTM3MzAiCiAgICAgICAgIG9wZXJhdG9yPSJhdG9wIgogICAgICAgICBpbjI9InJlc3VsdDAiIC8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI4IgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3MTIiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTp6b29tPSIwLjciCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjAiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6Y3g9IjIyNS43MTQyOSIKICAgICBpbmtzY2FwZTpjeT0iMjYwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM2NiIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIwIgogICAgIGZpdC1tYXJnaW4tdG9wPSI0IgogICAgIGZpdC1tYXJnaW4tbGVmdD0iNCIKICAgICBmaXQtbWFyZ2luLXJpZ2h0PSI0IgogICAgIGZpdC1tYXJnaW4tYm90dG9tPSI0IiAvPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC03MC4xNTI3LC0zMTMuOTM5KSI+CiAgICA8ZwogICAgICAgaWQ9ImcyMzkzIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMjAyIgogICAgICAgICBkPSJtIDQwMC4yMiwzMjAuOTQgYyAtNDkuMDE4LDAgLTkwLjYzOSwzMS4xMjYgLTEwNS42Niw3NC40MDYgLTEyLjc4MiwtNS42MzQ3IC0yNy4wMSwtOC42ODc1IC00MS43MTksLTguNjg3NSAtNTIuODYyLDAgLTk1LjY4OCwzOC45OTcgLTk1LjY4OCw4Ny4xMjUgMCwwLjU4NDkyIDAuMDE4NywxLjE2NzggMC4wMzEyLDEuNzUgLTIuMzY4MiwtMC4yMTg2MiAtNC43NTgyLC0wLjMxMjUgLTcuMTg3NSwtMC4zMTI1IC00MC4yMzgsMCAtNzIuODQ0LDMwLjY5MiAtNzIuODQ0LDY4LjU2MiAwLDM3Ljg3MSAzMi42MDYsNjguNTk0IDcyLjg0NCw2OC41OTQgMjAuMTAzLDAgMzguMzE4LC03LjY3MTIgNTEuNSwtMjAuMDYyIDIwLjE2NCwxMy45NTkgNTEuMDQsMjIuOTA2IDg1LjY1NiwyMi45MDYgMzcuMzg0LDAgNzAuMzczLC0xMC40MjcgOTAuMjUsLTI2LjM0NCAxNC4wNTQsMjAuOTM4IDM5LjM5NCwzNC45MDYgNjguMzEyLDM0LjkwNiAzMi40ODQsMCA2MC40MDcsLTE3LjY0IDcyLjkzOCwtNDIuOTY5IDYxLjIxMywtMi42MTA5IDEwOS45MSwtNDYuMzI3IDEwOS45MSwtOTkuODc1IDAsLTU1LjIyOCAtNTEuODEyLC0xMDAgLTExNS43MiwtMTAwIC00LjM0OSwwIC04LjYxOTMsMC4yMjExMyAtMTIuODQ0LDAuNjI1IC0xOC4zNjQsLTM1Ljk1NiAtNTYuMTM5LC02MC42MjUgLTk5Ljc4MSwtNjAuNjI1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjk5OSIKICAgICAgICAgc29kaXBvZGk6cng9Ijk1LjcxNDI4NyIKICAgICAgICAgc29kaXBvZGk6cnk9Ijg3LjE0Mjg2IgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHgiCiAgICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjQ3My43OTIxOCIKICAgICAgICAgc29kaXBvZGk6Y3g9IjI1Mi44NTc0MiIKICAgICAgICAgc29kaXBvZGk6ZW5kPSI1Ljc4ODg3NyIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjIuOTMyMTI1IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJtIDE1OS4yMzUyOCw0OTEuOTEyNTkgYSA5NS43MTQyODcsODcuMTQyODYgMCAwIDEgNjAuNjMyMjMsLTk5LjkyMzQ4IDk1LjcxNDI4Nyw4Ny4xNDI4NiAwIDAgMSAxMTcuMjQ2OTIsNDAuNDYwNSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMDAzIgogICAgICAgICBzb2RpcG9kaTpyeD0iMTEwIgogICAgICAgICBzb2RpcG9kaTpyeT0iNjEuNDI4NTciCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNTUzLjc5MDc3IgogICAgICAgICBzb2RpcG9kaTpjeD0iMjg3LjE0Mjg1IgogICAgICAgICBzb2RpcG9kaTplbmQ9IjMuMDk1MzIyNiIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjAiCiAgICAgICAgIHNvZGlwb2RpOmFyYy10eXBlPSJhcmMiCiAgICAgICAgIGQ9Ik0gMzk3LjE0Mjg1LDU1My43OTA3NyBBIDExMCw2MS40Mjg1NyAwIDAgMSAyODkuNjg3NDgsNjE1LjIwMjkgMTEwLDYxLjQyODU3IDAgMCAxIDE3Ny4yNjA1OCw1NTYuNjMyMDYiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjk5NyIKICAgICAgICAgc29kaXBvZGk6cng9IjcyLjg1NzE0IgogICAgICAgICBzb2RpcG9kaTpyeT0iNjguNTcxNDI2IgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHgiCiAgICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjU0My43OTA3NyIKICAgICAgICAgc29kaXBvZGk6Y3g9IjE1MCIKICAgICAgICAgc29kaXBvZGk6ZW5kPSI1LjI3NTcwNTciCiAgICAgICAgIHNvZGlwb2RpOnN0YXJ0PSI2LjA4ODY2MiIKICAgICAgICAgc29kaXBvZGk6YXJjLXR5cGU9ImFyYyIKICAgICAgICAgZD0ibSAyMjEuNDgzMDUsNTMwLjUzNTk5IGEgNzIuODU3MTQsNjguNTcxNDI2IDAgMCAxIC00My4yNjEzNyw3Ni40NzI4NCA3Mi44NTcxNCw2OC41NzE0MjYgMCAwIDEgLTg4LjMxMjA0NCwtMjQuNDQzMDYgNzIuODU3MTQsNjguNTcxNDI2IDAgMCAxIDcuNjExMDcyLC04Ni4zNDAxNSA3Mi44NTcxNCw2OC41NzE0MjYgMCAwIDEgOTEuMzg0NTIyLC0xMC40MTEyMSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMDA1IgogICAgICAgICBzb2RpcG9kaTpyeD0iODAiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSI3Mi44NTcxNCIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MXB4IgogICAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICAgIHNvZGlwb2RpOm9wZW49InRydWUiCiAgICAgICAgIHNvZGlwb2RpOmN5PSI1NTAuOTMzNTkiCiAgICAgICAgIHNvZGlwb2RpOmN4PSI0NDUuNzE0MjkiCiAgICAgICAgIHNvZGlwb2RpOmVuZD0iNC4xNjQ4NjQ3IgogICAgICAgICBzb2RpcG9kaTpzdGFydD0iNS44Mzk2NDQ3IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJNIDUxNy45NzMzMyw1MTkuNjY3NjcgQSA4MCw3Mi44NTcxNCAwIDAgMSA0ODIuNTI4OTcsNjE1LjYxNzkgODAsNzIuODU3MTQgMCAwIDEgMzc2LjAwNjgzLDU4Ni42ODI2OSA4MCw3Mi44NTcxNCAwIDAgMSA0MDQuMDY4MjksNDg4LjcyNzAxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0icGF0aDMwMDciCiAgICAgICAgIHNvZGlwb2RpOnJ4PSIxMTEuNjUzOTIiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSIxMTAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNDMwLjkzMzYyIgogICAgICAgICBzb2RpcG9kaTpjeD0iNDAwLjIyNjM1IgogICAgICAgICBzb2RpcG9kaTplbmQ9IjYuMTE0MDA2OSIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjIuNzgxNjI2OSIKICAgICAgICAgc29kaXBvZGk6YXJjLXR5cGU9ImFyYyIKICAgICAgICAgZD0ibSAyOTUuNzI4NDUsNDY5LjY4MDI2IGEgMTExLjY1MzkyLDExMCAwIDAgMSAyMi44NjQ5OCwtMTEzLjc5MzQ4IDExMS42NTM5MiwxMTAgMCAwIDEgMTEzLjY0ODgyLC0zMC4zMzQwMSAxMTEuNjUzOTIsMTEwIDAgMCAxIDc4LjA0Mzk5LDg2Ljg1OTg3IiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0icGF0aDMwMDkiCiAgICAgICAgIHNvZGlwb2RpOnJ4PSIxMTUuNzE0MjkiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSIxMDAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweCIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgICBzb2RpcG9kaTpjeT0iNDgwLjkzMzYyIgogICAgICAgICBzb2RpcG9kaTpjeD0iNTEyLjg1NzEyIgogICAgICAgICBzb2RpcG9kaTplbmQ9IjIuMTU1NzExMiIKICAgICAgICAgc29kaXBvZGk6c3RhcnQ9IjMuODQ1MTc1IgogICAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgICBkPSJNIDQyNC42MjE1Niw0MTYuMjM4MjggQSAxMTUuNzE0MjksMTAwIDAgMCAxIDU4NC4xNzEsNDAyLjE4MTkxIDExNS43MTQyOSwxMDAgMCAwIDEgNjA2LjczMjk2LDUzOS40MDA0MiAxMTUuNzE0MjksMTAwIDAgMCAxIDQ0OC45Njc5Nyw1NjQuMzA5NTMiIC8+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTIzIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yaz4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL3B1YmxpY2RvbWFpbi96ZXJvLzEuMC8iIC8+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudAogICAgICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vb3BlbmNsaXBhcnQub3JnLyI+CiAgICAgICAgICAgIDxkYzp0aXRsZT5PcGVuY2xpcGFydDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICA8L2NjOldvcms+CiAgICAgIDxjYzpMaWNlbnNlCiAgICAgICAgIHJkZjphYm91dD0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvcHVibGljZG9tYWluLyI+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI1JlcHJvZHVjdGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjRGlzdHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNEZXJpdmF0aXZlV29ya3MiIC8+CiAgICAgIDwvY2M6TGljZW5zZT4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K' /> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
Another rework of the previous example, this time using FontAwesome - not even this renders in Github mermaid diagram:
%%{init: {'theme':'base'}}%%
flowchart LR
subgraph Border
direction LR
M1["Machine 1"]:::wht;
subgraph CloudContainer[ ]
direction LR
%% text with <br> does not render with position:absolute
%% use img top and div padding to center text in image;
%% color:#c8c8c8 seems not to work here - must escape the # as #35;
CloudImgNode("<div style='position:absolute;left:8px;top:-20px;color:#35;bbb;font-size:80px;'>fa:fa-cloud</div> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
end
M2["Machine 2"]:::wht;
M1 --> CloudImgNode;
CloudImgNode --> M2;
end
%% Defining Class Styles
%% background-image:"" passes, but not with any text inside quotes
%% node that classes here get defined with "#graph-div " prepended!
%% however, seemingly <img> and such are included via foreignObject, so cannot refer to these classes
classDef BorderClass fill:#fff,stroke:#fff,stroke-width:4px,color:#fff,stroke-dasharray: 5 5,margin:0,padding:0;
classDef ContainerClass position:relative,padding:0,margin:0,fill:#fff,color:#000,stroke:none;
classDef ImgNodeClass fill:#fff,padding:0,margin:0,stroke:none,margin:0;
classDef wht fill:#fff,color:black,stroke:#000;
%% Custom Styles
%% Assigning Nodes to Classes
%% class gets applied to all childer, too!
class Border BorderClass;
class CloudContainer ContainerClass;
class CloudImgNode ImgNodeClass;
At least PNG direct markdown link from Mermaid Live editor works - unfortunately, the alignment of the icon you see in the Live editor and the png below will not be the same (the below is tuned for PNG output)
... and at last I tried with the Unicode symbol for cloud - and this seems to work also in Github mermaid diagram:
%%{init: {'theme':'base'}}%%
flowchart LR
subgraph Border
direction LR
M1["Machine 1"]:::wht;
subgraph CloudContainer[ ]
direction LR
%% text with <br> does not render with position:absolute
%% use img top and div padding to center text in image; color:#c8c8c8 seems not to work?
CloudImgNode("<div style='position:absolute;left:12px;top:-10px;color:#35;bbb;font-size:80px;'>#9729;#65039;</div> <div style='position:relative;z-index:100;color:black;padding:18px;'>Subnet <br /> 10.1.1.0/24 </div>");
end
M2["Machine 2"]:::wht;
M1 --> CloudImgNode;
CloudImgNode --> M2;
end
%% Defining Class Styles
%% background-image:"" passes, but not with any text inside quotes
%% node that classes here get defined with "#graph-div " prepended!
%% however, seemingly <img> and such are included via foreignObject, so cannot refer to these classes
classDef BorderClass fill:#fff,stroke:#fff,stroke-width:4px,color:#fff,stroke-dasharray: 5 5,margin:0,padding:0;
classDef ContainerClass position:relative,padding:0,margin:0,fill:#fff,color:#000,stroke:none;
classDef ImgNodeClass fill:#fff,padding:0,margin:0,stroke:none,margin:0;
classDef wht fill:#fff,color:black,stroke:#000;
%% Custom Styles
%% Assigning Nodes to Classes
%% class gets applied to all childer, too!
class Border BorderClass;
class CloudContainer ContainerClass;
class CloudImgNode ImgNodeClass;
@sdbbs Would you like to officially take this issue on? :)
More information available in #1250
Shape for actors
I think svg support is definitely the route to go. Simple ones are extremely compact compared to rendered images so they can easily be embedded into the markdown. I am wanting a simple cloud shape as well but for now will have to just use a box.
So it seems that the shapes are first created as points and added as functions.
For Example, (flowchart shapes) notice the function found at: https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js:
To Make a Trapezoid, notice the function on Line 120:
function trapezoid(parent, bbox, node) {
const w = bbox.width;
const h = bbox.height;
const points = [
{ x: (-2 * h) / 6, y: 0 },
{ x: w + (2 * h) / 6, y: 0 },
{ x: w - h / 6, y: -h },
{ x: h / 6, y: -h },
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
return intersectPolygon(node, points, point);
};
return shapeSvg;
}
So make inorder to make new shape, there would need to be a need a way to convert a SVG code into js points.
Example SVG:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<polygon points="10,10 40,10 30,40" fill="none" stroke="black" />
<polyline points="50,10 70,10 70,30 50,30" fill="none" stroke="blue" />
</svg>
Python script (untested):
import xml.etree.ElementTree as ET
def parse_svg(svg_path):
"""Parse the SVG file and convert its shapes into JavaScript code."""
# Parse the SVG file
tree = ET.parse(svg_path)
root = tree.getroot()
for element in root.iter():
if element.tag.endswith('polygon'):
# Parse the points attribute into a list of coordinate tuples
points = [(float(x), float(y)) for x, y in (p.split(',') for p in element.get('points').split())]
# Get the bounding box width and height
w = max(p[0] for p in points) - min(p[0] for p in points)
h = max(p[1] for p in points) - min(p[1] for p in points)
# Convert points into JavaScript object literals
js_points = [
f"{{ x: {p[0]}, y: {p[1]} }}"
for p in points
]
# Create a JavaScript code snippet
js_code = f"const points = [{', '.join(js_points)}];"
print(f"JavaScript Code:\n{js_code}\n")
def parse_svg_file(svg_path):
"""Parse an SVG file and print JavaScript code for each shape."""
parse_svg(svg_path)
# Usage
parse_svg_file('example.svg')
Example output:
const points = [{ x: 10, y: 10 }, { x: 40, y: 10 }, { x: 30, y: 40 }];
So out NEW function may look like this:
function myNewShape(parent, bbox, node) {
const w = bbox.width;
const h = bbox.height;
const points = [
{ x: 10, y: 10 },
{ x: 40, y: 10 },
{ x: 30, y: 40 }
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
return intersectPolygon(node, points, point);
};
return shapeSvg;
}
Please let me know if this works??
example.svg:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<polygon points="10,10 40,10 30,40" fill="none" stroke="black" />
<polyline points="50,10 70,10 70,30 50,30" fill="none" stroke="blue" />
</svg>
Other script versions:
Using PHP
<?php
function parse_svg($svg_path) {
$xml = simplexml_load_file($svg_path);
foreach ($xml->children() as $element) {
$tag = strtolower($element->getName());
if ($tag === "polygon") {
$points = (string) $element['points'];
$point_pairs = explode(" ", $points);
$js_points = array_map(function ($pair) {
list($x, $y) = explode(",", $pair);
return "{ x: " . floatval($x) . ", y: " . floatval($y) . " }";
}, $point_pairs);
$js_code_content = implode(", ", $js_points);
echo "JavaScript Array Content:\n" . $js_code_content . "\n\n";
}
// Additional logic for other shape types can be added here
}
}
parse_svg('example.svg');
?>
Script Functionality:
SimpleXML: The script uses PHP's simplexml_load_file function to parse the SVG file. Polygon Points: Points are parsed from the points attribute, split into pairs, and converted into JavaScript object literals. JavaScript Snippet: These literals are concatenated into a string representing the contents of the points array. Output: The script prints this string to the console.
OR Using JS
const fs = require('fs');
const { DOMParser } = require('xmldom');
function parseSVG(svgPath) {
// Read the SVG file as a string
const svgContent = fs.readFileSync(svgPath, 'utf8');
// Parse the SVG content into a DOM tree
const doc = new DOMParser().parseFromString(svgContent, 'text/xml');
const polygons = doc.getElementsByTagName('polygon');
for (let i = 0; i < polygons.length; i++) {
const points = polygons[i].getAttribute('points');
const pointPairs = points.split(' ');
const jsPoints = pointPairs.map(pair => {
const [x, y] = pair.split(',');
return `{ x: ${parseFloat(x)}, y: ${parseFloat(y)} }`;
});
const jsCodeContent = jsPoints.join(', ');
console.log(`JavaScript Array Content:\n${jsCodeContent}\n`);
}
}
// Usage
parseSVG('example.svg');
Script Functionality:
FS Module: The script uses Node.js's fs module to read the SVG file as a string. DOMParser: It uses the DOMParser class to convert the SVG content into a DOM tree. Polygon Points: Points are extracted from the points attribute, split into pairs, and converted into JavaScript object literals. JavaScript Snippet: The literals are concatenated into a string representing the array contents. Output: The script prints this string to the console.
Output:
{ x: 10, y: 10 }, { x: 40, y: 10 }, { x: 30, y: 40 }
Conclusion: Both scripts (PHP and JavaScript) parse the SVG file, extract its coordinates, and output them in a format suitable for JavaScript arrays. You can adapt and extend these scripts to handle various shapes or integrate them directly into your workflows.
Ah Fontawesome support is added. Now, how can we make custom FA icons https://fontawesome.com/search?o=r&f=brands
I would like to add a custom shape to my diagram, specifically a flow chart, but possibly other types?
I have an SVG file for it. Is there a simple way to add it as a shape in my diagrams, either by using it directly or converting it to another representation and then using it from there?