#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 进阶图表:甜甜圈图


<<:  【从实作学习ASP.NET Core】Day30 | 总结与回顾

>>:  Day29_ISO27037数位证据处理程序国际标准-2021/10/12

Day 28. Hi-Fi Prototype-以 Figma 制作高精度原型 (上)

终於,我们要进入 UX/UI 设计中的最後一个流程- 高精度原型 Hi-Fi Prototype,这...

[Day17] 系统保护策略

在某个我辅导过的团队,我曾观察到一个现象: RD 在评估工作时数,总是会估出不合理的长时间。是 RD...

Day 22 「戏如人生」以真实案例分析 Clean Architecture 的分层原则

相信大家或多或少都有去公家机关办事的经验。去公家机关办事时,如果等待时间拖太久,肯定觉得很烦吧?好不...

Day02: Hello TypeScript! 环境安装起来 + 牛刀小试~

Q: 同事说自己的 C++ 能力是世界第一,怎麽样可以让他意识到自己没那麽厉害? A: 实不相瞒,...

Day19 用python写UI-聊聊OptionMenu

OptionMenu就是下拉式选单的概念,可以有不同的设定方法,可以设成有预设选项的,也可以获得选好...