Setattribute text parameters - javascript

I'm trying to add a text element to my dynamically created SVG chart so that I can have labels generated but can't make it work.
There is a WHILE loop for adding boxes for a chart. I use the same while loop for text labels and it isn't working, it makes the boxes also fail. When I remove text labels, it works perfectly.
Your help much appreciated.
<svg id="mysvg" width="1000" height="800"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="50" y="60" fill="black"
font-family="Arial, Helvetica, sans-serif"
font-size="28">Revenue and Expenses</text>
<line x1="150" y1="80" x2="150" y2="320"
style="stroke:rgb(155, 144, 144);stroke-width:5" />
<script type="application/ecmascript">
<![CDATA[
var mysvg = document.getElementById("mysvg");
var chartStart = [152, 84, 152]
var chartWidth = [100,64,36]
var chartNames = ["Revenue", "Expenses","Profit"]
var chartColor = ["#28CE6D","#DF3456","#4DC7EC"]
var num = chartNames.length;
while (num-- > 0)
{
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", chartStart[num]);
rect.setAttribute("y", [num] * 70 + 100);
rect.setAttribute("width", chartWidth[num]);
rect.setAttribute("height", "50");
rect.setAttribute("style", "fill:" + chartColor[num] + ";stroke:black;stroke-width:0;opacity:1");
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("x", "280");
text.setAttribute("y", [num] *70 + 130);
text.setAttribute("style", "fill:black");
text.setAttribute("font-family", "Arial, Helvetica, sans-serif");
text.setAttribute("font-size","18");
text.setAttribute("textContent", chartNames[num]);
mysvg.appendChild(rect);
mysvg.appendChild(text);
}
]]>
</script>
</svg>

Ok, found my own solution, I had not created a text node to append to the value for text element. Fixed it using the below. I'm sharing so that this question doesn't go unanswered. Thanks
<!DOCTYPE html>
<body>
<svg id="mysvg" width="1000" height="800"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="50" y="60" fill="black"
font-family="Arial, Helvetica, sans-serif"
font-size="28">Revenue and Expenses</text>
<line x1="150" y1="80" x2="150" y2="320"
style="stroke:rgb(155, 144, 144);stroke-width:5" />
<script type="application/ecmascript">
<![CDATA[
var mysvg = document.getElementById("mysvg");
var chartStart = [152, 84, 152]
var chartWidth = [100,64,36]
var chartNames = ["Revenue", "Expenses","Profit"]
var chartColor = ["#28CE6D","#DF3456","#4DC7EC"]
var num = chartNames.length;
while (num-- > 0)
{
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", chartStart[num]);
rect.setAttribute("y", [num] * 70 + 100);
rect.setAttribute("width", chartWidth[num]);
rect.setAttribute("height", "50");
rect.setAttribute("style", "fill:" + chartColor[num] + ";stroke:black;stroke-width:0;opacity:1");
var label = document.createElementNS("http://www.w3.org/2000/svg", "text");
label.setAttribute("x", "280");
label.setAttribute("y", [num] *70 + 130);
label.setAttribute("style", "fill:black");
label.setAttribute("font-family", "Arial, Helvetica, sans-serif");
label.setAttribute("font-size","18");
var txt = document.createTextNode(chartNames[num]);
label.appendChild(txt);
mysvg.appendChild(rect);
mysvg.appendChild(label);
}
]]>
</script>
</svg>
</body>
</html>

Related

dynamically setAttribute Style FILL using data variable

