2014-02-14 53 views
2

我期待開發一個弧形環形圖。每個新數據集都顯示爲另一個同心環。d3.js同心環形圖表

http://jsfiddle.net/NYEaX/101/

我試圖採取的數據值的總和,並以此來幫助開發比例算法,以保證每個弧從來不會超過一個週期。

這部分管理同心環。

getArc: function(){ 
      var that = this; 

      var radiusArray = [100, 80]; 

      function getRadiusRing(i){ 
       return that.radius-(i*20);    
      } 
      var thickness = 15; 

      var arc = d3.svg.arc() 
        .innerRadius(function(d){ 
         return getRadiusRing(d.index);      
        }) 
        .outerRadius(function(d){ 
         return getRadiusRing(d.index)+thickness;  
        }) 
        .startAngle(function(d, i){ 
         return d.startAngle; 
        }) 
        .endAngle(function(d, i){ 
         return d.endAngle; 
        });  
      return arc; 
     } 

但我認爲在端角計算中存在缺陷。如果啓用更多數據 - 同心環雖然形成正確,但它們在整個圖表中包含可疑弧長?

setData: function(data){ 
      var diameter = 2 * Math.PI * this.radius;   
      var localData = new Array(); 

      var segmentValueSum = 0; 
      $.each(data[0].segments, function(ri, va) { 
       segmentValueSum+= va.value; 
      }); 

      $.each(data[0].segments, function(ri, value) { 

       var segmentValue = value.value; 

       var fraction = segmentValue/segmentValueSum; 

       var arcBatchLength = fraction*2*Math.PI; 
       var arcPartition = arcBatchLength;  

       var startAngle = 0; 
       var endAngle = ((ri+1)*arcPartition);    

       data[0].segments[ri]["startAngle"] = startAngle; 
       data[0].segments[ri]["endAngle"] = endAngle; 
       data[0].segments[ri]["index"] = ri; 
      }); 

      localData.push(data[0].segments); 

      return localData[0];   
     } 

試圖建立圖表,看起來像下面

Concentric ring chart

我增強了圖表,但仍然有傳說的位置和更新問題,戒指和價值。爲什麼舊數據還剩下來? http://jsfiddle.net/NYEaX/123/

如果有更多或更少的數據 - 標籤不得到正確​​

//draw labels      
      valueLabels = value_group.selectAll("text.value").data(reversedata) 
      valueLabels.enter().append("svg:text") 
      .attr("class", "value") 
      .attr("transform", function(d) { 
       var rings = counts; 

       return "translate("+(that.radius+55)/rings+", 0)"; 
      }) 
      .attr("dx", function(d, i){ 
       return 19*i;   }) 
      .attr("dy", function(d, i){ 
       return -5; 
      }) 
      .attr("text-anchor", function(d){ 
       return "start"; 
      }).text(function(d){ 
       return d.value; 
      }); 

      valueLabels.transition().duration(300).attrTween("d", arcTween) 
      valueLabels.exit().remove(); 
+0

