iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
Modern Web

這個網站也太嗨!30 個網頁動態提案系列 第 29

#26-圓餅圖動起來!玩轉D3.js漸變功能Transition+Interpolate

昨天用了D3的transition
今天來試試看attrTween來讓圓餅圖長出來!

老樣子先來看成果:

今天會先來看一下D3的Interpolate
想看code的請自己跳過喔~


D3 插入值 Interpolate!

tween就是補間的意思,
另外D3還有一個 interpolate (插入)可以在兩個值中間幫你算出過度的值。

官方文件: https://github.com/d3/d3-interpolate
這邊也有詳細的解釋(https://observablehq.com/@d3/d3-interpolate

看一下官方的案例:

數字

const i = d3.interpolateNumber(10, 20);//幫我算出10~20中間的補間吧~
i(0.0); // 10
i(0.2); // 12
i(0.5); // 15
i(1.0); // 20

顏色

const i = d3.interpolate({colors: ["red", "blue"]}, {colors: ["white", "black"]});
i(0.0); // {colors: ["rgb(255, 0, 0)", "rgb(0, 0, 255)"]}
i(0.5); // {colors: ["rgb(255, 128, 128)", "rgb(0, 0, 128)"]}
i(1.0); // {colors: ["rgb(255, 255, 255)", "rgb(0, 0, 0)"]}

tween搭配interpolate去做出過度,
而Colors, numbers, 和 transforms
可以直接用d3公式算出來(d3.interpolateTransformCss(a, b) 等等,
其他要客製化的參數,就可用:attrTween、styleTween、tween,官方案例:

transition.attrTween

transition.attrTween("fill", function() {
  return d3.interpolateRgb("red", "blue");
});

transition.styleTween

transition.styleTween("fill", function() {
  return d3.interpolateRgb("red", "blue");
});

transition.tween

transition.tween("attr.fill", function() {
  const i = d3.interpolateRgb(this.getAttribute("fill"), "blue");
  return function(t) {
    this.setAttribute("fill", i(t));
  };
});

將Interpolate放在圓餅圖!

將Interpolate & transition結合就可以完成我們的動態啦!
先來做基本設定:


//data
const ethnicGroupsData = [
 { label: 'Black',value:80.7},
   { label: 'Coloured',value:8.8},
   { label: 'White',value:7.9},
   { label: 'Asian',value:2.6}]

//做出顏色比例尺
const color = d3.scaleOrdinal().domain(ethnicGroupsData)
.range(['#f9c74f','#f8961e','#90be6d','#43aa8b']);

//原餅圖的半徑
const radius = 100;

// Animation
function play(){
  //先清空
  d3.select('svg').remove();
  
  //svg起手式
  const svg = d3.select('.graph2')
  .append('svg')
  .attr('width',300)
  .attr('height',300)
  .attr('id','graph2-svg')
  .append("g")
  .attr("transform", "translate(" + 300 / 2 + "," + 300 / 2 + ")");
  
  // 做餅啦
var pie = d3.pie().value(function(d) {return d.value});

// 畫圓餅圖製造機,幫每一個data做出扇形
//可以看這一篇:弧的產生器(https://ithelp.ithome.com.tw/articles/10207678)
var arcGenerator = 
  d3.arc()
  .innerRadius(0) //這邊如果有數值的話變成甜甜圈形狀的
  .outerRadius(radius)

// 把data塞進去
var arc = svg.selectAll('arc').data(pie(ethnicGroupsData)).enter()

來畫圖&做動態囉!

//做底圖和動畫一塊一塊啦
arc
.append('path')
.attr('d',arcGenerator)
.attr('fill', function(d, i){
  return color(d.data)
})
.transition()  //動畫起手式!
.duration(3000)
.attrTween("d", function(d) {
    //data裡面 有startAngle & endAngle
    var d3Interpolate = d3.interpolate({startAngle: 0, endAngle: 0}, d);
    return function(t) {
       // t就是時間間隔回傳0-1中間的數值
      //d3Interpolate(t) =>各個data在t時間的角度
      return arcGenerator(d3Interpolate(t));
    };
})

// Label 標籤
var label = d3.arc()
            .outerRadius(radius*1.5) //讓他在圓的更外面
            .innerRadius(radius);
            
var text = arc.append("text")
  .text(function(d) { return d.data.label; })
  .style("font-family", "arial")
  .style("font-size", 15)
  .style("fill", "transparent")
  .attr("text-anchor", "middle")
  .transition()
  .delay(2000)//讓他晚一點出現
  .duration(1000)
  .style("fill", "white")
  .attr("transform", function(d) { 
    return "translate(" + label.centroid(d) + ")"; 
   })

// Label標籤的線。polyline
var polyline = arc.append("polyline")
  .attr("stroke", "white")
  .attr("stroke-width", 1)
  .attr("fill", "transparent")
  .transition()
  .delay(3000) //讓他晚一點出現
  .duration(1000)
  .attr("points",function(d){
    var outer = label.centroid(d).map((i)=>i*0.9)
    return outer+','+ arcGenerator.centroid(d)
  })
}


play();

以上!

今天的code: 放在這

對於畫圓餅圖&甜甜圈圖有興趣也可以參考:
Day20-D3 基礎圖表:圓餅圖
Day27-D3 進階圖表:甜甜圈圖


上一篇
#25-讓長條圖一條條動起來~大數據時代!入手 D3.js~
下一篇
#27-微互動折線圖動態!就是要比較才看得出結果啊 (D3.js)
系列文
這個網站也太嗨!30 個網頁動態提案33

尚未有邦友留言

立即登入留言