Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw gradient arc using d3.js?

I have started using d3.js. I have following requirement

Requirement:

enter image description here

What I have tried?

fiddle

Question?

How to achieve gradient as same as above image.

Any suggestion or idea will be grateful.

Note

I am just started d3.js.

like image 333
karthick Avatar asked Aug 10 '15 06:08

karthick


1 Answers

Edit - changed data structure and fiddle link to represent unfilled chunk at the beginning.

I would use the pie function in d3 to create a pie chart. The image above is basically a pie with two different gradient styles applied to the pie chunks. A red linear gradient and a black/white radial gradient.

I created a fiddle linked below to show you an example. The key here is that you need to structure your data to also include the percentage that should not have the red-gradient applied. Using the example above, we have three chunks with red and the rest as unfilled. Imagine the data set like so:

    var data = [{
    percent: 10,
    pie: 0
}, {
    percent: 13,
    pie: 1
}, {
    percent: 13,
    pie: 1
}, {
    percent: 6,
    pie: 1
}, {
    percent: 56,
    pie: 0
}];

So we have the percent and we also flag which chunks should be red and which chunk should be the unfilled section using the pie attribute.

You can use whatever data set you wish but I'm just using this as an example.

So next thing is to create your SVG element:

 var width = 400;
    var height = 400;
    var radius = Math.min(width, height) / 2;

    var arc = d3.svg.arc()
     .outerRadius(radius - 10)
     .innerRadius(((radius - 10) / 5) * 4);


    var pie = d3.layout.pie()
    .sort(null)
    .value(function (d) { return d.percent });

    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

and after this we will create the two gradients to style the pie chunks. So first one is the linear red gradient:

// append a defs tag to SVG, This holds all our gradients and can be used
//by any element within the SVG we append it to
var defs = svg.append("svg:defs")

//next we append a linear gradient 
var red_gradient = defs.append("svg:linearGradient")
  .attr("id", "gradient")
  .attr("x1", "0%")
  .attr("y1", "0%")
  .attr("x2", "0%")
  .attr("y2", "100%")
  .attr("spreadMethod", "pad");

//first dark red color
    red_gradient.append("svg:stop")
        .attr("offset", "0%")
        .attr("stop-color", "rgb(221,48,2)")
        .attr("stop-opacity", 1);
//second light red color
    red_gradient.append("svg:stop")
        .attr("offset", "100%")
        .attr("stop-color", "rgb(247, 78, 1)")
        .attr("stop-opacity", 1);

Then we append the radial gradient for the unfilled part. This one is a little tricker because we need to move the gradient with a transform to get the right radial center. If you translate it half the width and height I think it should work out.

var radial_gradient = defs.append("radialGradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", '50%')
.attr("cy", '50%')
.attr("r", "75%")
.attr("fx", '50%')
.attr("fy", '50%')
.attr('gradientTransform', "translate(-200,-200)")
.attr("id", 'gradient2');
 radial_gradient.append("stop").attr("offset", "0%").style("stop-color", "black");
 radial_gradient.append("stop").attr("offset", "55%").style("stop-color", "white");
 radial_gradient.append("stop").attr("offset", "95%").style("stop-color", "black");

Once we have set up the gradients, we can add the pie:

   var g = svg.selectAll(".arc")
     .data(pie(data))
     .enter().append("g")
     .attr("class", "arc");

    // we create a function to append the different chucks of the pie. 
    // we check the pie attribute from the data and apply the correct gradient.

    g.append("path")
    .attr("d", arc)
    .style("fill", function (d) {
        if (d.data.pie === 1) {
            console.log('true' + d.data.pie);
            return "url(#gradient)"
        }
        else {
            console.log('false' + d.data.pie);
            return "url(#gradient2)"
        }
    })

JSFiddle: http://jsfiddle.net/staceyburnsy/afo292ty/2/

like image 52
Stacey Burns Avatar answered Oct 04 '22 22:10

Stacey Burns