Add border around svg sitemap - javascript

What do i have to do to get a border around my sitemap?
I have made a sitemap and i'd like to add a border around the elements just to give it a bit more character and less bland.
<style>
#svgJS g:hover polyline,
#svgJS g:hover line {
fill: none;
stroke-width: 2;
stroke: black;
}
#svgJS g:hover g text,
#svgJS g:hover text {
font-weight: bold;
}
#svgJS g:hover polygon,
#svgJS g:hover rect,
#svgJS g:focus polygon,
#svgJS g:focus rect {
fill: pink;
stroke: blue;
stroke-width: 2;
}
h1 {
font-family: sans-serif;
<!--text-align: centre;-->
}
a {
text-decoration: none;
}
a:link, a:visited {
color: #0000FF;
}
a:hover {
color: grey;
}
a:
.container {
margin: auto;
}
header {
position: sticky;
top: 0;
}
</style>
<svg style="text-align:center" id="svgJS" height="1920" width="1280">
<g id="GROUPONE">
<rect x="375" y="10" height="50" width="150"
stroke="#0000FF" fill="none" stroke-width="2" />
<text fill="#000" font-size="14" x="450" y="41"
font-family="Sans-Serif" text-anchor="middle">
Main Page</text>
</g>
<g id="groupId2">
<line id="shapeId2" stroke="#0000FF" stroke-width="2"
x1="450" y1="60" x2="450" y2="110"></line>
<polyline points="455, 105 450, 110 445, 105"
stroke="#0000FF" stroke-width="2" fill="none" />
</g>
<g id="groupId3" >
<rect x="375" y="110" height="50"
width="150" stroke="#0000FF" fill="none"
stroke-width="2" />
<text fill="#000" font-size="14" x="450" y="141"
font-family="Sans-Serif" text-anchor="middle">
Query form</text></g>

you can wrap your svg with a div tag and give it a border with CSS
<div class='myClassName'>
<SVG/>
<div>
then on your CSS
.myClassName {
border: 2px solid black;
}

I'm not sure what you're really looking for but I hope this answers your question.
Simply apply border style to the svg. like so:
/* ADDED THIS LINE */
svg {
border: 1px solid #ff0000
}
#svgJS g:hover polyline,
#svgJS g:hover line {
fill: none;
stroke-width: 2;
stroke: black;
}
#svgJS g:hover g text,
#svgJS g:hover text {
font-weight: bold;
}
#svgJS g:hover polygon,
#svgJS g:hover rect,
#svgJS g:focus polygon,
#svgJS g:focus rect {
fill: pink;
stroke: blue;
stroke-width: 2;
}
h1 {
font-family: sans-serif;
<!--text-align: centre;
-->
}
a {
text-decoration: none;
}
a:link,
a:visited {
color: #0000FF;
}
a:hover {
color: grey;
}
a: .container {
margin: auto;
}
header {
position: sticky;
top: 0;
}
<svg style="text-align:center" id="svgJS" height="1920" width="1280">
<g id="GROUPONE">
<rect x="375" y="10" height="50" width="150"
stroke="#0000FF" fill="none" stroke-width="2" />
<text fill="#000" font-size="14" x="450" y="41"
font-family="Sans-Serif" text-anchor="middle">
Main Page</text>
</g>
<g id="groupId2">
<line id="shapeId2" stroke="#0000FF" stroke-width="2"
x1="450" y1="60" x2="450" y2="110"></line>
<polyline points="455, 105 450, 110 445, 105"
stroke="#0000FF" stroke-width="2" fill="none" />
</g>
<g id="groupId3" >
<rect x="375" y="110" height="50"
width="150" stroke="#0000FF" fill="none"
stroke-width="2" />
<text fill="#000" font-size="14" x="450" y="141"
font-family="Sans-Serif" text-anchor="middle">
Query form</text></g>

Related

Add a tick selected css