I have a set of arrays to set the start position, weidth and name of some chart elements in a SVG. What I haven't been able to achieve is setting the colour of each of those elements using HEX values from an array called chart_color.
Currently you'll see I've set the value of fill to green. What I tried and failed with is fill: chart_color[num].
<!DOCTYPE html>
<body>
<svg id="mysvg" width="1000" height="800"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="50" y="60" fill="black"
font-family="Arial, Helvetica, sans-serif"
font-size="28">Revenue and Expenses</text>
<line x1="150" y1="80" x2="150" y2="320"
style="stroke:rgb(155, 144, 144);stroke-width:5" />
<script type="application/ecmascript"> <![CDATA[
var mysvg = document.getElementById("mysvg");
var chart_start = [152, 84, 152]
var chart_width = [100,64,36]
var chart_names = ["Revenue", "Expenses","Profit"]
var chart_color = ["#28CE6D","#DF3456","#4DC7EC"]
var num = 3;
while (num-- > 0)
{
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", chart_start[num]);
rect.setAttribute("y", [num] * 70 + 100);
rect.setAttribute("width", chart_width[num]);
rect.setAttribute("height", "50");
rect.setAttribute("style", "fill:green;stroke:black;stroke-width:0;opacity:1");
mysvg.appendChild(rect);
}
]]></script>
</svg>
</body>
</html>
With style attributes you can actually assign them a value without using the setAttribute function:
rect.style.fill = chart_color[num]
But use this method consistently so that you don't override the style attribute, like setting color to "red" then setting style to "width:100px".
You just need to get the index (num) of the chart_color array and apply that as a variable within in your style declaration (breaking out of the string).
Note that you are also setting the border to stroke: black - but hte stroke width to 0 - So it can be seen I have amended that to stroke-width: 1 so that the border on each shows up.
<!DOCTYPE html>
<body>
<svg id="mysvg" width="1000" height="800"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="50" y="60" fill="black"
font-family="Arial, Helvetica, sans-serif"
font-size="28">Revenue and Expenses</text>
<line x1="150" y1="80" x2="150" y2="320"
style="stroke:rgb(155, 144, 144);stroke-width:5" />
<script type="application/ecmascript"> <![CDATA[
var mysvg = document.getElementById("mysvg");
var chart_start = [152, 84, 152]
var chart_width = [100,64,36]
var chart_names = ["Revenue", "Expenses","Profit"]
var chart_color = ["#28CE6D","#DF3456","#4DC7EC"]
var num = 3;
while (num-- > 0)
{
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", chart_start[num]);
rect.setAttribute("y", [num] * 70 + 100);
rect.setAttribute("width", chart_width[num]);
rect.setAttribute("height", "50");
rect.setAttribute("style", "fill:" + chart_color[num] + ";stroke:black;stroke-width:1;opacity:1");
mysvg.appendChild(rect);
}
]]></script>
</svg>
</body>
</html>

Tweak SVG viewBox behaviour via javascript

I am using vanilla javascript to navigate the pages of a comic book. However, I need to setup a condition that checks if the points in the current polygon intersects with the points in the next polygon. If true, I want the viewBox to animate from the current points to the next points, if false let nothing happen (use the default fade transition).
Here is a section of my code
var DELAY = 400;
function nextArea() {
if (isFirstPage() || areaIndex >= areas.length - 1) {
changePage(true);
changeArea();
} else {
fade();
areaIndex++;
setTimeout(changeArea, DELAY);
}
}
function prevArea() {
if (isLastPage() || areaIndex <= 0) {
changePage(false);
changeArea();
} else {
fade();
areaIndex--;
setTimeout(changeArea, DELAY);
}
}
function changeArea() {
if (isFirstPage() || isLastPage()) {
return;
}
var activeArea = areas[areaIndex];
var points = activeArea.getAttribute('points').split(' ');
var xy1 = points[0].split(',');
var xy2 = points[1].split(',');
var xy3 = points[2].split(',');
var box = [xy1[0], xy1[1], xy2[0] - xy1[0], xy3[1] - xy2[1]];
activePage.classList.remove('fade');
activePage.setAttribute('viewBox', box.join(' '));
activeRect = rects[pageIndex - 1];
activeRect.setAttribute('x', xy1[0]);
activeRect.setAttribute('y', xy1[1]);
}
My code repository is here: https://github.com/cnario/svg-carousel
Here is what I have thus far: https://cnario.github.io/svg-carousel/
Here is how I expect it to act: https://read.marvel.com/#book/41323
I suppose this is what you may need: a way to transition the viewBox from one value to another so that every time you have only one part of the svg in the viewBox.
let BB = {};
BB.tomato = tomato.getBBox();
BB.skyblue = skyblue.getBBox();
BB.gold = gold.getBBox();
let radios = document.querySelectorAll("#controls input");
radios.forEach(r =>{
let color = r.dataset.color;
let bb = BB[color];
r.addEventListener("change",()=>{
svg.setAttributeNS(null,"viewBox", `${bb.x} ${bb.y} ${bb.width} ${bb.height}`)
svg.style.height = `${bb.height * 300 / bb.width}px`;
})
})
svg {
width: 300px;
border: 1px solid;
height: 600px;
transition: height 1s;
}
<p id="controls">
<label>tomato: <input type="radio" name="selector" data-color="tomato" /></label>
<label>skyblue: <input type="radio" name="selector" data-color="skyblue" /></label>
<label>gold: <input type="radio" name="selector" data-color="gold" /></label>
</p>
<svg id="svg" viewBox="0 0 100 200">
<g id="tomato">
<circle cx="35" cy="70" r="25" fill="tomato" />
</g>
<g id="skyblue">
<ellipse cx="75" cy="160" rx="15" ry="35" fill="skyblue" />
</g>
<g id="gold">
<polygon fill="gold" points="75,15 60,30 90,30" />
</g>
</svg>

