当前位置: 首页 > 开发杂谈 >

D3JsDay13 让资料拥有过渡动画,让各位观众看见神话—过渡动画

过渡动画

transition这个翻译成过渡的意思,一个吸引人的图表当中,加入了一点动画成分和过渡的转变能吸引使用者的目光,也让观看者有预期心理画面将要转换,另外也使得图表更有质感。

首先我们先创建一个<rect>以宽50高300的长方形。

const svg = d3.select("body")
            .append("svg")
            .attr("width",800)
            .attr("height",800);
svg.append("rect")
    .attr("x",10)
    .attr("y",0)
    .attr("width",50)
    .attr("height",300)
    .attr("fill","orange");

transition()函式

官方文件如下图

https://ithelp.ithome.com.tw/upload/images/20210928/20125095V3ivJBpxnx.png

d3-transition官方API文件

这时候我们要考虑的地方是transition()要放在到哪个位置,依据官方的文件说明,前面要有一个selection,也就是你所选择的元素,後方需要带入要改变的样式,因此依据指示我们可以放在append()的後面

程序码如下

svg.append("rect")
    .attr("x",10)
    .attr("y",0)
    .attr("width",50)
    .attr("height",300)
    .attr("fill","orange")
    ;

此时当你按下浏览器的重新整理按钮的时候或是刚载入网页的时候应当会看到如下面这个范例
codepen范例如下
D3Day13-1范例


但出现的速度如此之快因此我们可以加入另一个函式来处理播放时间。

duration()和delay()函式

duration()添加至transtition()後面,以下范例设定3000毫秒,也就是3秒

程序码如下

 const svg = d3.select("body")
            .append("svg")
            .attr("width",600)
            .attr("height",600);
svg.append("rect")
.transition()
.duration(3000)
.attr("x",10)
.attr("y",0)
.attr("width",50)
.attr("height",300)
.attr("fill","orange");

codepen范例如下

D3day13-2


delay()函式放在transition()函式後面,主要的用途是要延迟几秒再执行的意思

codepen范例如下

D3day13-3

ease()函式系列

easeLinear()

这边主要是带入要呈现渐变时期的动画时的效果,里面带入参数第一个是指定你要的函式第二个是时间,具体用法程序码如下

svg.append("rect")
    .transition()
    .ease(d3.easeLinear,1)
    .duration(1500)
    .attr("x",10)
    .attr("y",0)
    .attr("width",50)
    .attr("height",300)
    .attr("fill","orange");

函数图形如下
https://ithelp.ithome.com.tw/upload/images/20210928/20125095avXX5rDvsi.png
这边带入的就是线性的动画,虽然官方文件写参数值带入t,但笔者观看原始码後线性所转回的值与原先是一样的情况,基本上你带入99所呈现的画面应当不会有所差别。

codepen范例如下

D3day13-4


Linear原始码如下

https://ithelp.ithome.com.tw/upload/images/20210928/20125095JQjBBWPrDz.png

官方easeLinear说明

官方Linear原始码

easePolyIn()

这边官方说明就有提到t数值会改变动画的效果
官方原文如下

https://ithelp.ithome.com.tw/upload/images/20210928/20125095BTy0OZOact.png
程序码如下

    svg.append("rect")
        .transition()
        .ease(d3.easePoly,4)
        .duration(5000)
        .attr("x",10)
        .attr("y",0)
        .attr("width",50)
        .attr("height",300)
        .attr("fill","orange")
        ;

codepen范例如下

D3day13-5


函数图型如下

https://ithelp.ithome.com.tw/upload/images/20210928/20125095UhvDHxwVjv.png

官方easePolyIn说明

这边仅介绍两个函数当范例
其他更多的函数可以参考官方API文件

easeAPI官方文件

值得注意的一点是有些函数并不适用於每个属性像是这个长条图有宽和高
因此如果你想尝试使用d3.easeElasticInOut()这个函数的话
由於函数图型有超出原本的区间,因此会造成宽高变成负值就会输出错误。

https://ithelp.ithome.com.tw/upload/images/20210928/20125095Q9K50gTOY7.png

另外D3的作者有发表关於其他范例,可以参考d3作者所用的范例,它所用的范例是改变位移的属性,因此也就能更加了解每个函式直接的差别。

范例如下

官方范例网址如下

D3作者的范例

长条图动画

原本的<rect>的程序码如下,延续我们之前的范例,假设我们希望画面载入的时候长条图由底部开始渐渐变长的话,该如何撰写呢?

svg.selectAll("rect")
    .data(newTaipei)
    .join("rect")
    .attr("x", (d, i) => {
        return padding + i * 60;
    })
    .attr("y", (d) => {
        return scaleY(d.people_total);
    })
    .attr("width", 50)
    .attr("height", (d) => {
        return 400 - scaleY(d.people_total);
    })
    .attr("fill", "orange");