.showcase-components-colorlist color {
border: 2px solid transparent;
margin: 1px;
padding: 2px;
border-radius: 50%;
cursor: pointer;
}
<div class="showcase-components-colorlist color showcase-components-colorlist color-- active">
<svg width="40" height="40">
<circle cx="20" cy="20" r="19" fill="#c5145d" stroke="#fff" stroke-width="1"></circle>
</svg>
</div>
<div class="showcase-components-colorlist color">
<svg width="40" height="40">
<circle cx="20" cy="20" r="19" fill="#db2586" stroke="#fff" stroke-width="1"></circle>
</svg>
</div>
How to add a check mark to one of the circles as generated by the code above.
One way to do this is through pseudo content. You need to give the element which you'll set the pseudo content a relative container. Then, you create your pseudo content (in this case, a check mark). The positioning will be relative to the parent element's dimensions.
.showcase-components-colorlist {
border: 2px solid transparent;
margin: 1px;
padding: 2px;
border-radius: 50%;
cursor: pointer;
position: relative;
}
.showcase-components-colorlist.selected::before {
content: '✅';
position: absolute;
left: 11px;
top: 9px;
}
<div class="showcase-components-colorlist color showcase-components-colorlist color-- active">
<svg width="40" height="40"><circle cx="20" cy="20" r="19" fill="#c5145d" stroke="#fff" stroke-width="1">
</circle>
</svg>
</div>
<div class="showcase-components-colorlist selected">
<svg width="40" height="40">
<circle cx="20" cy="20" r="19" fill="#db2586" stroke="#fff" stroke-width="1"></circle>
</svg>
</div>
Create your own <svg-option> Native JavaScript Web Component.
<svg-option></svg-option>
<svg-option fill="red" selected></svg-option>
<svg-option fill="rebeccapurple" selected-fill="yellow" selected></svg-option>
creates:
<script>
customElements.define("svg-option",class extends HTMLElement{
connectedCallback(){
this.style.display = "inline-block";
this.innerHTML=`<svg viewBox="0 0 50 50">
<circle cx="50%" cy="50%" r="49%" fill="${this.getAttribute("fill") || "green"}"/>
<circle cx="50%" cy="50%" r="30%" fill="${this.getAttribute("selected-fill") || "beige"}" visibility="hidden"/>
</svg>`;
this.select();
this.onclick = (evt) => this.toggle();
}
select(state = this.hasAttribute("selected")) {
this.querySelector("circle:nth-child(2)").setAttribute("visibility" , state ? "visible" :"hidden");
}
toggle(){
this.select( this.toggleAttribute("selected") );
}
})
</script>
<style>
svg-option {
--svg-option-size:180px;
width: var(--svg-option-size);
height: var(--svg-option-size);
cursor: pointer;
}
svg-option[selected]{
background:lightgreen;
}
svg-option:not([selected]){
background:pink;
}
</style>
<svg-option></svg-option>
<svg-option fill="red" selected></svg-option>
<svg-option fill="rebeccapurple" selected-fill="yellow" selected></svg-option>

Fade color in path tag

In HTML with SVG you can create a rect with fading color:
<svg>
<rect width="100%" height="100%">
<animate attributeName="fill" values="red;blue;red" dur="10s" repeatCount="indefinite" />
</rect>
</svg>
Now in my code I have a path like that:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="247pt" height="543pt" viewBox="0.00 0.00 246.86 543.19">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 539.1859)">
<!-- c->e -->
<g id="a1124" class="edge">
<title>c->e</title>
<path fill="none" stroke="#ff0000" stroke-width="3" d="M208.109,-297.8625C205.1217,-279.2357 200.2512,-248.8658 195.5911,-219.8076" />
<polygon fill="#ff0000" stroke="#ff0000" stroke-width="3" points="198.9943,-218.9251 193.9549,-209.6055 192.0827,-220.0336 198.9943,-218.9251" />
</g>
</g>
</svg>
I am looking for a way to fade the color of the path along the path so that it illustrates some kind of data flow. Is there a way to accomplish that? (via CSS or Javascript).
Try this
#keyframes fade {
0% {
stroke: red;
fill: red;
}
50% {
stroke: blue;
fill: blue;
}
100% {
stroke: red;
fill: red;
}
}
#fade {
animation-name: fade;
animation-duration: 10s;
animation-iteration-count: infinite;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="247pt" height="543pt" viewBox="0.00 0.00 246.86 543.19">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 539.1859)">
<!-- c->e -->
<g id="a1124" class="edge">
<title>c->e</title>
<path id="fade" stroke="#ff0000" stroke-width="3" d="M208.109,-297.8625C205.1217,-279.2357 200.2512,-248.8658 195.5911,-219.8076" />
<polygon id="fade" stroke-width="3" points="198.9943,-218.9251 193.9549,-209.6055 192.0827,-220.0336 198.9943,-218.9251" />
</g>
</g>
</svg>

