使用 d3.js 拼出多层饼图的效果

Piece out effect for Multilayer pie Chart using d3.js

我有一个不同内径的多层饼图,如下所示:

上面饼图的代码可以在这里找到:

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

        var color = d3.scale.ordinal()
            .range(["cyan", "green", "blue", "brown", "violet", "orange", "purple"]);
    var arcMajor = d3.svg.arc()
        .outerRadius(function (d) {
            return radius - 20;
        })
        .innerRadius(0);
    //this for making the minor arc
    var arcMinor = d3.svg.arc()
        .outerRadius(function (d) {
            // scale for calculating the radius range([20, radius - 40])
            var s = scale((d.data.major - d.data.minor));
            if (s > radius - 20) {
                return radius - 20;
            }

            return scale(d.data.major - d.data.minor);
        })
        .innerRadius(0);
    var labelr = 260;
    var pie = d3.layout.pie()
        .sort(null)
        .value(function (d) {
            return d.major;
        });


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

    data = [{
        major: 500,
        minor: 250,
        grp: 1
    }, {
        major: 100,
        minor: 80,
        grp: 2
    }, {
        major: 100,
        minor: 50,
        grp: 3
    }, {
        major: 100,
        minor: 60,
        grp: 4
    }, {
        major: 100,
        minor: 10,
        grp: 5
    }];
    var scale = d3.scale.linear()
    .range([d3.min(data, function (d) {
        return d.minor;
    }), radius - 100 - d3.max(data, function (d) {
        return d.minor / d.major;
    })])
    //setting the scale domain
    .domain([d3.min(data, function (d) {
        return d.minor;
    }), d3.max(data, function (d) {
        return d.minor;
    })]);

    var g = svg.selectAll(".arc")
        .data(pie(data))
        .enter().append("g")
        .attr("class", "arc");
    g.append("svg:text")
.attr("transform", function (d) {
    var c = arcMajor.centroid(d),
        x = c[0],
        y = c[1],
        // pythagorean theorem for hypotenuse
        h = Math.sqrt(x * x + y * y);
    return "translate(" + (x / h * labelr) + ',' +
       (y / h * labelr) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
    // are we past the center?
    return (d.endAngle + d.startAngle) / 2 > Math.PI ?
        "end" : "start";
})
.text(function (d, i) { return d.value.toFixed(2); });
    //this makes the major arc
    g.append("path")
        .attr("d", function (d) {
            return arcMajor(d);
        })
        .style("fill", function (d) {
            return d3.rgb(color(d.data.grp));
        });

    //this makes the minor arcs
    g.append("path")
        .attr("d", function (d) {
            return arcMinor(d);
        })
        .style("fill", function (d) {
            return d3.rgb(color(d.data.grp)).darker(2);//for making the inner path darker
        });

http://jsfiddle.net/6e8aue0h/10/

我想给这个馅饼添加拼图功能。像这样:

我试过使用 d3-pie 插件,但没用。

当您将鼠标悬停在特定部分时,它应该如下图所示得到饼图。 https://github.com/dansdom/plugins-d3-pie

在这种特殊情况下我该如何实施?

非常感谢。

在这里,我以类似的方式为主要馅饼添加了分割效果,您可以为内部馅饼添加。我在变量

上添加了圆弧
var arcOver = d3.svg.arc()
        .outerRadius(radius + 9);

主弧的 mouseenter 和 mouseout 函数。

.on("mouseenter", function(d) {

            d3.select(this)
               .attr("stroke","white")
               .transition()
               .duration(1000)
               .attr("d", arcOver)             
               .attr("stroke-width",6);
        })
        .on("mouseleave", function(d) {
            d3.select(this).transition()            
               .attr("d", arcMajor)
               .attr("stroke","none");
        })

