javascript - d3.js 彩虹图动画增强

标签 javascript d3.js charts

我创建了这个弧形图。我想更好地对标签进行动画处理,让它们与弧形动画进行补间。我已将标签放在里面以避免被掩盖。

jsFiddle

enter image description here

var arcGenerator = {
radius: 100,
oldData: "",
init: function(data){
    var clone = jQuery.extend(true, {}, data);
    this.oldData = this.setData(clone, false);
    this.setup(this.setData(data, true));           
},
update: function(data){
    var clone = jQuery.extend(true, {}, data);          
    this.animate(this.setData(data, true));         
    this.oldData = this.setData(clone, false);
},
animate: function(data){
    var that = this;

    var chart = d3.select(".arcchart");
    that.generateArcs(chart, data);
},  
setData: function(data, isSorted){

    var diameter = 2 * Math.PI * this.radius;

    var localData = new Array();

    var displacement = 0;
    var oldBatchLength = 0;

    $.each(data, function(index, value) {               
        var riseLevels = value.segments;
        var riseLevelCount = riseLevels.length;

        if(oldBatchLength !=undefined){             
            displacement+=oldBatchLength;
        }

        var arcBatchLength = 2*Math.PI;
        var arcPartition = arcBatchLength/riseLevelCount;

            $.each(riseLevels, function( ri, value ) {
                var startAngle = (ri*arcPartition);
                var endAngle = ((ri+1)*arcPartition);

                if(index!=0){
                    startAngle+=displacement;
                    endAngle+=displacement;
                }

                riseLevels[ri]["startAngle"] = startAngle;
                riseLevels[ri]["endAngle"] = endAngle;                  
            });

        oldBatchLength = arcBatchLength;

        localData.push(riseLevels);
    });

    var finalArray = new Array();

    $.each(localData, function(index, value) {
        $.each(localData[index], function(i, v) {
            finalArray.push(v);
        });
    });

    return finalArray;

},
generateArcs: function(chart, data){

    var that = this;

    //_arc paths

    //append previous value to it.          
    $.each(data, function(index, value) {
        if(that.oldData[index] != undefined){
            data[index]["previousEndAngle"] = that.oldData[index].endAngle;
        }
        else{
            data[index]["previousEndAngle"] = 0;
        }
    });     


    var arcpaths = that.arcpaths.selectAll("path")
            .data(data);

        arcpaths.enter().append("svg:path")
            .attr("class", function(d, i){
                return d.machineType;
            })  
            .style("fill", function(d, i){
                return d.color;
            })
            .transition()
            .ease("elastic")
            .duration(750)
            .attrTween("d", arcTween);               

        arcpaths.transition()
            .ease("elastic")                    
            .style("fill", function(d, i){
                return d.color;
            })
            .duration(750)
            .attrTween("d",arcTween);

        arcpaths.exit().transition()
            .ease("bounce")
            .duration(750)
            .attrTween("d", arcTween)
            .remove();

    function arcTween(b) {

        var prev = JSON.parse(JSON.stringify(b));
        prev.endAngle = b.previousEndAngle;
        var i = d3.interpolate(prev, b);

        return function(t) {
            return that.getArc()(i(t));
        };
    }
    //_arc paths





     var r = that.radius - 50;
    var ir = that.radius + 90;

                //__labels  
                var labels = that.labels.selectAll("text")
                    .data(data);

                labels.enter()
                    .append("text")
                    .attr("text-anchor", "middle")


                labels
                    .attr("x", function(d) {
                        var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
                        d.cx = Math.cos(a) * (ir+((r-ir)/2));
                        return d.x = Math.cos(a) * (r + 20);
                    })
                    .attr("y", function(d) {
                        var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
                        d.cy = Math.sin(a) * (ir+((r-ir)/2));
                        return d.y = Math.sin(a) * (r + 20);
                    })
                    .text(function(d) {
                        return d.color; 
                    })
                    .each(function(d) {
                        var bbox = this.getBBox();
                        d.sx = d.x - bbox.width/2 - 2;
                        d.ox = d.x + bbox.width/2 + 2;
                        d.sy = d.oy = d.y + 5;
                    })
                    .transition()
                        .duration(300)

                labels
                    .transition()
                    .duration(300)      

                labels.exit().remove();
                //__labels            




                //__pointers
            that.pointers.append("defs").append("marker")
                    .attr("id", "circ")
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 6)
                    .attr("refX", 3)
                    .attr("refY", 3)
                    .append("circle")
                    .attr("cx", 3)
                    .attr("cy", 3)
                    .attr("r", 3);

                var pointers = that.pointers.selectAll("path.pointer")
                    .data(data);

                pointers.enter()
                    .append("path")
                    .attr("class", "pointer")
                    .style("fill", "none")
                    .style("stroke", "black")
                    .attr("marker-end", "url(#circ)");

                pointers
                    .attr("d", function(d) {
                        if(d.cx > d.ox) {
                            return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
                        } else {
                            return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
                        }
                    })
                    .transition()
                        .duration(300)

                pointers
                    .transition()
                    .duration(300)      

                pointers.exit().remove();

                //__pointers



},
setup: function(data){      
    var chart = d3.select("#threshold").append("svg:svg")
            .attr("class", "chart")
            .attr("width", 420)
            .attr("height", 420)
                .append("svg:g")
                .attr("class", "arcchart")
                .attr("transform", "translate(200,200)");




    this.arcpaths = chart.append("g")
                        .attr("class", "arcpaths");


    this.labels = chart.append("g")
                        .attr("class", "labels");


    this.pointers = chart.append("g")
                        .attr("class", "pointer");



    this.generateArcs(chart, data);     
},
getArc: function(){
    var that = this;

    var arc = d3.svg.arc()
            .innerRadius(function(d, i){
                return that.radius;
            })
            .outerRadius(function(d){
                var maxHeight = 100;
                var ratio = (d.height/maxHeight * 100)+that.radius;
                return ratio;
            })
            .startAngle(function(d, i){
                return d.startAngle;
            })
            .endAngle(function(d, i){
                return d.endAngle;
            });

    return arc;
}

}