With a SVG circle, how to position the starting point?

I'm working to create an SVG circle progress indicator in react... Here is my output:
CODEPEN
The problem is I need the red stroke to start at the top, not at the current 90% angle... Is there some CSS I can add to reposition the red stroke to start at the top?
FYI, I'm using the following component in react to render this HTML: https://github.com/wmartins/react-circular-progress/blob/gh-pages/src/js/components/CircularProgress.jsx.js
codepen source below
html
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
css
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
You could use transform, add transform="rotate(-90 25 25)" and it will start at the top
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle transform="rotate(-90 25 25)" class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-startOffest: 50%;stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
If to use CSS, you can rotate the svg element instead of the circle (which might or might not be possible based on its shape)
.CircularProgress {
transform: rotate(-90deg);
}
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0, 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>

svg with inline css to image data uri

So I have currently tried converting an SVG to an image with a data uri, and it works for simple SVGs, however I am using mermaid js for complex charts and graphs which contains internal css and other elements, here is an example:
<div class="mermaid" data-processed="true"><svg id="mermaidChart1" width="100%" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1112 268" style="max-width:1112px;"><style type="text/css" title="mermaid-svg-internal-css">/* */
#mermaidChart1 .node { fill:#ffa; stroke:#666; stroke-width:3px; }
#mermaidChart1 .node text { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .edgeLabel text { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .cluster rect { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0px; padding: 0px; border: 0px; outline: 0px; font-size: 100%; vertical-align: baseline; background: transparent; }
#markdown-preview .mermaid .label { color: rgb(51, 51, 51); }
#markdown-preview .node rect, #markdown-preview .node circle, #markdown-preview .node polygon { fill: rgb(238, 238, 238); stroke: rgb(51, 51, 51); stroke-width: 1px; }
#markdown-preview .edgePath .path { stroke: rgb(51, 51, 51); }
#markdown-preview .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4px !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
#markdown-preview .cluster text { fill: rgb(51, 51, 51); }
#markdown-preview text { font-family: 'Roboto Slab', verdana, arial; font-size: 14px; }
/* */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph2" transform="translate(969,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph2</div></foreignObject></g></g><rect width="206" height="208" x="-103" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Effects</text></g><g class="cluster" id="subGraph1" transform="translate(581.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-48,-12)"><foreignObject width="96" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph1</div></foreignObject></g></g><rect width="469" height="208" x="-234.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Combat Scenario</text></g><g class="cluster" id="subGraph0" transform="translate(158.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph0</div></foreignObject></g></g><rect width="277" height="208" x="-138.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Weapon & Target</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M257,77L297,77L322,77L347,77L403.9148936170213,102" marker-end="url(#arrowhead125)" style="fill:none"></path><defs><marker id="arrowhead125" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M272,171L297,171L322,171L347,171L403.9148936170213,146" marker-end="url(#arrowhead126)" style="stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;"></path><defs><marker id="arrowhead126" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,102L561,77L595,77" marker-end="url(#arrowhead127)" style="fill:none"></path><defs><marker id="arrowhead127" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,146L561,171L586,171" marker-end="url(#arrowhead128)" style="fill:none"></path><defs><marker id="arrowhead128" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M782,77L816,77L841,77L866,77L891,77" marker-end="url(#arrowhead129)" style="fill:none"></path><defs><marker id="arrowhead129" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M791,171L816,171L841,171L866,171L908.5,171" marker-end="url(#arrowhead130)" style="fill:none"></path><defs><marker id="arrowhead130" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node" id="Damage" transform="translate(688.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-93.5" y="-22" width="187" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-83.5,-12)"><foreignObject width="167" height="24"><div style="display: inline-block; white-space: nowrap;">DamageCalculator</div></foreignObject></g></g></g><g class="node" id="Output" transform="translate(969,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;">Bonus Damage</div></foreignObject></g></g></g><g class="node" id="Visual" transform="translate(688.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-102.5" y="-22" width="205" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-92.5,-12)"><foreignObject width="185" height="24"><div style="display: inline-block; white-space: nowrap;">VisualEffectHandler</div></foreignObject></g></g></g><g class="node" id="Output2" transform="translate(969,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;">Set On Fire</div></foreignObject></g></g></g><g class="node" id="CombatHandler" transform="translate(454,124)" style="opacity: 1;"><rect rx="5" ry="5" x="-82" y="-22" width="164" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-72,-12)"><foreignObject width="144" height="24"><div style="display: inline-block; white-space: nowrap;">CombatHandler</div></foreignObject></g></g></g><g class="node" id="Tags" transform="translate(158.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-98.5" y="-22" width="197" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-88.5,-12)"><foreignObject width="177" height="24"><div style="display: inline-block; white-space: nowrap;">silver, magic, sharp</div></foreignObject></g></g></g><g class="node" id="Optional" transform="translate(158.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-113.5" y="-22" width="227" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-103.5,-12)"><foreignObject width="207" height="24"><div style="display: inline-block; white-space: nowrap;">werewolf, undead, frail</div></foreignObject></g></g></g></g></g></g></svg></div>
Now the problem is when I target svg tags and do the xml serialization like so:
var svgToDataUri = function(svgElement){
console.log("converting svg to datauri");
// Create canvas for converting image to data URL
var image = document.createElement("img");
var parent = svgElement.parentElement;
image.style.width = svgElement.width + "px";
image.style.height = svgElement.height + "px";
// get svg data
var xml = new XMLSerializer().serializeToString(svgElement);
// make it base64
var svg64 = btoa(xml);
var image64 = 'data:image/svg+xml;base64,' + svg64;
// Get data URL encoding of image
image.setAttribute("src", image64);
parent.insertBefore(image, svgElement);
parent.removeChild(svgElement);
};
The output image is missing bits and also does not seem to be styled correctly, even though it is basically replacing the existing content so should have all same styles on the page, so do I need to do anything special when outputting more complex svg elements to images or should this work? (tried it in FF, Chrome)
Here is an example of the actual output and desired output:
So as you can see it just blacks out sections and some lines are not visible, the one below looks how I would expect it to look.
#markdown-preview doesn't occur as an id of any element of your svg - or of the posted html for that matter. This means it won't render as you expect as original svg (see second attached image below).
Probably the html originally surrounding the div does contain an element with that id.
Quick fix: give the outer group in the svg the markdown-preview id: replace </style><g><g class="output"> with </style><g id="markdown-preview"><g class="output"> (see attached and HTML snippet image below)
Permanent fix: file an issue with the software that rendered the svg.
results
I've uncommented the parent.removeChild(svgElement); in your code so I could see both the img (first in each) and the original svg (second).
Fixed:
The original HTML:
The code I used to reproduce 'fixed'
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" defer>
var svgToDataUri = function(svgElement){
console.log("converting svg to datauri");
// Create canvas for converting image to data URL
var image = document.createElement("img");
var parent = svgElement.parentElement;
image.style.width = svgElement.width + "px";
image.style.height = svgElement.height + "px";
// get svg data
var xml = new XMLSerializer().serializeToString(svgElement);
// make it base64
var svg64 = btoa(xml);
var image64 = 'data:image/svg+xml;base64,' + svg64;
// Get data URL encoding of image
image.setAttribute("src", image64);
parent.insertBefore(image, svgElement);
// parent.removeChild(svgElement);
};
</script>
</head>
<body>
<div class="mermaid" data-processed="true"><svg id="mermaidChart1" width="100%" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1112 268" style="max-width:1112px;"><style type="text/css" title="mermaid-svg-internal-css">/* */
#mermaidChart1 .node { fill:#ffa; stroke:#666; stroke-width:3px; }
#mermaidChart1 .node text { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .edgeLabel text { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .cluster rect { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0px; padding: 0px; border: 0px; outline: 0px; font-size: 100%; vertical-align: baseline; background: transparent; }
#markdown-preview .mermaid .label { color: rgb(51, 51, 51); }
#markdown-preview .node rect, #markdown-preview .node circle, #markdown-preview .node polygon { fill: rgb(238, 238, 238); stroke: rgb(51, 51, 51); stroke-width: 1px; }
#markdown-preview .edgePath .path { stroke: rgb(51, 51, 51); }
#markdown-preview .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4px !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
#markdown-preview .cluster text { fill: rgb(51, 51, 51); }
#markdown-preview text { font-family: 'Roboto Slab', verdana, arial; font-size: 14px; }
/* */
</style><g id="markdown-preview"><g class="output"><g class="clusters"><g class="cluster" id="subGraph2" transform="translate(969,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph2</div></foreignObject></g></g><rect width="206" height="208" x="-103" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Effects</text></g><g class="cluster" id="subGraph1" transform="translate(581.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-48,-12)"><foreignObject width="96" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph1</div></foreignObject></g></g><rect width="469" height="208" x="-234.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Combat Scenario</text></g><g class="cluster" id="subGraph0" transform="translate(158.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph0</div></foreignObject></g></g><rect width="277" height="208" x="-138.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Weapon & Target</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M257,77L297,77L322,77L347,77L403.9148936170213,102" marker-end="url(#arrowhead125)" style="fill:none"></path><defs><marker id="arrowhead125" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M272,171L297,171L322,171L347,171L403.9148936170213,146" marker-end="url(#arrowhead126)" style="stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;"></path><defs><marker id="arrowhead126" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,102L561,77L595,77" marker-end="url(#arrowhead127)" style="fill:none"></path><defs><marker id="arrowhead127" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,146L561,171L586,171" marker-end="url(#arrowhead128)" style="fill:none"></path><defs><marker id="arrowhead128" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M782,77L816,77L841,77L866,77L891,77" marker-end="url(#arrowhead129)" style="fill:none"></path><defs><marker id="arrowhead129" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M791,171L816,171L841,171L866,171L908.5,171" marker-end="url(#arrowhead130)" style="fill:none"></path><defs><marker id="arrowhead130" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node" id="Damage" transform="translate(688.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-93.5" y="-22" width="187" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-83.5,-12)"><foreignObject width="167" height="24"><div style="display: inline-block; white-space: nowrap;">DamageCalculator</div></foreignObject></g></g></g><g class="node" id="Output" transform="translate(969,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;">Bonus Damage</div></foreignObject></g></g></g><g class="node" id="Visual" transform="translate(688.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-102.5" y="-22" width="205" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-92.5,-12)"><foreignObject width="185" height="24"><div style="display: inline-block; white-space: nowrap;">VisualEffectHandler</div></foreignObject></g></g></g><g class="node" id="Output2" transform="translate(969,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;">Set On Fire</div></foreignObject></g></g></g><g class="node" id="CombatHandler" transform="translate(454,124)" style="opacity: 1;"><rect rx="5" ry="5" x="-82" y="-22" width="164" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-72,-12)"><foreignObject width="144" height="24"><div style="display: inline-block; white-space: nowrap;">CombatHandler</div></foreignObject></g></g></g><g class="node" id="Tags" transform="translate(158.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-98.5" y="-22" width="197" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-88.5,-12)"><foreignObject width="177" height="24"><div style="display: inline-block; white-space: nowrap;">silver, magic, sharp</div></foreignObject></g></g></g><g class="node" id="Optional" transform="translate(158.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-113.5" y="-22" width="227" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-103.5,-12)"><foreignObject width="207" height="24"><div style="display: inline-block; white-space: nowrap;">werewolf, undead, frail</div></foreignObject></g></g></g></g></g></g></svg></div>
<script>
svgToDataUri(document.getElementById("mermaidChart1"));
</script>
</body>
</html>
B.t.w. here's some things I learned the hard way to do while developing mscgen_js, but you might already know and left out just to simplify your sample code:
add a charset to the data uri, so text will render correctly even when it's not ASCII (provided fonts are available) data:image/svg+xml;charset=utf-8;base64,
for similar reasons, when dumping the generated uri in links/ url bars encodeURIComponent and unescape it before feeding it to the btoa
(... and think of a strategy for hitting browse max uri length in case you ever run on IE)

SVG not showing after dynamicallly added into HTML document

I am using Saxon CE for some transformations from xml to another xml and then to svg. My point is, that the transformations completes successfully and in source I am able to see that the svg has been added into the HTML document, however is not visible for some reason (I have set visibility to visible and that does not help). I am attaching the HTML structure as it before the transformations begins, then is the transformation output and finally the updated HTML. When I open the full HTML just in browser it works fine. Could it be some runtime problem i guess, however I do not know where to look for more information.
EDIT: I have previously used "g" elements, I thought it should be connected with it, but do not seems like it
<g>
Thanks in advance for any tips and help,
<!DOCTYPE html>
<html>
<head>
<title>Book Catalogue</title>
<script src="http://localhost:12345/SaxonCE/Saxonce.nocache.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
function PK_func(in_xml) {
var proc = Saxon.newXSLT20Processor(Saxon.requestXML("Flattening_XSD_StackOverFlow.xsl"));
proc.transformToDocument(Saxon.parseXML(in_xml));
var rd1URI = proc.getResultDocuments()[0];
var rd1Doc = proc.getResultDocument(rd1URI);
//var proc2 = Saxon.newXSLT20Processor(Saxon.requestXML("Flattening_XSD_StackOverFlow.xsl"));
//proc2.updateHTMLDocument(Saxon.parseXML(in_xml));
return rd1Doc;
}
function PK_func_2(in_xml) {
var proc = Saxon.newXSLT20Processor(Saxon.requestXML("Visualise_flatten_xsd.xsl"));
proc.transformToDocument(Saxon.parseXML(in_xml));
var rd1URI = proc.getResultDocuments()[0];
var rd1Doc = proc.getResultDocument(rd1URI);
var proc2 = Saxon.newXSLT20Processor(Saxon.requestXML("Visualise_flatten_xsd.xsl"));
proc2.updateHTMLDocument(rd1Doc);
return rd1Doc;
}
function get_width(input_text) {
var measuringCanvas = document.getElementById('measuringCanvas');
var ctx = measuringCanvas.getContext("2d");
ctx.font = "12px Verdana";
var width = ctx.measureText(input_text).width;
return width + 60;
}
window.onload = function() {
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e)
{
var xml = reader.result;
var flatten_xsd = PK_func(xml);
console.log(flatten_xsd);
var visualised_xsd = PK_func_2(flatten_xsd);
console.log(visualised_xsd);
}
reader.readAsText(file);
});
}
</script>
</head>
<body>
<div id="sortToolTip" class="tooltip" style="position:fixed; visibility:hidden; left:0px; top:0px">
Click to sort on this column
</div>
<canvas id="measuringCanvas" display="none" width="50px" height="50px" style="display: none;"></canvas>
<h1 id="title">Header</h1>
<input type="file" id="fileInput">
<h2>Genres</h2>
<div id="genres"></div>
<h2>Books</h2>
<div id="XYZ"></div>
</body>
</html>
The added SVG:
<svg visibility="visible" height="500" width="500">
<svg visibility="visible" transform="scale(37.03703703703704)">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="1" x="5.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="2.5" x2="6.5" y1="2" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="2.5" x2="6.5" y1="2.5" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="3" x2="6.5" y1="2.5" x1="6.5"/>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="7.5">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="3" x="5.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="4.5" x2="6.5" y1="4" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="4.5" x2="11.5" y1="4.5" x1="1.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="1.5" y1="4.5" x1="1.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="4" y1="4.5" x1="4"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="6.5" y1="4.5" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="9" y1="4.5" x1="9"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="11.5" y1="4.5" x1="11.5"/>
<svg visibility="visible" pk:maxy="6" pk:maxx="2.5" pk:thisx="2.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="0.5"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="5" pk:thisx="5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="3"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="7.5" pk:thisx="7.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="5.5"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="10" pk:thisx="10">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="8"/>
</svg>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="12.5">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="5" x="10.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="6.5" x2="11.5" y1="6" x1="11.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="6.5" x2="11.5" y1="6.5" x1="11.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="7" x2="11.5" y1="6.5" x1="11.5"/>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="12.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="7" x="10.5"/>
</svg>
</svg>
</svg>
</svg>
</svg>
The final document (which is rendering "fine", at at least renders at all :)) :
<html>
<head>
<title>Book Catalogue</title>
<script src="http://localhost:12345/SaxonCE/Saxonce.nocache.js" type="text/javascript"></script><script defer="defer">Saxonce.onInjectionDone('Saxonce')</script>
<script type="text/javascript" language="javascript">
function PK_func(in_xml) {
var proc = Saxon.newXSLT20Processor(Saxon.requestXML("Flattening_XSD_StackOverFlow.xsl"));
proc.transformToDocument(Saxon.parseXML(in_xml));
var rd1URI = proc.getResultDocuments()[0];
var rd1Doc = proc.getResultDocument(rd1URI);
return rd1Doc;
}
function PK_func_2(in_xml) {
var proc = Saxon.newXSLT20Processor(Saxon.requestXML("Visualise_flatten_xsd.xsl"));
proc.transformToDocument(Saxon.parseXML(in_xml));
var rd1URI = proc.getResultDocuments()[0];
var rd1Doc = proc.getResultDocument(rd1URI);
var proc2 = Saxon.newXSLT20Processor(Saxon.requestXML("Visualise_flatten_xsd.xsl"));
proc2.updateHTMLDocument(rd1Doc);
return rd1Doc;
}
function get_width(input_text) {
var measuringCanvas = document.getElementById('measuringCanvas');
var ctx = measuringCanvas.getContext("2d");
ctx.font = "12px Verdana";
var width = ctx.measureText(input_text).width;
return width + 60;
}
window.onload = function() {
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e)
{
var xml = reader.result;
var flatten_xsd = PK_func(xml);
console.log(flatten_xsd);
var visualised_xsd = PK_func_2(flatten_xsd);
console.log(visualised_xsd);
}
reader.readAsText(file);
});
}
</script>
</head>
<body>
<div id="sortToolTip" class="tooltip" style="position:fixed; visibility:hidden; left:0px; top:0px">
Click to sort on this column
</div>
<canvas id="measuringCanvas" display="none" width="50px" height="50px" style="display: none;"></canvas>
<h1 id="title">Header</h1>
<input id="fileInput" type="file">
<h2>Genres</h2>
<div id="genres"></div>
<h2>Books</h2>
<div id="XYZ"></div>
<iframe tabindex="-1" style="position: absolute; width: 0px; height: 0px; border: medium none;" id="Saxonce" src="javascript:''"></iframe>
<svg visibility="visible" height="500" width="500">
<svg visibility="visible" transform="scale(37.03703703703704)">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="1" x="5.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="2.5" x2="6.5" y1="2" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="2.5" x2="6.5" y1="2.5" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="3" x2="6.5" y1="2.5" x1="6.5"/>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="7.5">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="3" x="5.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="4.5" x2="6.5" y1="4" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="4.5" x2="11.5" y1="4.5" x1="1.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="1.5" y1="4.5" x1="1.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="4" y1="4.5" x1="4"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="6.5" y1="4.5" x1="6.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="9" y1="4.5" x1="9"/>
<line style="stroke: black; stroke-width:0.1;" y2="5" x2="11.5" y1="4.5" x1="11.5"/>
<svg visibility="visible" pk:maxy="6" pk:maxx="2.5" pk:thisx="2.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="0.5"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="5" pk:thisx="5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="3"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="7.5" pk:thisx="7.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="5.5"/>
</svg>
<svg visibility="visible" pk:maxy="6" pk:maxx="10" pk:thisx="10">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="5" x="8"/>
</svg>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="12.5">
<rect style="fill: none; stroke: black; stroke-width:0.1" height="1" width="2" y="5" x="10.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="6.5" x2="11.5" y1="6" x1="11.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="6.5" x2="11.5" y1="6.5" x1="11.5"/>
<line style="stroke: black; stroke-width:0.1;" y2="7" x2="11.5" y1="6.5" x1="11.5"/>
<svg visibility="visible" pk:maxy="8" pk:maxx="12.5" pk:thisx="12.5">
<rect style="fill: none; stroke: black; stroke-width:0.1;" height="1" width="2" y="7" x="10.5"/>
</svg>
</svg>
</svg>
</svg>
</svg>
</body>
</html>
I have not checked all the script code but as you seem to create the SVG first as XML I would start first by ensuring that the SVG elements are in the SVG namespace and not in no namespace as in the sample you have shown.

Categories

Resources