Reusing SVG elements while inserting different text? - svg

I want to display balls with 1,2,3,4 inside. Can I use <use>? or I must duplicate the stone <g>?
#stone text {
fill: grey;
dominant-baseline: middle;
text-anchor: middle;
font-size: 0.33pt;
}
#pane {
background-color: yellow;
width: 100%;
height: 100%;
}
.stone-white {
fill: #F2F4F4;
}
.stone-black {
fill: #273746;
}
<svg id="pane" viewBox="0 0 22 22" preserveAspectRatio="none">
<defs>
<g id="stone">
<circle cx="0" cy="0" r="0.45" />
<text>333</text>
</g>
</defs>
<use href="#stone" class="stone-white" x="1" y="1"/>
<use href="#stone" class="stone-white" x="2" y="2"/>
<use href="#stone" class="stone-black" x="3" y="2"/>
<use href="#stone" class="stone-black" x="2" y="4"/>
</svg>

Related

How to make a circular bullet point containing a number where the number text must scale

So I have been asked to make a section number that is constructed as a non-filled circle with a 2px border containing a number. The range of the numbers is 1 to 999.
As you can see from the example below, it looks pleasing at one & two digit section numbers, but when we hit three digits the number is clipped.
My thinking is that there needs to be a process where the text is drawn, measured, then scaled to fit into the target space inside the circle, where the target space is effectively a square rect 60% of the diameter of the circle.
However, no JS is allowed in the solution.
I thought it might be possible using SVG and its scaling capabilities via the 'preserveAspectRatio' parameter. However the image above is a screen grab of my SVG results. Working snippet below.
My intention with the code was to have the inner SVG containing the text resize proportionally so that it would fit the width of the parent, with the height set to auto so that it would change in proportion.
Can anyone tell me where I am going wrong?
PS. I am using Chrome on PC to test.
Note: In the following snippet the output looks like the image, so 8, then 88, then 888. The markup is the same for each case - only the text content changes.
body {
padding: 20px;
overflow: hidden;
background-color: #f0f0f0;
}
.counterDiv {
width: 44px;
max-width: 44px;
min-width: 44px;
height: 44px;
max-height: 44px;
min-height: 44px;
margin: 0;
padding: 0;
}
svg {
width: 100%;
height: 100%;
}
text {
font: normal normal 18pt Helvetica, Arial, Verdana;
}
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">8</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">88</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">888</text>
</svg>
</g>
</svg>
</div>
A posible solution would be using textLength and lengthAdjust. The lengthAdjust attribute controls how the text is stretched into the length defined by the textLength attribute. One inconvinient would be that the 1 digit numbers would be stretched.
An alternative solution would be using a smaller font size.
Also you may want to use javascript to target only the 3 digit text elements.
body {
padding: 20px;
overflow: hidden;
background-color: #f0f0f0;
}
.counterDiv {
width: 44px;
max-width: 44px;
min-width: 44px;
height: 44px;
max-height: 44px;
min-height: 44px;
margin: 0;
padding: 0;
}
svg {
width: 100%;
height: 100%;
}
text {
font: normal normal 18pt Helvetica, Arial, Verdana;
}
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">8</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">88</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">888</text>
</svg>
</g>
</svg>
</div>
Not for OP,
but for all those SVG loving people who have an inner-guide (or sensible boss)
that tells them: "JavaScript is fine, when applied with common sense"
customElements.define("svg-counter", class extends HTMLElement {
connectedCallback() {
this.render();
}
render(
val = this.getAttribute("value") || "888",
color = "green",
circlestrokewidth = 4,
circlestroke = "red",
circlefill = "none"
){
let id = "P" + (new Date() / 1); // uniqueid
let singleDigit = val.length == 1;
this.innerHTML = `
<svg viewbox="0 0 100 100">
<circle cx="50" cy="50" r="${50-circlestrokewidth}" stroke="${circlestroke}"
fill="${circlefill}" stroke-width="${circlestrokewidth}"/>
<path id="${id}" pathLength="100" d="M0 60H100" stroke="none"/>
<text transform="scale(${singleDigit?1:.7})" transform-origin="50 50">
<textPath href="#${id}" method="stretch"
textlength="100" lengthAdjust="${singleDigit?"":"spacingAndGlyphs"}"
startoffset="50" text-anchor="middle" dominant-baseline="middle"
font-family="Helvetica"
fill="${color}" font-size="${100}px">${val}</textPath>
</text>
</svg>`;
}
});
svg {
width: 20%;
}
<svg-counter value="8"></svg-counter>
<svg-counter value="88"></svg-counter>
<svg-counter value="888"></svg-counter>
<svg-counter value="8888"></svg-counter>
Alas FireFox has some issues, slight tweaked version to make it work in FireFox:
Alas I have a boss who says "We don't care about FireFox customers"
customElements.define("svg-counter", class extends HTMLElement {
connectedCallback() {
this.render();
}
render(
val = this.getAttribute("value") || "888",
color = "green",
circlestrokewidth = 4,
circlestroke = "red",
circlefill = "none"
){
let id = "P" + (new Date() / 1) + val.length; // uniqueid
let singleDigit = val.length == 1;
this.innerHTML = `
<svg viewbox="0 0 100 100">
<circle cx="50" cy="50" r="${50-circlestrokewidth}" stroke="${circlestroke}"
fill="${circlefill}" stroke-width="${circlestrokewidth}"/>
<path id="${id}" pathLength="100" d="M0 55H100" stroke="blue"/>
<text transform="scale(${[0,1.7,1.2,.9,.7][val.length]})" transform-origin="50 50">
<textPath href="#${id}" method="stretch"
textlength="100" lengthAdjust="${singleDigit?"":"spacingAndGlyphs"}"
startoffset="50" text-anchor="middle" dominant-baseline="middle"
font-family="Helvetica"
fill="${color}" font-size="50px">${val}</textPath>
</text>
</svg>`;
}
});
svg {
width: 20%;
}
<svg-counter value="8"></svg-counter>
<svg-counter value="88"></svg-counter>
<svg-counter value="888"></svg-counter>
<svg-counter value="8888"></svg-counter>