$(document).ready(function() {

    var dataCharts = [
            {
                "data": [
                    {
                        "segments": [
                            {
                                height: 10,
                                color: "grey"                           
                            },
                            {
                                height: 40,
                                color: "darkgrey"                           
                            },
                            {
                                height: 33,
                                color: "grey"                           
                            },
                            {
                                height: 50,
                                color: "darkgrey"
                            },
                            {
                                height: 33,
                                color: "grey"                           
                            },
                            {
                                height: 10,
                                color: "darkgrey"                           
                            },
                            {
                                height: 50,
                                color: "grey"
                            },
                            {
                                height: 45,
                                color: "darkgrey"                           
                            },
                            {
                                height: 10,
                                color: "grey"                           
                            },
                            {
                                height: 40,
                                color: "darkgrey"                           
                            }                           
                        ]
                    }
                ]
            },
            {
                "data": [
                    {
                        "segments": [
                            {
                                height: 50,
                                color: "red"
                            },
                            {
                                height: 100,
                                color: "yellow"                         
                            },
                            {
                                height: 10,
                                color: "green"                          
                            }                       
                        ]
                    }
                ]
            }               
        ];

        var clone = jQuery.extend(true, {}, dataCharts);

        arcGenerator.init(clone[0].data);

        $(".testers a").on( "click", function(e) {
            e.preventDefault();

            var clone = jQuery.extend(true, {}, dataCharts);

            var pos = $(this).parent("li").index();
            arcGenerator.update(clone[pos].data);           
        });

});

最佳答案

这有两个部分。首先,指针线的动画。这相对容易,唯一缺少的是 .transition() 位于错误的位置:

pointers
  .transition()
  .duration(300)
  .attr("d", function(d) {
// etc

第二部分是文本标签的动画。这有点困难,因为它们的计算包括一些允许正确计算指针线的副作用。这分为两部分——位置的计算和显示文本的范围的计算。考虑到这一点,更改相对简单,我们只需要确保这些计算在转换开始之前进行即可:

labels.text(function(d) {
  return d.color; 
}).each(function(d) {
  var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
  d.cx = Math.cos(a) * (ir+((r-ir)/2));
  d.cy = Math.sin(a) * (ir+((r-ir)/2));
  d.x = d.x || Math.cos(a) * (r + 20);
  d.y = d.y || Math.sin(a) * (r + 20);
  var bbox = this.getBBox();
  d.sx = d.x - bbox.width/2 - 2;
  d.ox = d.x + bbox.width/2 + 2;
  d.sy = d.oy = d.y + 5;
})

首先,设置文本本身。这是能够使用 .getBBox() 确定其尺寸所必需的。然后,计算指针路径所需的所有值 - 这些代码位之前用于计算文本位置,但这就是我们想要转换到的值,以便稍后设置这些值(新文本标签除外)没有设置坐标)。

现在剩下的就是以与以前相同的方式为文本坐标的变化设置动画:

.transition()
.duration(300)
.attr("x", function(d) {
  var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
  return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function(d) {
  var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
  return d.y = Math.sin(a) * (r + 20);
});

完整示例 here .

关于javascript - d3.js 彩虹图动画增强,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22284611/

相关文章:

javascript - 图没有占用 d3.js 中的整个空间

jQuery Accordion 的 JavaScript 关闭问题(我相信)

javascript - 从 FB 相册中随机抽取图片

javascript - 最小化 jQuery 代码

javascript - 获取选中复选框的 href 值?

javascript - 将 d3.js 气泡转换为基于强制/重力的布局

html - 如何将 REST 响应放回 angular JS 标签中以绘制 D3 js 饼图

android - 如何获得 Canvas 区域点击?

javascript - Highcharts折线图,在折线系列末尾显示系列名称

asp.net 图表 : final series getting cut off when setting . AxisX.Maximum