这是示例。

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

        var color = d3.scale.ordinal()
            .range(["cyan", "green", "blue", "brown", "violet", "orange", "purple"]);

        var arcMajor = d3.svg.arc()
            .outerRadius(function (d) {
                return radius - 20;
            })
            .innerRadius(0);

   var arcOver = d3.svg.arc()
        .outerRadius(radius + 9);
        //this for making the minor arc
        var arcMinor = d3.svg.arc()
            .outerRadius(function (d) {
                // scale for calculating the radius range([20, radius - 40])
                var s = scale((d.data.major - d.data.minor));
                if (s > radius - 20) {
                    return radius - 20;
                }

                return scale(d.data.major - d.data.minor);
            })
            .innerRadius(0);

  var arcOverMin = d3.svg.arc()
        .outerRadius(radius - 90 );

  // Define the div for the tooltip
        var div = d3.select("body").append("div") 
            .attr("class", "tooltip")    
            .style("opacity", 0);
  
        var labelr = 260;
        var pie = d3.layout.pie()
            .sort(null)
            .value(function (d) {
                return d.major;
            });


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

        data = [{
            major: 500,
            minor: 250,
            grp: 1
        }, {
            major: 100,
            minor: 80,
            grp: 2
        }, {
            major: 100,
            minor: 50,
            grp: 3
        }, {
            major: 100,
            minor: 60,
            grp: 4
        }, {
            major: 100,
            minor: 10,
            grp: 5
        }];
        var scale = d3.scale.linear()
        .range([d3.min(data, function (d) {
            return d.minor;
        }), radius - 100 - d3.max(data, function (d) {
            return d.minor / d.major;
        })])
        //setting the scale domain
        .domain([d3.min(data, function (d) {
            return d.minor;
        }), d3.max(data, function (d) {
            return d.minor;
        })]);

        var g = svg.selectAll(".arc")
            .data(pie(data))
            .enter().append("g")
            .attr("class", "arc");
        g.append("svg:text")
    .attr("transform", function (d) {
        var c = arcMajor.centroid(d),
            x = c[0],
            y = c[1],
            // pythagorean theorem for hypotenuse
            h = Math.sqrt(x * x + y * y);
        return "translate(" + (x / h * labelr) + ',' +
           (y / h * labelr) + ")";
    })
    .attr("dy", ".35em")
    .attr("text-anchor", function (d) {
        // are we past the center?
        return (d.endAngle + d.startAngle) / 2 > Math.PI ?
            "end" : "start";
    })
    .text(function (d, i) { return d.value.toFixed(2); });
        //this makes the major arc
        g.append("path")
            .attr("d", function (d) {
                return arcMajor(d);
            })
            .on("mouseenter", function(d) {
           
            d3.select(this)
               .attr("stroke","white")
               .transition()
               .duration(1000)
               .attr("d", arcOver)             
               .attr("stroke-width",6);
            
               div.transition()  
                .duration(200)  
                .style("opacity", .9);  
              div.html(
                  '<a href= "http://facebook.com">' + // The first <a> tag
     d.data.major +
    "</a>"
                  + "<br/>"  + d.data.minor) 
                .style("left", (d3.event.pageX) + "px")  
                .style("top", (d3.event.pageY - 28) + "px"); 
           
        })
        .on("mouseleave", function(d) {
            d3.select(this).transition()            
               .attr("d", arcMajor)
               .attr("stroke","none");
        })
            .style("fill", function (d) {
                return d3.rgb(color(d.data.grp));
            });

        //this makes the minor arcs
        g.append("path")
            .attr("d", function (d) {
                return arcMinor(d);
            })
          .on("mouseenter", function(d) {
           
            d3.select(this)
               .attr("stroke","white")
               .transition()
               .duration(1000)
               .attr("d", arcOverMin)             
               .attr("stroke-width",6);
        })
        .on("mouseleave", function(d) {
            d3.select(this).transition()            
               .attr("d", arcMinor)
               .attr("stroke","none");
        })
            .style("fill", function (d) {
                return d3.rgb(color(d.data.grp)).darker(2);//for making the inner path darker
            });