How to overlay Html elements over svg path

I need to place some html elements over my svg path. How can i do that ?
I looked up for foreignObject but it only allows for whole svg what about the path sections ?
Here is my svg code
<svg id="svg" width="50%" height="50%" fill="none" stroke="#000000" stroke-linejoin="round" enable_background="new 0 0 1000 589" pretty_print="False" version="1.1" viewBox="0 0 271.87 232.08" xmlns="http://www.w3.org/2000/svg">
<g fill="#f9f9f9" fill-rule="evenodd" stroke-width=".97063">
<path d="m109.29 15.045 0.2913-7.5709-3.106-0.0971-21.451-0.97063-21.548-1.3589-48.92-4.2708-3.009-0.29119-0.38825 3.4943-7.2797 75.127-0.67944 7.0856-2.7178 28.634 0.38826 0.0971 13.395 1.2618 1.2618-6.7944 2.4266-1.9413 27.178 2.4266h0.19413l-2.4266-4.7561 12.327 0.87357 30.769 1.7471 19.218 0.87357 3.3002-91.045 0.67944 0.0971 0.0971-2.6207z" data-id="NM" data-name="New Mexico"/>
<path d="m246.35 13.201-0.19413-2.6207-0.0971-2.5236-0.19413-2.5236-3.6884 0.29119-37.563 1.7471-52.705 0.77651-22.519-0.29119-4.1737-0.0971h-1.553l-6.115-0.19413-1.9413-0.0971-4.0766-0.0971-1.9413-0.0971-0.2913 7.5709-0.0971 2.6207h0.58238l23.489 0.58238 24.848 0.29119 0.29119 33.196 1.7471 5.8238 3.8825 3.6884 4.1737 0.19413 0.87356-1.7471 5.7267 5.2414 7.4739 0.7765 1.3589 1.553 2.7178-1.2618 6.7944 3.2031v1.8442l2.5236-0.0971 2.6207-2.2324 4.8532 3.106 4.562 1.6501 3.106-4.2708 9.9004 4.659 3.6884-3.009 3.009-1.1648 2.4266 0.58238 9.1239-2.6207 4.8532 2.0383 4.3678 2.8148 3.7855 0.67944h0.0971l-0.0971-4.3678-1.0677-26.401-0.0971-4.3678-3.7855-19.607-0.58238-2.7178-0.0971-2.5236z" data-id="OK" data-name="Oklahoma"/>
<path d="m210.82 227.22-4.659-17.568v3.3002zm-1.0677-30.866-3.3002 6.212-0.38825 2.0383zm2.6207-4.562 3.106-4.0767-2.2324 1.3589zm10.968-9.9004-7.2797 3.7855 2.0383-0.38825zm0.97063-1.3589 2.0383-1.6501-0.7765 0.19413zm-115.12-162.87-0.67944-0.0971-3.3002 91.045-19.218-0.87357-30.769-1.7471-12.327-0.87357 2.4266 4.7561 10.58 10.58 6.0179 7.0856 7.9592 5.9208 5.6297 10.289 2.1354 10.774 4.562 3.009 3.5913 3.9796 5.1443 1.8442 7.4739 4.7561 3.3972 1.2618 4.659-4.659 1.456-4.9502 2.4266-4.7561 7.5709-3.009 2.9119 1.4559 8.4445 0.67945 7.668 4.7561 5.2414 0.97063-1.456 2.7178 3.009 1.9413 2.8148 3.3972 0.58238 3.5913 1.8442 2.4266 4.2708 10.289 4.2708 3.5913 3.3002 5.4355 4.1737 4.2708 1.8442 0.58238 1.553 11.065 4.562 2.5236 0.19412 3.4943 1.1648-0.29119 7.9592 9.7063 3.9796 0.87357 5.0473 3.009h7.765l5.6297 3.106 6.6974-1.4559-3.009-2.8148-2.7178-8.1533-1.0677-7.0856-1.553-2.3295 0.67944-4.7561-2.0383-0.19413-2.7178-4.4649 3.106 3.3002 3.5913-1.2618 1.9413-5.1444-3.8825-5.2414 5.8238 0.67944 2.7178-4.1737-0.38825-1.456 2.4266-3.2031-0.58238 2.8148 2.7178-2.1354-1.0677-3.7855 3.4943 1.8442 4.4649-2.5236-4.3678-4.562 2.7178 1.0677 5.0473 0.29119 6.6003-1.456 7.3768-4.9502 4.4649-3.6884 0.67944-2.7178 2.7178-2.8148-1.456-4.659 0.29119-2.9119 4.8532-2.1354-0.38826 5.1444h2.9119l-3.2031 2.7178 12.909-6.7944 2.1354-0.0971 1.3589-6.212h0.38826l1.4559-3.5913 0.67944-11.065 0.87357-4.4649-2.5236-7.9592-3.106-5.4355-0.0971-2.6207-3.2031-4.4649-1.9413-18.733-0.0971-2.3295-0.19413-2.4266-0.58238-8.5416-5.8238 0.19413-1.456-1.553-0.29119-0.0971h-0.0971l-3.7855-0.67944-4.3678-2.8148-4.8532-2.0383-9.1239 2.6207-2.4266-0.58238-3.009 1.1648-3.6884 3.009-9.9004-4.659-3.106 4.2708-4.562-1.6501-4.8532-3.106-2.6207 2.2324-2.5236 0.0971v-1.8442l-6.7944-3.2031-2.7178 1.2618-1.3589-1.553-7.4739-0.7765-5.7267-5.2414-0.87356 1.7471-4.1737-0.19413-3.8825-3.6884-1.7471-5.8238-0.29119-33.196-24.848-0.29119-23.489-0.58238h-0.58238z" data-id="TX" data-name="Texas"/>
</g>
</svg>
You need to find the center of a path in pixels in a resizable svg element. For this you need:
to find the center of a path in svg units
convert the svg units in pixels
repeat on resize
Please read the comments on my code.
In my code the div #label is just a point. If you need to add text to the div you'll need to take in account the width and the height of the div.
// the values of the svg viewBox
svgVB = { x: 0, y: 0, w: 271.87, h: 232.08 };
//the bounding box for the path id="NM"
let BB = NM.getBBox();
//the center of the path in svg units
let center = {};
center.x = BB.x + BB.width / 2;
center.y = BB.y + BB.height / 2;
//the center of the path in html units
let htmlCenter = {};
// a function to get the position of the div
function positionDiv() {
//first get the size and the position of the svg element
let SVGClientRect = svg.getBoundingClientRect();
//calculate the htmlCenter x
htmlCenter.x = map(
center.x,
svgVB.x,
svgVB.w,
SVGClientRect.x,
SVGClientRect.x + SVGClientRect.width
);
//calculate the htmlCenter y
htmlCenter.y = map(
center.y,
svgVB.y,
svgVB.h,
SVGClientRect.y,
SVGClientRect.y + SVGClientRect.height
);
// set the styles for the label
label.style.left = htmlCenter.x + "px";
label.style.top = htmlCenter.y + "px";
}
//call the positionDiv function
positionDiv();
//call the positionDiv function on resize
window.setTimeout(function() {
positionDiv();
window.addEventListener("resize", positionDiv, false);
}, 15);
function map(n, a, b, _a, _b) {
let d = b - a;
let _d = _b - _a;
let u = _d / d;
return _a + n * u;
}
svg {
border: 1px solid;
}
#label {
width: 5px;
height: 5px;
border-radius: 50%;
background: red;
position: absolute;
}
<svg id="svg" width="50%" height="50%" fill="none" stroke="#000000" stroke-linejoin="round" enable_background="new 0 0 1000 589" pretty_print="False" version="1.1" viewBox="0 0 271.87 232.08" xmlns="http://www.w3.org/2000/svg">
<g fill="#f9f9f9" fill-rule="evenodd" stroke-width=".97063">
<path d="m109.29 15.045 0.2913-7.5709-3.106-0.0971-21.451-0.97063-21.548-1.3589-48.92-4.2708-3.009-0.29119-0.38825 3.4943-7.2797 75.127-0.67944 7.0856-2.7178 28.634 0.38826 0.0971 13.395 1.2618 1.2618-6.7944 2.4266-1.9413 27.178 2.4266h0.19413l-2.4266-4.7561 12.327 0.87357 30.769 1.7471 19.218 0.87357 3.3002-91.045 0.67944 0.0971 0.0971-2.6207z" id="NM" data-name="New Mexico"/>
<path d="m246.35 13.201-0.19413-2.6207-0.0971-2.5236-0.19413-2.5236-3.6884 0.29119-37.563 1.7471-52.705 0.77651-22.519-0.29119-4.1737-0.0971h-1.553l-6.115-0.19413-1.9413-0.0971-4.0766-0.0971-1.9413-0.0971-0.2913 7.5709-0.0971 2.6207h0.58238l23.489 0.58238 24.848 0.29119 0.29119 33.196 1.7471 5.8238 3.8825 3.6884 4.1737 0.19413 0.87356-1.7471 5.7267 5.2414 7.4739 0.7765 1.3589 1.553 2.7178-1.2618 6.7944 3.2031v1.8442l2.5236-0.0971 2.6207-2.2324 4.8532 3.106 4.562 1.6501 3.106-4.2708 9.9004 4.659 3.6884-3.009 3.009-1.1648 2.4266 0.58238 9.1239-2.6207 4.8532 2.0383 4.3678 2.8148 3.7855 0.67944h0.0971l-0.0971-4.3678-1.0677-26.401-0.0971-4.3678-3.7855-19.607-0.58238-2.7178-0.0971-2.5236z" id="OK" data-name="Oklahoma"/>
<path d="m210.82 227.22-4.659-17.568v3.3002zm-1.0677-30.866-3.3002 6.212-0.38825 2.0383zm2.6207-4.562 3.106-4.0767-2.2324 1.3589zm10.968-9.9004-7.2797 3.7855 2.0383-0.38825zm0.97063-1.3589 2.0383-1.6501-0.7765 0.19413zm-115.12-162.87-0.67944-0.0971-3.3002 91.045-19.218-0.87357-30.769-1.7471-12.327-0.87357 2.4266 4.7561 10.58 10.58 6.0179 7.0856 7.9592 5.9208 5.6297 10.289 2.1354 10.774 4.562 3.009 3.5913 3.9796 5.1443 1.8442 7.4739 4.7561 3.3972 1.2618 4.659-4.659 1.456-4.9502 2.4266-4.7561 7.5709-3.009 2.9119 1.4559 8.4445 0.67945 7.668 4.7561 5.2414 0.97063-1.456 2.7178 3.009 1.9413 2.8148 3.3972 0.58238 3.5913 1.8442 2.4266 4.2708 10.289 4.2708 3.5913 3.3002 5.4355 4.1737 4.2708 1.8442 0.58238 1.553 11.065 4.562 2.5236 0.19412 3.4943 1.1648-0.29119 7.9592 9.7063 3.9796 0.87357 5.0473 3.009h7.765l5.6297 3.106 6.6974-1.4559-3.009-2.8148-2.7178-8.1533-1.0677-7.0856-1.553-2.3295 0.67944-4.7561-2.0383-0.19413-2.7178-4.4649 3.106 3.3002 3.5913-1.2618 1.9413-5.1444-3.8825-5.2414 5.8238 0.67944 2.7178-4.1737-0.38825-1.456 2.4266-3.2031-0.58238 2.8148 2.7178-2.1354-1.0677-3.7855 3.4943 1.8442 4.4649-2.5236-4.3678-4.562 2.7178 1.0677 5.0473 0.29119 6.6003-1.456 7.3768-4.9502 4.4649-3.6884 0.67944-2.7178 2.7178-2.8148-1.456-4.659 0.29119-2.9119 4.8532-2.1354-0.38826 5.1444h2.9119l-3.2031 2.7178 12.909-6.7944 2.1354-0.0971 1.3589-6.212h0.38826l1.4559-3.5913 0.67944-11.065 0.87357-4.4649-2.5236-7.9592-3.106-5.4355-0.0971-2.6207-3.2031-4.4649-1.9413-18.733-0.0971-2.3295-0.19413-2.4266-0.58238-8.5416-5.8238 0.19413-1.456-1.553-0.29119-0.0971h-0.0971l-3.7855-0.67944-4.3678-2.8148-4.8532-2.0383-9.1239 2.6207-2.4266-0.58238-3.009 1.1648-3.6884 3.009-9.9004-4.659-3.106 4.2708-4.562-1.6501-4.8532-3.106-2.6207 2.2324-2.5236 0.0971v-1.8442l-6.7944-3.2031-2.7178 1.2618-1.3589-1.553-7.4739-0.7765-5.7267-5.2414-0.87356 1.7471-4.1737-0.19413-3.8825-3.6884-1.7471-5.8238-0.29119-33.196-24.848-0.29119-23.489-0.58238h-0.58238z" id="TX" data-name="Texas"/>
</g>
</svg>
<div id="label"></div>
You need to add an id to your path
<path id="my-text" .......... />
aftet that, inside your svg tags put:
<text>
<textPath xlink:href="#text">text on a path</textPath>
</text>
you use the same id you used for that path in the href=""
Hope this helps!
this article also may help you out! https://vanseodesign.com/web-design/svg-text-on-a-path-part-1/
for putting elements in your svg:
The only way i found was using <foreignObject>
example:
<svg>
....
....
<foreignObject>
<div> your content</div>
</foreignObject>
</svg>
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject this article can you more about that. There are ways yo position with x and y attributes.