一個相關的討論:(http://stackoverflow.com/q/24507751/320399) – blong

回答

1

我已經成功地修復所有的錯誤 - 這是作爲jQuery插件的最終代碼,享受

enter image description here

http://jsfiddle.net/NYEaX/165/

$(document).ready(function() { 


      (function($){ 
       var methods = { 
        el: "", 
        init : function(options) { 
         var clone = jQuery.extend(true, {}, options["data"]); 
         var preparedData = methods.setData(clone); 

         methods.el = this;   
         methods.setup(preparedData, options["width"], options["height"]); 
        }, 
        setup: function(data, w, h){ 

         var selector = methods.el["selector"]; 

         var padding = 20; 


         var chart = d3.select(selector).append("svg:svg") 
          .attr("class", "chart") 
          .attr("width", w) 
          .attr("height", h) 
         .append("svg:g") 
          .attr("class", "concentricchart") 
          .attr("transform", "translate("+((w/3)+padding)+","+h/3+")"); 

         methods.radius = Math.min(w, h)/2; 

         var label_group = chart.append("svg:g") 
          .attr("class", "label_group") 
          .attr("transform", "translate("+((w/3)-15)+","+(-h/4)+")"); 

         var legend_group = chart.append("svg:g") 
          .attr("class", "legend_group") 
          .attr("transform", "translate("+((w/3)-130)+","+((-h/4)-5)+")"); 

         var value_group = chart.append("svg:g") 
          .attr("class", "value_group") 
          .attr("transform", "translate(0,"+(h/4)+")"); 

         var path_group = chart.append("svg:g") 
          .attr("class", "path_group") 
          .attr("transform", "translate(0,"+(h/4)+")");    


         this.generateArcs(selector, data);  
        }, 
        update: function(data){ 
         var clone = jQuery.extend(true, {}, data); 

         var preparedData = methods.setData(clone); 

         methods.el = this; 
         methods.animate(preparedData);   
         methods.oldData = preparedData; 
        }, 
        animate: function(data){ 
         var that = this; 

         var selector = methods.el["selector"]; 

         that.generateArcs(selector, data); 
        }, 
        setData: function(data){ 
          var diameter = 2 * Math.PI * this.radius;   
          var localData = new Array(); 

          var segmentValueSum = 0; 
          $.each(data[0].segments, function(ri, va) { 
           segmentValueSum+= va.value; 
          }); 

          segmentValueSum = 200;//consistent total accross different data sets 

          $.each(data[0].segments, function(ri, value) { 
           var segmentValue = value.value; 

           var fraction = segmentValue/segmentValueSum; 

           var arcBatchLength = fraction*4*Math.PI; 
           var arcPartition = arcBatchLength;  

           var startAngle = Math.PI/2;   
           var endAngle = startAngle + arcPartition; 

           data[0].segments[ri]["startAngle"] = startAngle; 
           data[0].segments[ri]["endAngle"] = endAngle; 
           data[0].segments[ri]["index"] = ri; 
          }); 

          localData.push(data[0].segments); 

          return localData[0];   
        }, 
        textOffset: 10, 
        generateArcs: function(selector, data){ 
         var that = this; 

         var chart = d3.select(selector); 

         //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 thickness = $(selector).data("thickness"); 
         var ir = ($(selector).data("width")/3); 


         var path_group = d3.select(selector+ ' .path_group'); 

         var arcpaths = path_group.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", function(d){ 
           return that.arcTween(d, thickness, ir); 
          });  

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

         arcpaths.exit().transition() 
          .ease("bounce") 
          .duration(750) 
          .attrTween("d", function(d){ 
           return that.arcTween(d, thickness, ir); 
          }) 
          .remove(); 

         //draw labels  
         that.drawLabels(chart, data, ir, thickness); 
         that.buildLegend(chart, data); 
        }, 
        arcTween: function(b, thickness, ir){ 
         var that = methods; 

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

         return function(t) { 
          return that.getArc(thickness, ir)(i(t)); 
         }; 
        }, 
        drawLabels: function(chart, data, ir, thickness){ 
         $(methods.el["selector"]+' .value_group').empty(); 

         var that = this; 

         var reversedata = data.reverse(); 
         var counts = data.length; 

         var value_group = d3.select(methods.el["selector"]+ ' .value_group'); 

         valueLabels = value_group.selectAll("text.value").data(reversedata) 
         valueLabels.enter().append("svg:text") 
          .attr("class", "value") 
          .attr("transform", function(d) {  
           return "translate("+(that.getRadiusRing(ir, counts-1))+", 0)"; 
          }) 
          .attr("dx", function(d, i){ 
           return 20*i;   }) 
          .attr("dy", function(d, i){ 
           return -5; 
          }) 
          .attr("text-anchor", function(d){ 
           return "start"; 
          }).text(function(d){ 
           return d.value; 
          }); 

         valueLabels 
          .transition() 
          .duration(300) 
          .attrTween("d", function(d){ 
           return that.arcTween(d, thickness, ir); 
          }) 

         valueLabels 
          .exit() 
          .remove();  
        }, 
        buildLegend: function(chart, data){ 
         console.log("build legend"); 
         $(methods.el["selector"]+' .label_group').empty(); 
         $(methods.el["selector"]+' .legend_group').empty(); 


         var label_group = d3.select(methods.el["selector"]+ ' .label_group'); 

         //draw labels      
         labels = label_group.selectAll("text.labels") 
          .data(data.reverse());    

         labels.enter().append("svg:text") 
          .attr("class", "labels") 
          .attr("dy", function(d, i){ 
           return 19*i 
          }) 
          .attr("text-anchor", function(d){ 
           return "start"; 
          }) 
          .text(function(d){ 
           return d.label; 
          }); 

         labels.exit().remove(); 

         var legend_group = d3.select(methods.el["selector"]+ ' .legend_group'); 

         legend = legend_group.selectAll("circle").data(data); 

         legend.enter().append("svg:circle") 
          .attr("cx", 100) 
          .attr("cy", function(d, i){ 
           return 19*i 
          }) 
          .attr("r", 7) 
          .attr("width", 18) 
          .attr("height", 18) 
          .style("fill", function(d){ 
           return d.color; 
          }); 

         legend.exit().remove(); 
        }, 
        getRadiusRing: function(ir, i){ 
         return ir-(i*20);    
        }, 
        getArc: function(thickness, ir){ 
         var that = this; 

         var arc = d3.svg.arc() 
          .innerRadius(function(d){ 
           return that.getRadiusRing(ir, d.index);      
          }) 
          .outerRadius(function(d){ 
           return that.getRadiusRing(ir+thickness, d.index); 
          }) 
          .startAngle(function(d, i){ 
           return d.startAngle; 
          }) 
          .endAngle(function(d, i){ 
           return d.endAngle; 
          }); 
         return arc; 
        }, 
        radius: 100, 
        oldData: "" 
       }; 

       $.fn.concentric = function(methodOrOptions) { 
        if (methods[methodOrOptions]) { 
         return methods[ methodOrOptions ].apply(this, Array.prototype.slice.call(arguments, 1)); 
        } else if (typeof methodOrOptions === 'object' || ! methodOrOptions) { 
         // Default to "init" 
         return methods.init.apply(this, arguments); 
        } else { 
         $.error('Method ' + methodOrOptions + ' does not exist'); 
        }  
       }; 

      })(jQuery); 




      var dataCharts = [ 
       { 
        "data": [ 
         { 
          "segments": [ 
           { 
            "label": "Turkey", 
            "value": 25, 
            "color": "red" 
           }, 
           { 
            "label": "United States", 
            "value": 40, 
            "color": "blue"       
           }, 
           { 
            "label": "Switzerland", 
            "value": 60, 
            "color": "green"        
           }, 
           { 
            "label": "Iceland", 
            "value": 80, 
            "color": "gold" 
           }       
          ] 
         } 
        ] 
       }, 
       { 
        "data": [ 
         { 
          "segments": [ 
           { 
            "label": "Peanut Butter", 
            "value": 50, 
            "color": "red" 
           }, 
           { 
            "label": "Tea", 
            "value": 25, 
            "color": "orange"       
           }, 
           { 
            "label": "Cheese", 
            "value": 25, 
            "color": "purple"       
           }      
          ] 
         } 
        ] 
       } , 
       { 
        "data": [ 
         { 
          "segments": [ 
           { 
            "label": "Jam", 
            "value": 90, 
            "color": "purple" 
           }, 
           { 
            "label": "Lemons", 
            "value": 15, 
            "color": "brown"        
           }      
          ] 
         } 
        ] 
       }   
      ]; 

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

       //__invoke concentric 
       $('[data-role="concentric"]').each(function(index) { 
        var selector = "concetric"+index; 

        $(this).attr("id", selector); 

        var options = { 
         data: clone[0].data, 
         width: $(this).data("width"), 
         height: $(this).data("height") 
        } 

        $("#"+selector).concentric(options); 
       }); 


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

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

       var min = 0; 
       var max = 2; 

       //__invoke concentric 
       $('[data-role="concentric"]').each(function(index) { 
        pos = Math.floor(Math.random() * (max - min + 1)) + min; 
        console.log("id", $(this).attr("id")); 
        $("#"+$(this).attr("id")).concentric('update', clone[pos].data); 
       }); 

      }); 

}); 
2