Issue when zooming in on SVG donut chart in Safari

I'm attempting to create a donut chart using SVG, and am running into a problem when viewing it in Safari. Here's a fiddle that shows the issue; I'll describe it in detail below:
https://jsfiddle.net/nijhazer/phy2ossh/
This fiddle shows a graphic comprised of two circles overlaid atop one another. The problem becomes apparent when a Safari user increases zoom size in her browser:
Relevant HTML from the example:
<div class="donut-chart">
<svg width="200" height="200">
<circle class="backdrop" cx="100" cy="100" r="65" fill="#d5d8d5" stroke="none" stroke-width="0"></circle>
<circle class="progress" cx="100" cy="100" r="75" fill="none" stroke="lightgreen" stroke-width="20" style="stroke-dashoffset: 353.428875px;"></circle>
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none" stroke="#d5d8d5" stroke-width="1"></circle>
</svg>
</div>
Relevant CSS from the example:
body {
background-color: white;
}
.donut-chart {
width: 200px;
height: 200px;
position: relative;
}
svg {
width: 200px;
height: 200px;
}
.progress {
stroke-dasharray: 471.24;
transform: rotate(-90deg);
transform-origin: 50% 50%;
background-color: transparent;
}
I don't know if this helps, but at I can read from the comments that people are blaming the CSS property transform-origin. In this example I moved the styling to attributes on the circle element. I also added pathLength to make it easier to control the progress bar.
body {
background-color: white;
}
.donut-chart {
width: 200px;
height: 200px;
position: relative;
}
svg {
width: 200px;
height: 200px;
}
<div class="donut-chart">
<svg viewBox="0 0 200 200" xmlns="http//www.w3.org/2000/svg">
<circle class="backdrop" cx="100" cy="100" r="65" fill="#d5d8d5"
stroke="none" stroke-width="0" />
<circle class="progress" cx="100" cy="100" r="75" fill="none"
stroke="lightgreen" stroke-width="20" stroke-dasharray="25 100"
transform="rotate(-90 100 100)" pathLength="100" />
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none"
stroke="#d5d8d5" stroke-width="1" />
</svg>
</div>
I can confirm chrwahl's approach is working (at least in MacOS/IOS safari versions (15.4) I've tested - Unfortunately, the support of functions may vary from version to version)
Another workaround could be to add a translateX offset before rotating like so:
.donut-chart {
width: 200px;
height: 200px;
position: relative;
display: block;
}
svg {
width: 200px;
height: 200px;
}
.progress {
stroke-dasharray: 471.24;
background-color: transparent;
transform: translate(0px, 200px) rotate(-90deg);
}
<div class="donut-chart">
<svg width="200" height="200" viewBox="0 0 200 200">
<circle class="backdrop" cx="50%" cy="50%" r="65" fill="#d5d8d5" stroke="none" stroke-width="0"></circle>
<circle class="progress" cx="50%" cy="50%" r="75" fill="none" stroke="lightgreen" stroke-width="20" style="stroke-dashoffset: 353.428875px;"></circle>
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none" stroke="#d5d8d5" stroke-width="1"></circle>
</svg>
</div>
This "hack" won't work combined with transform-origin: 50% 50%

