Day19-D3 的 RWD 图表

本篇大纲:window.resize、RWD 图表、轴线刻度数量随画面变化增减

前两篇看完比例尺跟轴线後,现在D3的知识拼图就只差最後这块啦!今天我们要学的是怎麽画「响应式图表」,也就是让图表在画面放大或缩小时,都能够随着画面去调整图表的大小!这个章节也是轻松简单的单元,只是有比较多细节需要设定,一起来看一下吧~

在之前的篇章中,我们建立的 svg 都有固定的宽高,这样的图表在网页上看很OK,但如果要在手机或平板上看,就会发现图表太大无法看

https://i.imgur.com/wcKVhbV.gif

为了使用者在手机或平板上也能够看图表,因此我们要对图表进行一些设定,让它变成下面这样

https://i.imgur.com/9U8gPge.gif

Window.resize 事件

要设定RWD图表的话,我们需要使用到 window 的 onresize 事件,每当 window 监听到画面大小有变化时,就会触发设定的方法。首先,我们先用d3的选取器把window选起来接着使用 selection.on( )的方法监听 resize 事件,并设定画面 resize 的时候要做什麽事

d3.select(window).on('resize', function(){
		console.log('画面变化')
  });

这样一来,画面大小变化时,就会触发我们设定好的功能啦(请看画面右方的 console 讯息)~
https://i.imgur.com/EEZRyud.gif

设定外容器宽度

接着,我们要来设定外容器的高度。如果我们的 svg 是包在div中的话,就是设定这个div的宽度。

<div class="RWDChart">
	<svg>......</svg>
</div>

我们使用 css 把外容器的宽度设定成百分比,让外容器能随着画面变化而缩放

.RWDChart{
    width: 80%
}

设定 svg 宽高

再来设定 svg 的宽高吧!之前我们的 svg 宽高都是直接写死

const width = 500,
      height = 400;

const svg = d3.select('.simpleChart')
              .append('svg')
              .attr('width', width)
              .attr('height', height)

现在我们要改变作法,用外容器RWD的宽度来设定 svg 的宽高。

  • svg 宽度:用 d3.selection 抓到外容器的宽度,接着用 parseInt( )将这个宽度赋予给 rwdSvgWidth 变数,接着将这个变数设定成 svg 的宽度
  • svg 高度:用刚刚设定好的 rwdSvgWidth 来设定 rwdSvgHeight 变数,并将 rwdSvgHeight 设定成 svg 的高度
const rwdSvgWidth = parseInt(d3.select('.RWDChart').style('width')),
      rwdSvgHeight = rwdSvgWidth*0.8,
      margin = 30,
      bandWidth = 20 

const svg = d3.select('.RWDChart')
              .append('svg')
              .attr('width', rwdSvgWidth)
              .attr('height', rwdSvgHeight);

这样一来,我们的 svg 宽高就能够随着画面缩放而增减啦!

RWD图表

现在我们可以开始绘制RWD的图表啦!由於这边的重点是RWD,因此绘制图表的程序码就先不呈现,而是着重在要怎麽让图表RWD上

function RWDChart(){
		const rwdSvgWidth = parseInt(d3.select('.RWDChart').style('width')),
		      rwdSvgHeight = rwdSvgWidth*0.8,
		      margin = 30,
		      bandWidth = 20 
		
		const svg = d3.select('.RWDChart')
		              .append('svg')
		              .attr('width', rwdSvgWidth)
		              .attr('height', rwdSvgHeight);

		// 以下为绘制图表的程序码
		// ......
		// ......
}

RWDChart() // 一开始要先执行一次,才能在画面开始时建立图表
d3.select(window).on('resize', RWDChart); // 接着要在每次画面变化时都重新渲染图表

重新渲染导致图表重复

但这时候出现一个新的问题:每次画面变化重新渲染图表时,我们的图表就会一直不停重复增加!!
https://ithelp.ithome.com.tw/upload/images/20211001/20134930o66vT249BH.jpg

这是因为画面变化时会重新渲染图表,但原本的图表也都还存在,导致图表不停的往下增加。因此我们要加上一段程序,让每次图表绘制前,都会删除掉原本的图表

function RWDChart(){
		**d3.select('.RWDChart svg').remove(); // 删除前一次建立的图表**

		const rwdSvgWidth = parseInt(d3.select('.RWDChart').style('width')),
		      rwdSvgHeight = rwdSvgWidth*0.8,
		      margin = 30,
		      bandWidth = 20 
		
		const svg = d3.select('.RWDChart')
		              .append('svg')
		              .attr('width', rwdSvgWidth)
		              .attr('height', rwdSvgHeight);

		// 以下为绘制图表的程序码
		// ......
		// ......
}

RWDChart() // 一开始要先执行一次,才能在画面开始时建立图表
d3.select(window).on('resize', RWDChart); // 接着要在每次画面变化时都重新渲染图表

这样一来,就可以解决图表重复出现的问题啦~

轴线刻度数量随画面变化增减

最後,我们要讲一个有趣的功能~当图表随画面缩小时, 有时候坐标轴的刻度会因为图表缩小而重叠在一起
https://ithelp.ithome.com.tw/upload/images/20211001/20134930K9IxV3Uyo2.jpg

为了不让刻度重叠,我们要在图表缩小时减少刻度的数量。这时候就要用到 window.innerWidth 跟 ticks 设定的方法啦!

先来设定一个 tickNumber 的变数,并且:

  • 当画面宽度大於 450 时,tickNumber 的值是null
  • 当画面宽度大於 450 时,tickNumber 的值是 5

最後将 tickNumber 作为参数带给 .ticks( ) 这个方法。由於这边不是在讲解如何建立图表,因此就只把刻度RWD的程序码撷取出来。想看完整程序码的人请直接到下方的 Giithub 页面查看~

// rwd X轴的刻度
let tickNumber = window.innerWidth > 450 ? null : 5;

xAxis = d3.axisBottom(xScale)
                .ticks(tickNumber)
                .tickFormat(function (d) {
                  //调整标签样式
                  return `${d} 元`;
                })

这样就完成罗!
https://i.imgur.com/4bdACrb.gif

今天的内容就到这边。这样一来,D3 绘图的重要知识都已经全部讲解完毕啦!接下来我们就要运用这几天学到的知识去绘图罗!一天一张图表,我来了!!


Github Page 图表与 Github 程序码

最後附上本章的程序码与图表 GithubGithub Page,需要的人请自行取用~


<<:  Day24-"取址运算子、提令运算子"

>>:  JavaScript学习日记 : Day19 - Class继承

【Day 08】工厂方法设计模式(Python)

前言 上一篇我们讨论DDD的战术设计,它建议引用各种设计模式,提高生产力,因此接下来,就来介绍各种设...

主管与技术团队的分工

我自己是从RD出身的主管,我自己也想了很久,我到底做对了什麽,与可能做错了什麽,让我自己培养出这样的...

Day 19 Docker Compose 操作指令

使用 docker compose 来串起一连串的 Container 服务前,这边先笔记下一些在过...

【Day10】Flutter环境设定 ( windows )

在拖延症的影响下,周日原本打算多备点稿的我又变成只有当日更新。 可能以後要强制自己每天多写一篇比较实...

[DAY28]GKE-Google Kubernetes Engine

GKE GKE是GOOGLE在GCP上面的k8s cluster服务,对於GCP使用者来说,GKE可...