D3.js之餅圖動畫2
阿新 • • 發佈:2019-02-17
上篇只是說了餅圖的從無到有的旋轉動畫,這次來說說怎麼給餅圖新增外接註釋加連線,以及資料更新的動畫。
雖然d3.js寫的麻煩,我看了幾天echart,發現只要套套模板更改一下引數就行,但是d3可塑性很高,完全由你想象,想怎麼畫就怎麼畫。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>頭疼</title> </head> <style type="text/css"> button{ position: absolute; margin: 10px; } </style> <body> <button onclick="changeData()">更換資料</button> <script type="text/javascript" src='../js/d3.js'></script> <script type="text/javascript"> var width = 500+100; var height = 500; var dataset=[["標籤1",30],["標籤2",20],["標籤3",43],["標籤4",55],["標籤5",13]]; var outerRadius = 150; //外半徑 var innerRadius = 0; //內半徑,為0則中間沒有空白 var arc = d3.svg.arc() //弧生成器 .innerRadius(innerRadius) //設定內半徑 .outerRadius(outerRadius); //設定外半徑 var color = d3.scale.category20();//構造20種顏色的序數比例尺,索引值可以是字串或數字 var pie = d3.layout.pie() //餅圖佈局 .sort(null) //不排序,不寫則會從大到小,順時針排序。 .value(function(d){ return d[1]}); //設定value值為上面的2二維陣列中的數字 var piedata=pie(dataset); var svg = d3.select("body") //新增一個svg並且設定寬高 .append("svg") .attr("width", width) .attr("height", height); var arcs=svg.selectAll(".arc") .data(piedata) //返回是pie(data0) .enter().append("g") .attr("class", "arc") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") //將圓心平移到svg的中心 .append("path") .attr("fill", function(d, i) { return color(i); //根據下標填充顏色 }) .attr("d", function(d, i) { return arc(d); ///呼叫上面的弧生成器 }); var text=svg.selectAll(".text") .data(piedata) //返回是pie(data0) .enter().append("g") .attr("class", "text") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .append("text") .style('text-anchor', function(d, i) { //根據文字在是左邊還是右邊,在右邊文字是start,文字預設都是start。 return (d.startAngle + d.endAngle)/2 < Math.PI ? 'start' : 'end'; }) .attr('transform', function(d, i) { var pos = arc.centroid(d); //centroid(d)計算弧中心 pos[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4) pos[1]*=2.1; //將文字移動到外面去。 return 'translate(' + pos + ')'; }) .attr("dy",".3em") //將文字向下便宜.3em .text(function(d) { //設定文字 return d.data[0]; }) var text2=svg.selectAll(".text2") .data(piedata) //返回是pie(data0) .enter().append("g") .attr("class", "text") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .append("text") .style('text-anchor',"middle") .attr('transform', function(d, i) { var pos = arc.centroid(d); //將數字放在圓弧中心 return 'translate(' + pos + ')'; }) .text(function(d) { return d.data[1]; }) var line = svg.selectAll(".line") //新增文字和弧之間的連線 .data(piedata) //返回是pie(data0) .enter().append("g") .attr("class", "line") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .append("polyline") .attr('points', function(d, i) { var pos1= arc.centroid(d),pos2= arc.centroid(d),pos3= arc.centroid(d); pos1[0]*=2,pos1[1]*=2; pos2[0]*=2.1,pos2[1]*=2.1 pos3[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4) pos3[1]*=2.1; //pos1表示圓弧的中心邊緣位置,pos2是網上稍微去了一下,pos3就是將pos2平移後得到的位置 //三點連結在一起就成了線段。 return [pos1,pos2,pos3]; }) .style('fill', 'none') .style('stroke',function(d,i){ return color(i); }) .style('stroke-width', "3px") .style('stroke-dasharray',"5px") var label=svg.selectAll('.label') //新增右上角的標籤 .data(piedata) .enter() .append('g') .attr("transform","translate("+(width-50)+","+10+")") ; label.append('rect') //標籤中的矩形 .style('fill',function(d,i){ return color(i); }) .attr('x',function(d,i){ return 0; }) .attr("y",function(d,i){ return 10+i*30; }) .attr('rx','5') //rx=ry 會出現圓角 .attr('ry','5') .attr('width',50) .attr('height',20) ; label.append('text') //標籤中的文字 .attr('x',function(d,i){ return 25; //因為rect寬度是50,所以把文字偏移25,在後面再將文字設定居中 }) .attr("y",function(d,i){ return 15+10+i*30; }) .text(function(d){ return d.data[0]; }) .style({ "font-size":"10px", "text-anchor":"middle", 'fill':"white", "font-weight":600 }) function changeData(){ random() var pie2=pie(dataset); piedata.forEach(function(d,i){ d.laststartAngle=d.startAngle; d.lastendAngle=d.endAngle; d.startAngle=pie2[i].startAngle; d.endAngle=pie2[i].endAngle; }) arcs.data(piedata) .transition().duration(800) .attrTween("d", tweenArc(function(d, i) { return { startAngle: d.laststartAngle, endAngle: d.lastendAngle, }; })) text.data(piedata) .transition().duration(800) .style('text-anchor', function(d, i) { //圓的中心位置在哪裡,在右邊文字是start return (d.startAngle + d.endAngle)/2 < Math.PI ? 'start' : 'end'; }) .attr('transform', function(d, i) { console.log(d); var pos = arc.centroid(d); pos[0] = outerRadius * ((d.startAngle + d.endAngle)/2 < Math.PI ? 1.4 : -1.4) pos[1] *= 2; return 'translate(' + pos + ')'; }); text2.data(piedata) .transition().duration(800) .attr('transform', function(d, i) { var pos = arc.centroid(d); return 'translate(' + pos + ')'; }).text(function(d) { return d.data[1]; }); line.data(piedata) .transition().duration(800) .attr('points', function(d, i) { var pos1= arc.centroid(d),pos2= arc.centroid(d),pos3= arc.centroid(d); pos1[0]*=2,pos1[1]*=2; pos2[0]*=2.1,pos2[1]*=2.1 pos3[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4) pos3[1]*=2.1; console.log(pos1); return [pos1,pos2,pos3]; }) } function random(){ var n=5; while(n--){dataset[n][1]=Math.floor(Math.random()*40+10)} } function tweenArc(b) { return function(a, i) { var d = b.call(this, a, i), i = d3.interpolate(d, a); return function(t) { return arc(i(t)); }; }; } </script> </body> </html>
上面只是圖片,大家可以貼上程式碼來執行一下。
可以點選上面的更新資料來實現餅圖動畫。d3.js還是很神奇的,有好多想法,尤其是看了官網好多非常酷炫的例子。