Responsive SVG sizing

I have the following SVG:
body {
background-color: #dad9c7;
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Which looks like this:
How can I do the following?
Keep heights of colored strips the same when scaling the window (not scale).
Stretch colored strips horizontally to the edges of the viewport on either side left and right.
Stretch the top-most rectangle to the top of the screen so the upper third of the viewport is orange and stretch the bottom-most rectangle to the bottom of the viewport so that the lower third of the viewport is purple.
Always keep the "square" centered vertically which already works with CSS, but however the SVG is manipulated to solve would have to keep this into account.
Here is an example of how this would look: As the window gets taller, the colored rectangles will stay in the middle, but the top orange and bottom purple would be cut off based on the height of the viewport.
How can I do the following?
Keep heights of colored strips the same when scaling the window (not scale).
You are already doing this by setting height to 400px.
Stretch colored strips horizontally to the edges of the viewport on either side left and right.
Set preserveAspectRatio="none" on the SVG. See below.
body {
background-color: #dad9c7;
}
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<svg viewBox="0 0 1000 1000" preserveAspectRatio="none">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Stretch the top-most rectangle to the top of the screen so the upper third of the viewport is orange and stretch the bottom-most rectangle to the bottom of the viewport so that the lower third of the viewport is purple.
You cannot automatically stretch the rectangle itself with CSS. But one way you could do it is to use pseudo elements to colour the top and bottom halves of the parent element with matching colours.
body {
background-color: #dad9c7;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 0;
margin: 0;
}
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
body::before {
content: "";
display: block;
position: absolute;
width: 100%;
top: 0;
bottom: 50%;
background-color: #d5835b;
}
body::after {
content: "";
display: block;
position: absolute;
width: 100%;
top: 50%;
bottom: 0;
background-color: #313d53;
z-index: -1;
}
<svg viewBox="0 0 1000 1000" preserveAspectRatio="none">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Always keep the "square" centered vertically which already works with CSS, but however the SVG is manipulated to solve would have to keep this into account.
N/A here.
Alternate pure-SVG solution
There is also a pure SVG solution using nested <svg> elements. The only CSS we are using is just to ensure the SVG occupies the full size of the page.
It works by making the top and bottom rectangles extend outside the viewBox by an extra 1000 pixels. To make sure they are visible, we set overflow="visible". 1000 is an arbitrary value. If you want to support screens > 2400 pixels high, then you could choose a larger value.
The inner SVG gets centred vertically using a combination of a y offset and a transform that shifts it up by 200px. This is equivalent to the common top: 50%; transform: translate(0,-50%)" trick to vertically centre CSS block elements.
body {
background-color: #dad9c7;
padding: 0;
margin: 0;
}
#mysvg {
position: absolute;
display: block;
width: 100%;
height: 100%;
}
<svg id="mysvg">
<g transform="translate(0, -200)">
<svg width="100%" height="400px"
y="50%" transform="translate(0, -200)"
viewBox="0 0 1000 1000" preserveAspectRatio="none"
overflow="visible">
<g>
<rect width="1000" height="1151" x="0" y="-1000" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="1176" x="0" y="825" fill="#313d53" />
</g>
</svg>
</g>
</svg>
You cannot use media queries or css styling for that since a svg does not support that. If you really need to that with an SVG, you will need some Javascript to accomplish your desired effect. In your case, I guess it is simpler to create that using html and css with some media queries.
The only thing you can control when scaling/displaying a SVG is the preserveAspectRatio attribute. A detailed description can be found here.

circular arc paths with svg

