Reputation: 3
I'm trying to create an funnel chart like this with svg. https://i.sstatic.net/hUyru.jpg
My first attempt was with svg filter effects, but then I found out that svg filter effects aren't supported in IE.
The second attempt was with svg paths but I can't manage to transform the path based on the previous circle.
http://codepen.io/justpixel/pen/MwOLRQ
<path transform="translate(0 27) scale(0.9 0.6)" fill="#ED1C24" d="M240.208,110.922c-43.5-29-140.417,19.125-175.322,19.125V0c34.906,0,131.822,50.422,175.333,18.667
L240.208,110.922z"/>
Do you have any tips on how can I do this?
Upvotes: 0
Views: 1044
Reputation: 101830
It's quite simple. as long as you know how to create SVG elements with JS - and you know a little bit of trigonometry.
var svgns = "http://www.w3.org/2000/svg";
// Make the graph
var radius = [88, 66, 56, 27];
var inter_circle_gap = 80;
var startX = 120;
var startY = 120;
var funnelSqueezeFactor = 0.3;
// Draw the funnels
var g = document.getElementById("funnels");
var x = startX; // centre of first circle
var numFunnels = radius.length - 1;
for (var i=0; i<numFunnels; i++)
{
nextX = x + radius[i] + inter_circle_gap + radius[i+1];
makeFunnel(g, x, nextX, startY, radius[i], radius[i+1]);
x = nextX;
}
// Draw the circles
var g = document.getElementById("circles");
var x = startX - radius[0]; // left edge of first circle
for (var i=0; i<radius.length; i++)
{
x += radius[i]; // centre X for this circle
makeCircle(g, x, startY, radius[i]);
x += radius[i] + inter_circle_gap; // step to left edge of next circle
}
// Function to make a circle
function makeCircle(g, x, y, r)
{
var circle = document.createElementNS(svgns, "circle");
circle.setAttribute("cx", x);
circle.setAttribute("cy", y);
circle.setAttribute("r", r);
g.appendChild(circle);
}
// Function to make a funnel
function makeFunnel(g, x1, x2, y, r1, r2)
{
var tangentAngle = 30 * Math.PI / 180;; // 30 degrees
startPointX = r1 * Math.sin(tangentAngle);
startPointY = r1 * Math.cos(tangentAngle);
endPointX = r2 * Math.sin(tangentAngle);
endPointY = r2 * Math.cos(tangentAngle);
ctrlPointX = (x1 + x2) / 2;
ctrlPointY = (startPointY + endPointY) * funnelSqueezeFactor / 2;
var d = 'M' + (x1 + startPointX) + ',' + (y - startPointY);
d += ' Q' + ctrlPointX + ',' + (y - ctrlPointY) + ','
+ (x2 - endPointX) + ',' + (y - endPointY);
d += ' L' + (x2 - endPointX) + ',' + (y + endPointY);
d += ' Q' + ctrlPointX + ',' + (y + ctrlPointY) + ','
+ (x1 + startPointX) + ',' + (y + startPointY);
d += "Z";
var path = document.createElementNS(svgns, "path");
path.setAttribute("d", d);
g.appendChild(path);
}
#circles circle {
fill: #27293d;
}
#funnels path {
fill: #f5d135;
}
<svg width="779px" height="306px">
<g id="funnels"></g>
<g id="circles"></g>
</svg>
Upvotes: 1