.arc text {
    font: 10px sans-serif;
    text-anchor: middle;
}
.arc path {
    stroke: #fff;
}
div.tooltip { 
    position: absolute;   
    text-align: center;   
    width: 60px;     
    height: 28px;     
    padding: 2px;    
    font: 12px sans-serif;  
    background: lightsteelblue; 
    border: 0px;  
    border-radius: 8px;    
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

您只需增加 outerRadius 弧度即可实现此效果。

希望对您有所帮助。

 var arcMajorOver = d3.svg.arc()
   .outerRadius(function(d) {
     return radius - 10;
   });

 var arcMinorOver = d3.svg.arc()
   .outerRadius(function(d) {
     var s = scale((d.data.major - d.data.minor));
     if (s > radius - 20) {
       return radius - 20;
     }    
     return scale(d.data.major - d.data.minor) + 10;
   });

 //this makes the major arc
 g.append("path")
   .attr("d", function(d) {
     return arcMajor(d);
   })
   .style("fill", function(d) {
     return d3.rgb(color(d.data.grp));
   }).on("mouseenter", function(d) {
     d3.select(this)
       .attr("stroke", "white")
       .transition()
       .duration(1000)
       .attr("d", arcMajorOver)
       .style("stroke-width",6);
   })
   .on("mouseleave", function(d) {
     d3.select(this).transition()
       .attr("d", arcMajor)
       .style("stroke-width",0);
   });;;

 //this makes the minor arcs
 g.append("path")
   .attr("d", function(d) {
     return arcMinor(d);
   })
   .style("fill", function(d) {
     return d3.rgb(color(d.data.grp)).darker(2); //for making the inner path darker
   }).on("mouseenter", function(d) {
     d3.select(this)
       .attr("stroke", "white")
       .transition()
       .duration(1000)
       .attr("d", arcMinorOver)
       .style("stroke-width",6);
   })
   .on("mouseleave", function(d) {
     d3.select(this).transition()
       .attr("d", arcMinor)
       .style("stroke-width",0);
   });

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

 var color = d3.scale.ordinal()
   .range(["cyan", "green", "blue", "brown", "violet", "orange", "purple"]);

 var arcMajor = d3.svg.arc()
   .outerRadius(function(d) {
     return radius - 20;
   })
   .innerRadius(0);

 var arcMajorOver = d3.svg.arc()
   .outerRadius(function(d) {
     return radius - 10;
   });

 //this for making the minor arc
 var arcMinor = d3.svg.arc()
   .outerRadius(function(d) {
     // scale for calculating the radius range([20, radius - 40])
     var s = scale((d.data.major - d.data.minor));
     if (s > radius - 20) {
       return radius - 20;
     }

     return scale(d.data.major - d.data.minor);
   })
   .innerRadius(0);

 var arcMinorOver = d3.svg.arc()
   .outerRadius(function(d) {
     var s = scale((d.data.major - d.data.minor));
     if (s > radius - 20) {
       return radius - 20;
     }

     return scale(d.data.major - d.data.minor) + 10;
   });

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


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

 data = [{
   major: 500,
   minor: 250,
   grp: 1
 }, {
   major: 100,
   minor: 80,
   grp: 2
 }, {
   major: 100,
   minor: 50,
   grp: 3
 }, {
   major: 100,
   minor: 60,
   grp: 4
 }, {
   major: 100,
   minor: 10,
   grp: 5
 }];
 var scale = d3.scale.linear()
   .range([d3.min(data, function(d) {
     return d.minor;
   }), radius - 100 - d3.max(data, function(d) {
     return d.minor / d.major;
   })])
   //setting the scale domain
   .domain([d3.min(data, function(d) {
     return d.minor;
   }), d3.max(data, function(d) {
     return d.minor;
   })]);

 var g = svg.selectAll(".arc")
   .data(pie(data))
   .enter().append("g")
   .attr("class", "arc");
 g.append("svg:text")
   .attr("transform", function(d) {
     var c = arcMajor.centroid(d),
       x = c[0],
       y = c[1],
       // pythagorean theorem for hypotenuse
       h = Math.sqrt(x * x + y * y);
     return "translate(" + (x / h * labelr) + ',' +
       (y / h * labelr) + ")";
   })
   .attr("dy", ".35em")
   .attr("text-anchor", function(d) {
     // are we past the center?
     return (d.endAngle + d.startAngle) / 2 > Math.PI ?
       "end" : "start";
   })
   .text(function(d, i) {
     return d.value.toFixed(2);
   });
 //this makes the major arc
 g.append("path")
   .attr("d", function(d) {
     return arcMajor(d);
   })
   .style("fill", function(d) {
     return d3.rgb(color(d.data.grp));
   }).on("mouseenter", function(d) {
     d3.select(this)      
       .transition()
       .duration(1000)
       .attr("d", arcMajorOver)
     .style("stroke-width",6);
   })
   .on("mouseleave", function(d) {
     d3.select(this).transition()
       .attr("d", arcMajor)
       .style("stroke-width", 0);
   });;;

 //this makes the minor arcs
 g.append("path")
   .attr("d", function(d) {
     return arcMinor(d);
   })
   .style("fill", function(d) {
     return d3.rgb(color(d.data.grp)).darker(2); //for making the inner path darker
   }).on("mouseenter", function(d) {
     d3.select(this)       
       .transition()
       .duration(1000)
       .attr("d", arcMinorOver)
       .style("stroke-width",6);
   })
   .on("mouseleave", function(d) {
     d3.select(this).transition()
       .attr("d", arcMinor)
       .style("stroke-width", 0);
   });
.arc text {
  font: 10px sans-serif;
  text-anchor: middle;
}
.arc path {
  stroke: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>