I am pretty new to SVG and wanted to ask for a best approach to the following design:
I believe SVG is the way to go here since I need hover and click effects on each of the red arc pieces. These values and this design are essentially hardcoded and will not change. Are there any tools / libraries (D3 or Raphael) that would make this easier for me?
Thanks In Advance.
meetamit's suggestion is a good one. Or you could look into the 'sector' method shown here:
Half circle using raphael
You don't really need d3 or even an editor. It's a design that is easy to code by hand.
I was bored, so I whipped this up in about 10 minutes.
document.getElementById("band4").addEventListener("click", function(e) {
alert("50+");
}, false);
document.getElementById("band3").addEventListener("click", function(e) {
alert("20-50");
}, false);
document.getElementById("band2").addEventListener("click", function(e) {
alert("10-20");
}, false);
document.getElementById("band1").addEventListener("click", function(e) {
alert("Less than 10");
}, false);
svg {
position: absolute;
top: 0px;
}
circle.band {
fill: #a20c3e;
}
circle.band:hover {
fill: #ca3f5e;
}
text {
font-family: sans-serif;
font-size: 12px;
font-weight: bold;
fill: white;
}
tspan.sup {
font-size: 6px;
}
text.sub {
font-size: 5px;
font-weight: normal;
}
<img src="http://lorempixel.com/400/200/" width="100%"/>
<svg viewBox="-100 -100 200 100">
<defs>
<mask id="target">
<rect x="-100" width="100%" height="100%" fill="black"/>
<circle r="97" fill="white"/>
<circle r="77" fill="black"/>
<circle r="74" fill="white"/>
<circle r="54" fill="black"/>
<circle r="51" fill="white"/>
<circle r="31" fill="black"/>
<circle r="28" fill="white"/>
</mask>
</defs>
<circle id="band4" class="band" r="98" mask="url(#target)"/>
<circle id="band3" class="band" r="75" mask="url(#target)"/>
<circle id="band2" class="band" r="52" mask="url(#target)"/>
<circle id="band1" class="band" r="29" mask="url(#target)"/>
<text y="-82" text-anchor="middle" pointer-events="none">50<tspan class="sup" font-size="50%" dy="-0.7em">+</tspan></text>
<text y="-59" text-anchor="middle" pointer-events="none">20-50</text>
<text y="-36" text-anchor="middle" pointer-events="none">10-20</text>
<text y="-17" text-anchor="middle" class="sub" pointer-events="none">Less than</text>
<text y="-6" text-anchor="middle" pointer-events="none">10</text>
</svg>

Why are my SVG marker and gradient defs being overwritten?