Render SVG to PNG using JavaScript

The following HTML element is on my page:
<canvas id="canvas" width=400 height=400 />
And I am trying to render the following tag as a PNG.
<div style="font-size=40px">
Fun with d3.js
</div>
My JavaScript function is as follows. It should be rendering the tag containing the text "Fun with d3.js" as an image in the canvas, however, it is not being rendered. But, if I insert the raw HTML elements using devtools, the SVG renders as legitimate. Somewhere in translation the Javascript seems to be losing the html element, but for the life of me cannot figure out why. TThe img.onerror event is being called but provides very little in terms of useful information.
renderToPNG: function() {
var myCanvas = document.getElementById("canvas");
var context = myCanvas.getContext("2d");
var data =
'<svg width=\"400\" height=\"400\">' +
' <foreignObject width=\"100%\" height=\"100%\">' +
' <div style=\"font-size=40px\">' +
' Fun with d3.js' +
' </div>' +
' </foreignObject>' +
'</svg>';
var domURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type:"image/svg+xml;charset=utf-8"});
var url = domURL.createObjectURL(svg);
img.onload = function() {
context.drawImage(img, 0, 0);
domURL.revokeObjectURL(url);
}
img.src = url;
}
I tried running your code and it turns out the foreignObject doesn't work for some reason. So that might be at the root of the problem.
It also depends on which browser you are using. Take a look at the snippet, it shows the SVG, the Canvas, and the Image, and you can see each of them having different problems (I see the canvas distorted on Chrome, and on Safari it doesn't even show).
function renderToPNG() {
var myCanvas = document.getElementById("canvas");
var context = myCanvas.getContext("2d");
var data =
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
'<svg version="1.1"' +
' baseProfile="full"' +
' width="200" height="200"' +
' xmlns="http://www.w3.org/2000/svg">' +
' <foreignObject width="100%" height="100%">' +
' <div style="font-size=40px; color: black">' +
' Fun with d3.js' +
' </div>' +
' </foreignObject>' +
' <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />' +
'</svg>';
var domURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {
type: "image/svg+xml;charset=utf-8"
});
var url = domURL.createObjectURL(svg);
img.onload = function() {
context.drawImage(img, 0, 0);
domURL.revokeObjectURL(url);
}
img.src = url;
console.debug(img);
$('#image').append(img);
}
renderToPNG();
#svg,
#canvas,
#image {
border: 1px solid;
width: 200px;
height: 200px;
display: inline-block;
vertical-align: bottom;
}
#svg {
border-color: red
}
#canvas {
border-color: green
}
#image {
border-color: blue
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg id="svg" version="1.1" baseProfile="full" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<foreignObject width="100%" height="100%">
<div style="font-size:40px; color: black">
Fun with d3.js
</div>
</foreignObject>
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<canvas id="canvas" width="200" height="200"></canvas>
<div id="image"></div>
One thing to notice: I added the SVG doctype declaration on the JS code since that's how it's supposed to work when using the SVG as source for an Image (it acts as if it was an external file).
Just my two cents. Hoping for a better answer...