放置替換

var endAngle = ((ri+1)*arcPartition); 

通過

var endAngle = startAngle + arcPartition; 
+0

良好,即固定它[使用D3.js同心弧]我認爲。最新演示。 http://jsfiddle.net/NYEaX/103/ –

+0

我已經爲戒指添加了標籤 - 但是標籤在更新時不會被刪除? http://jsfiddle.net/NYEaX/114/ - 我又如何在它的最後添加戒指的價值? –

+0

我已經添加了值 - 但是再次 - 我在更新標籤和標籤/值之間刪除了一個問題 - http://jsfiddle.net/NYEaX/115/ –

1

enter image description here

我做了其中的圖表從頂部開始的一個版本 - 如此的不同方位。把它作爲一個變量很好 - 也許可以選擇在4個不同的象限中啓動圖表。

http://jsfiddle.net/NYEaX/364/

我在設定數據

變種由startAngle調整

  • 起始角度=數學。PI * 2;

-the標籤展示位置

valueLabels.enter().append("svg:text") 
          .attr("class", "value") 
          .attr("transform", function(d) {  
           return "translate("+(that.getRadiusRing(ir, counts-1))+", 0)"; 
          }) 
          .attr("dx", function(d, i){ 
           return 0; 
          }) 
          .attr("dy", function(d, i){ 
           return (thickness + 4)*i; 
          }) 
          .attr("text-anchor", function(d){ 
           return "start"; 
          }).text(function(d){ 
           return d.value; 
          });