The gradient and marker definitions for my SVG appear to get overwritten when my SVG is inside my webpage. There are no other SVGs on the page.
But when I take the SVG out of the page, it looks just fine.
Here is the SVG in this example.
<svg xmlns="http://www.w3.org/2000/svg" height="500" width="800">
<style>
svg .node.species {
stroke: #FFB800;
stroke-width: 3px;
size: 300px;
}
svg .node.reaction {
stroke: #8089F7;
opacity: 0;
stroke-width: 1.5px;
}
svg .link {
stroke: black;
stroke-width: 3px;
}
svg .link.modifier {
stroke-dasharray: 5, 5;
}
svg .node-label {
font-size: 14px;
font-family: Georgia;
font-weight: bolder;
text-anchor: middle;
dominant-baseline: middle;
}
/* svg .node.selected {
stroke: #FF0000;
}
svg .link.selected {
stroke: #FF0000;
}*/
svg marker {
overflow: visible;
}
svg .null-symbol {
fill: none;
stroke: black;
stroke-width: 3px;
}
</style>
<defs>
<linearGradient id="gradient">
<stop offset="5%" stop-color="#FFDC9E"></stop>
<stop offset="95%" stop-color="#FFF"></stop>
</linearGradient>
<linearGradient id="markerGradient">
<stop offset="5%" stop-color="rgb(97, 116, 255)"></stop>
<stop offset="95%" stop-color="#FFF"></stop>
</linearGradient>
<linearGradient id="reactionGradient">
<stop offset="5%" stop-color="#B0C0FF"></stop>
<stop offset="95%" stop-color="#FFF"></stop>
</linearGradient>
<marker case-sensitive="refX,refY" id="production" viewBox="0 0 10 10" markerWidth="10" markerHeight="10" orient="auto" refx="-2" refy="0" refX="-2" refY="0">
<path fill="url(#markerGradient)" stroke="#0013FF" transform="rotate(-90)" d="M0,2.0808957251439084L2.4028114141347543,-2.0808957251439084 -2.4028114141347543,-2.0808957251439084Z"></path>
</marker>
<marker case-sensitive="refX,refY" id="degradation" viewBox="0 0 10 10" markerWidth="10" markerHeight="10" orient="auto" refx="-2" refy="0" refX="-2" refY="0">
<path fill="url(#markerGradient)" stroke="#0013FF" transform="rotate(-90)" d="M0,2.0808957251439084L2.4028114141347543,-2.0808957251439084 -2.4028114141347543,-2.0808957251439084Z"></path>
</marker>
<marker case-sensitive="refX,refY" id="modifier" viewBox="0 0 10 10" markerWidth="30" markerHeight="30" orient="auto" refx="-0.4" refy="0" refX="-0.4" refY="0">
<path stroke="black" stroke-width="0.3" fill="none" d="M0,0.5641895835477563A0.5641895835477563,0.5641895835477563 0 1,1 0,-0.5641895835477563A0.5641895835477563,0.5641895835477563 0 1,1 0,0.5641895835477563Z"></path>
</marker>
</defs>
<g transform="translate(, )scale(1)">
<g>
<line class="reaction production link" marker-end="url(#production)" x1="449.9996697164325" y1="218.45791860388687" x2="451.42692033038736" y2="246.7481154723436">
</line><line class="reaction production link" marker-end="url(#production)" x1="399.21583821133174" y1="309.0153067725509" x2="345.33989421522693" y2="338.2824980727582">
</line>
</g>
<g>
<line class="reaction reactant link" x1="446.9075572254284" y1="157.1677217354301" x2="449.9996697164325" y2="218.45791860388687">
</line><line class="reaction reactant link" x1="453.0917822074366" y1="279.7481154723436" x2="399.21583821133174" y2="309.0153067725509">
</line>
</g>
<g>
</g>
<g draggable="" transform="translate(446.9075572254284,157.1677217354301)" style="position: relative; border: 1px solid red; background-color: rgb(211, 211, 211); cursor: pointer;">
<rect class="species node" fill="url(#gradient)" x="-50" y="-15" width="100" height="30" ry="15">
<title>ID: S1, Name: S1</title>
</rect>
<text class="node-label">S1</text>
</g><g draggable="" transform="translate(453.0917822074366,279.7481154723436)" style="position: relative; border: 1px solid red; background-color: rgb(211, 211, 211); cursor: pointer;">
<rect class="species node" fill="url(#gradient)" x="-50" y="-15" width="100" height="30" ry="15">
<title>ID: S2, Name: S2</title>
</rect>
<text class="node-label">S2</text>
</g><g draggable="" transform="translate(345.33989421522693,338.2824980727582)" style="position: relative; border: 1px solid red; background-color: rgb(211, 211, 211); cursor: pointer;">
<rect class="species node" fill="url(#gradient)" x="-50" y="-15" width="100" height="30" ry="15">
<title>ID: S3, Name: S3</title>
</rect>
<text class="node-label">S3</text>
</g>
<g draggable="" transform="translate(473.4770117242872,216.74146493626216)" style="position: relative; border: 1px solid red; background-color: rgb(211, 211, 211); cursor: pointer;">
<circle class="node reaction" fill="url(#reactionGradient)" r="5">
<title>ID: reaction1, Name: reaction1</title>
</circle>
<text class="node-label"></text>
</g><g draggable="" transform="translate(409.9633485910613,329.9478703486097)" style="position: relative; border: 1px solid red; background-color: rgb(211, 211, 211); cursor: pointer;">
<circle class="node reaction" fill="url(#reactionGradient)" r="5">
<title>ID: reaction2, Name: reaction2</title>
</circle>
<text class="node-label"></text>
</g>
</g>
</svg>
EDIT 1
Here is the style of the linearGradient element
EDIT 2
Style of the defs element
EDIT 3
I found that when I remove the head tag, and then reapply it, the SVG is then correctly rendered. Weird.
Turns out I had <base href="/"> in head which was messing things up.

Resources