由於transition方法链後面所带入的东西是你要改变的属性,因此势必我们得思考後面带入的东西是什麽?因为我们预计会改变长方形的高度,所以我们必须关注height属性,另外我们的svg的(0,0)座标是在左上角,如果只改变height属性的话,长方形的动画会从上方伸长到下方,因此我们也得改变y的起始点位置,这边svg的底部y的位置是400,所以在transition前面写下.attr("y", 400),高度从0开始伸长所以写下.attr("height", 0)

而我们原本的程序码是放在transition之後当作最後的结果,最後的程序码就如下面所示

svg.selectAll("rect")
            .data(newTaipei)
            .join("rect")
            .attr("x", (d, i) => {
              return padding + i * 60;
            })
            .attr("y", 400)
            .attr("height", 0)
            .attr("width", 50)
            .attr("fill", "orange")
            .transition()
            .duration(3000)
            .attr("y", (d) => {
              return scaleY(d.people_total);
            })
            .attr("height", (d) => {
              return 400 - scaleY(d.people_total);
            });

整个做出长条图从无到有的过程大概分成三个阶段

  1. 先制作出初始样貌放在transition前面
  2. 加入transition函式和delayduration等等函式
  3. 放在transition後面是最後要改变的属性或样式

本日完整程序码如下

  let newTaipei = taipei.map((el) => {
            el.people_total = Number(el.people_total);
            el.area = Number(el.area);
            el.population_density = Number(el.population_density);
            el.site_id = el.site_id.substr(3);
            return el;
          });

          let padding = 50;
          let svg = d3
            .select("body")
            .append("svg")
            .attr("width", 800)
            .attr("height", 450);
          let min = d3.min(newTaipei, (d) => d.people_total);
          let max = d3.max(newTaipei, (d) => d.people_total);
          console.log(newTaipei);
          let scaleY = d3.scaleLinear().domain([0, 320000]).range([400, 0]);

          svg.selectAll("rect")
            .data(newTaipei)
            .join("rect")
            .attr("x", (d, i) => {
              return padding + i * 60;
            })
            .attr("y", 400)
            .attr("height", 0)
            .attr("width", 50)
            .attr("fill", "orange")
            .transition()
            .duration(3000)
            .attr("y", (d) => {
              return scaleY(d.people_total);
            })
            .attr("height", (d) => {
              return 400 - scaleY(d.people_total);
            });

          svg.selectAll("text")
            .data(newTaipei)
            .join("text")
            .text((d) => {
              return d.site_id;
            })
            .attr("x", (d, i) => {
              return padding + i * 60;
            })
            .attr("y", (y) => {
              return 450 - 20;
            });

          let axisY = d3.axisRight(scaleY)
                        .ticks(5)
                        .tickFormat(function (d) {
                        return d / 10000 + "万";
                        });
          let g = svg.append("g");
          axisY(g);
        });

实际效果如下

页面如下
githubPage


相关文章:

  • 网页颜色-30天学会HTML+CSS,制作精美网站
  • 面临税务稽查的情况下 跨境电商该如何应对?
  • Day 6【React】阿嬷你怎麽没感觉?
  • Day 28:Google Map 显示目前位置
  • Day-2: Ruby on Rails 是什麽?
  • 跨境电商选品的逻辑:唯一性
  • Day 15 | 同步与非同步- Coroutines
  • Day 14 Compose GridLayout
  • Day 26. 双向绑定语法糖 - v-model
  • # Day24--开分支免费啦!超简易开分支的方法
  • Day 6 Dart语言-变数与常数
  • [Day4] 找出你的受众目标
  • 【PHP Telegram Bot】Day22 - ReplyKeyboardMarkup:让输入框下方出现按钮区域
  • Day 14 - Grid 排版
  • 跨境电商澳大利亚海外仓分销该如何寻找?
  • VPS评测:阿里、腾讯、百度、京东VPS最低配理性对比
  • 数字人民币是什么?什么是数字人民币
  • 阿里云需要实名认证吗?阿里云个人可以做企业认证吗
  • WordPress 5.7 引入函数来检查文章是否可以公开查看
  • 教程:阿里云国际版绑定香港PayPal购买方法
  • RPA是什么?Litrpa是什么?可以做什么好用吗?
  • 最便宜的国外VPS推荐:5美金以下的VPS大全
  • 让 Rank Math SEO 输出关键词 keywords meta 字段信息
  • 阿里云国际版怎么注册绑卡购买香港美国新加坡云主机【2020年最新教程】
  • 挖矿是什么?怎么挖矿怎么挖比特币?虚拟币比特币挖矿原理
  • 使用MailPoet扩展您的电子商务邮件列表
  • 印度独立站怎么做?如何做印度市场独立站商城
  • Jungle Scout选品工具中文版好用吗?亚马逊选品为什么要用JungleScout
  • Vultr促销码和2020年最新优惠:Vultr注册教程和使用方法
  • SiteGround域名转移教程:如何转出SiteGround域名