Dynamic SVG linear gradient when using JavaScript

I can get this working successfully within the html body, example...
<div id="myContainer" style="float: left; background-color: Blue; height: 100px;
width: 100px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%">
<defs>
<lineargradient id="myLinearGradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop id="start" offset="50%" style="stop-color: White; stop-opacity: 1" />
<stop id="stop" offset="60%" style="stop-color: #99cd9f; stop-opacity: 1" />
</lineargradient>
</defs>
<circle cx="50px" cy="50px" r="50px" fill="url(#myLinearGradient)" />
</svg>
</div>
However, I need to create this dynamically using javascript. Creating just the circle works fine, it's when I point the circle's Fill to the lineargradient it fails - I just get a black circle.
I think I'm not setting the stop 'style' attribute correctly. I have tried an alternative way to no avail, see below...
I'm using Chrome, and thanks in advance!
Within the body tages:
<body>
<div style="float: left; background-color: Blue; height: 100px;
width: 100px;">
<svg id="Svg1" xmlns="http://www.w3.org/2000/svg">
<defs id="mydefs">
</defs>
</svg>
</div>
</body>
My script:
<script>
// lineargradient
var myLinearGradient = document.createElementNS("http://www.w3.org/2000/svg", "lineargradient");
myLinearGradient.setAttribute("id", "myLGID");
myLinearGradient.setAttribute("x1", "0%");
myLinearGradient.setAttribute("x2", "0%");
myLinearGradient.setAttribute("y1", "0%");
myLinearGradient.setAttribute("y2", "100%");
document.getElementById("mydefs").appendChild(myLinearGradient);
//stops
var stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
stop1.setAttribute("id", "myStop1");
stop1.setAttribute("offset", "70%");
//stop1.setAttribute("style", "stop-color: White; stop-opacity: 1");
stop1.setAttribute("stop-color", "White");
document.getElementById("mydefs").appendChild(stop1);
var stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
stop2.setAttribute("id", "myStop2");
stop2.setAttribute("offset", "80%");
//stop2.setAttribute("style", "stop-color: #99cd9f; stop-opacity: 1");
stop2.setAttribute("stop-color", "#99cd9f");
document.getElementById("mydefs").appendChild(stop2);
// Circle
var myCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
myCircle.setAttribute("id", "idCircle");
myCircle.setAttribute("cx", "50px");
myCircle.setAttribute("cy", "50px");
myCircle.setAttribute("r", "50px");
myCircle.setAttribute("fill", "url(#myLGID)");
document.getElementById("Svg1").appendChild(myCircle);
</script>
Two things:
The element name for linear gradients is linearGradient, not lineargradient.
You have to append the stops to the linearGradient element, not the defs element.
See this codepen for an MIT-licensed example:
// Store the SVG namespace for easy reuse.
var svgns = 'http://www.w3.org/2000/svg';
// Create <svg>, <defs>, <linearGradient> and <rect> elements using createElementNS to apply the SVG namespace.
// (https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS)
var svg = document.createElementNS(svgns, 'svg');
var defs = document.createElementNS(svgns, 'defs');
var gradient = document.createElementNS(svgns, 'linearGradient');
var rect = document.createElementNS(svgns, 'rect');
// Store an array of stop information for the <linearGradient>
var stops = [
{
"color": "#2121E5",
"offset": "0%"
},{
"color": "#206DFF",
"offset": "100%"
}
];
// Parses an array of stop information and appends <stop> elements to the <linearGradient>
for (var i = 0, length = stops.length; i < length; i++) {
// Create a <stop> element and set its offset based on the position of the for loop.
var stop = document.createElementNS(svgns, 'stop');
stop.setAttribute('offset', stops[i].offset);
stop.setAttribute('stop-color', stops[i].color);
// Add the stop to the <lineargradient> element.
gradient.appendChild(stop);
}
// Apply the <lineargradient> to <defs>
gradient.id = 'Gradient';
gradient.setAttribute('x1', '0');
gradient.setAttribute('x2', '0');
gradient.setAttribute('y1', '0');
gradient.setAttribute('y2', '1');
defs.appendChild(gradient);
// Setup the <rect> element.
rect.setAttribute('fill', 'url(#Gradient)');
rect.setAttribute('width', '100%');
rect.setAttribute('height', '100%');
// Assign an id, classname, width and height
svg.setAttribute('width', '100%');
svg.setAttribute('height', '100%')
svg.setAttribute('version', '1.1');
svg.setAttribute('xmlns', svgns);
// Add the <defs> and <rect> elements to <svg>
svg.appendChild(defs);
svg.appendChild(rect);
// Add the <svg> element to <body>
document.body.appendChild(svg);

Categories

Resources