【D3.js 01】

D3.js 01

    • 说在前面
    • 1 概述
    • 2 配置Web环境
    • 3 HTML
    • 4 SVG
    • 5 DOM
    • 6 JS
    • 7 常用接口
    • 8 D3语法基础
    • 9 使用D3查询SVG
    • 10 使用D3设置SVG中属性
    • 11 修改整组属性
    • 12 使用D3添加与删除SVG元素
    • 13 数据读取 —— CSV数据
    • 14 D3.js的数值计算
    • 15 比例尺
      • Scale - Linear
      • Scale - Band
    • 16 引入坐标轴
    • 17 DATA-JOIN

说在前面

最近需要使用到D3.js,所以在B站上找到清华的D3.js教程,同时在这里做相关的自学笔记
原视频链接如下:

【数据可视化编程-使用D3.js(2022)】 https://www.bilibili.com/video/BV1qg411X7bB/?share_source=copy_web&vd_source=773b408053db6c74535b5afe2aa8feb9

1 概述

D3.js是目前最主流的,社区规模最大的,支持定制图元级别可视化效果的框架

相关文档:https://github.com/xswei/d3js_doc
D3画廊:https://observablehq.com/@d3/gallery

其他如Echarts不支持图元级别定制,但是支持图表混搭

之后课程会介绍动画与交互,可视化图表绘制,其他常用接口

D3: Data-Driven Documents
通过D3提供的接口基于数据操控文档(画布)的各个图元

接口约等于D3.js提供的函数调用

主要参考资料:

https://d3js.org/ 官网,文档,样例
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute SVG 属性参考
https://github.com/d3/d3 官方样例仓库
https://observablehq.com/@d3/gallery 官方样例仓库
https://github.com/xswei/d3js_doc d3.js资源汇总,包括示例、书籍、API文档等
https://github.com/Shao-Kui/D3.js-Demos

2 配置Web环境

D3.js基于JS,用于在Web前端控制HTML中的元素

  • 使用VScode,安装Live Server
  • 直接应用常用框架:Python Simple HTTP Server(不推荐),Node.js Simple HTTP Server,Flask, Express等

3 HTML

HyperText Markup Language
HTML包含大量元素(标签)

  • 元素之间类别不同,如矩形,直线,文本,圆等等
  • 元素包含属性,如位置,大小,色调,文本风格等等

  • 通过本地服务器链接 - ./d3.min.js
  • 通过unpkg链接 - https://unpkg.com/browse/[email protected]/dist/d3.js
    尽量使用本地的d3.min.js库
  • 4 SVG

    D3的绘制画布
    Scalable Vector Graphics 可缩放矢量图形

    5 DOM

    文档对象模型
    【D3.js 01】_第1张图片

    对于根节点的操作会影响子节点
    常用父节点中的

    • Axis可以封装为一个group
    • Legend(图例)可以封装为一个group

    6 JS

    解释型
    不需要编译
    JS语句类似于C与C++
    变量声明不需指定类型 int double function等,直接let, var const
    运算操作基本等同C,C++和Java
    下面是函数定义:

    function abc(a) { return a + 5; }
    const p = function(a, b){return a + b;}
    let f = datum => datum.value;
    let myFunction = (a, b) => a + b
    let f = (d, i) => { console.log(d);return d + I;}
    

    一个变量可以是一个函数
    类似于C/C++中的函数指针
    const myFunction = function(a, b){ return a + b; }
    回调(CallBack)
    JS脚本中常见将函数作为变量输入用于实现异步编程

    setTimeout( funciton() {
    	console.log('hello world')
    }, 1000);
    

    在D3中存在大量类似调用

    • 将函数作为参数给图元
    • 为每个数据点指定不同颜色
    • 配置坐标轴

    7 常用接口

    模版字符串

    let a = 10;
    let myString = `abc-${a}`;
    // myString最终为'abc-10'
    

    数组 a = [1, 2, 3]
    对象 a = {name: ‘Zane’, age: 24, lab: ‘cs’}
    D3数据可视化常见对象数组

    a = [{name:'Zane', age: 20, dept: 'cs'},
    		 {name:'LJD', age: 21, dept: 'cs'},
    		 {name: 'LH', age: 22, dept: 'ee'}]
    

    数组排序 a.sort()
    - 可以通过加入回调函数来替代缺省的排序方案,如为日期排序
    - a.sort(function(a, b){ return new Date(b.date) - new Date(a.date); }
    数组查询 a.find()
    a.find( d => d.name === ‘Zane’)

    将字符串转为数值 +(‘3.14’)
    D3.js经常读取CSV,JSON等文件,涉及大量数组,对象操作

    8 D3语法基础

    使用D3获取,修改,增加以及删除节点(图元)
    数据读取 - CSV
    数值计算
    比例尺:1. 线性比例尺 Linear Scale
    2. 条带比例尺 Band Scale
    坐标轴绘制: Margin
    Data-Join基础
    基于D3与Data-Doin绘制柱状图

    9 使用D3查询SVG

    d3.select(‘#rect1’) 永远返回第一个
    d3.selectAll(‘.class1’) 返回所有
    ID前加#,Class前加.,标签前不加

    层级查询
    d3.select(‘#maingroup rect’)
    d3.select(‘.tick text’)
    d3.selectAll(‘#secondgroup rect’)

    10 使用D3设置SVG中属性

    常见属性:

    • id, class (特殊属性,可使用.attr设置)
    • x, y, cx, cy (注意屏幕坐标系)
    • fill, stroke
    • height, width, r (圆的半径)
    • transform -> translate, rotate, scale

    SVG的属性非常多,并且属性的取值范围和类型各不相同

    1. 尽可能记住常见的属性来提高编程速度
    2. 遇见不认识的or想要设置某个属一定要查阅文档

    https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute

    屏幕空间的坐标系与常见坐标系不同
    左上方为原点
    y,x分别垂直向下、水平向右

    element.attr(…)
    设置元素属性: element.attr(‘attr_name’, ‘attr_value’)

    • 两参数:属性名,属性值
    • rect1.attr(‘y’, ‘100’)
    • d3.select(‘#rect1’).attr(‘y’, ‘100’)

    获取元素属性: element.attr(‘attr_name’)

    • 一参数: 属性名

    链式调用:

    • selection.attr(…).attr(…).attr(…)
    • .attr(…)返回的是选择的图元本身

    11 修改整组属性

    DOM
    父节点的属性会影响子节点
    子节点的属性相对于父节点
    以下代码可以直接移动组内的所有元素
    d3.select(‘#maingroup’).attr(‘transform’, ‘translate(200, 100)’)

    12 使用D3添加与删除SVG元素

    • element.append(…)

      • const myRect = svg.append(‘rect’);
      • const myRect = d3.select(‘#mainsvg’).append(‘rect’)
      • const myRect = d3.select(‘#mainsvg’).append(‘rect’).attr(‘x’, ‘100’)
    • D3的链式添加(调用)

      • const myRect = d3.select(‘#mainsvg’).append(‘g’).attr(‘id’, ‘maingroup’)
      • .append(‘rect’).attr(‘fill’, ‘yellow’)
    • element.remove()

      • 小心使用
      • 因为将移除整个标签
      • d3.select(‘#rect1’).remove()

    在debug过程中可以使用’opacity’属性hack出移除效果

    • element.attr(‘opacity’, ‘0’)

    13 数据读取 —— CSV数据

    第一行是属性列表,后面每一行对应一条数据
    CSV本质上是纯文本,区别于EXCEL格式

    • d3.csv(…):

      • 读取目标路径下的某一CSV文件
      • d3.csv(‘static/data/hello.csv’);
    • d3.csv是一个JavaScript异步函数:

      • 不可以直接获得其返回值
      • 不可以有 let myData = d3.csv(‘static/data/hello.csv’);
    • d3.csv(‘path/to/data.csv’).then( data => { // ‘数据读取后的代码逻辑’ } )

      • 需要通过.then( data => {…} )的方式获得读取后的数据
      • then(…)中的 data => {…} 是一个函数
      • 该函数接收的是输入参数,也即data,是读取后的数据
    • JavaScript异步机制

      • d3.csv是异步函数,即便没有读取完毕数据,后面的代码依旧继续执行
      • d3.csv被调用后的返回值是一个JavaScript的Promise对象(object)
      • Promise 询问:数据读取完毕后需要做什么,做什么即对应.then()中函数的内容

    读取后的数据格式(接口)与原本的CSV结构不同

    14 D3.js的数值计算

    数据可视化常常涉及对数据的处理与计算
    下面三个接口分别用于计算数组的最大值,最小值,[最小值, 最大值]

    • d3.max(array)

    • 返回数组中的最大值

    • d3.min(array)

    • 返回数组中的最小值

    • d3.extent(array)

    • 同时以数组的形式返回最小值与最大值

    数组中的内容可以是任意对象

    • 每个对象可能包含多个属性
    • 具体需要那个属性的最值可以通过回调函数提示d3.max, d3.min与d3.extent

    15 比例尺

    比例尺用于将实际数据空间映射到屏幕(画布)空间,也即两个空间转化
    用于映射数据和创建坐标轴,区别主要在于数据的尺度不同

    Scale - Linear

    d3.scaleLinear():

    • 定义一个线性比例尺,返回的是一个函数
    • 如 let scale = d3.scaleLinear(); // scale是函数

    scale.domain([min_d, max_d]).range([min, max]):

    • 设置比例尺的定义域与值域
    • 线性比例尺的定义域和值域都是连续的(Continuous),需要给出最大值与最小值
    • const scale = d3.scaleLinear().domain([20, 80]).range([0, 120]);

    比例尺本质上是函数

    • scale(20) // 0
    • scale(50) // 60

    常常结合读取的数据与d3.max等接口连用

    • const xScale = d3.scaleLinear().domain([0, d3.max(data, d => d.value)]).range([0, innerWidth]);

    Scale - Band

    d3.scaleBand():

    • 定义一个条带比例尺,返回一个函数
    • let scale = d3.scaleBand();

    scale.domain(array).range([min, max]):

    • 设置比例尺的定义域和值域
    • Band比例尺的定义域是离散的(Discrete),值域是连续的
    • 如 const scale = d3.scaleBand().domain([‘a’, ‘b’, ‘c’]).range([0, 120]);
    • 比例尺本质上是函数:
      • scale(‘b’) // 40
      • scale(‘c’) // 80

    d3.scaleBand()常常结合JS的array.map接口一同使用:

    • let a = [{name: ‘Zane’, value: 6}, {name: ‘LiHao’, value: 7}, {name:‘Ljd’, value: 8}]
    • a.map(d => d.name) // [‘Zane’, ‘LiHao’, ‘Ljd’]
    • const yScale = d3.scaleBand()
    • .domain(data.map(d => d.name))
    • .range([0, innerHeight])
    • .padding(0.1)

    scale.padding(0.1):
    设置条带间距占各自区域的比重

    scale.bandwidth():
    返回条带长度

    16 引入坐标轴

    一个坐标轴为一个group,也即
    通常需要两个坐标轴

    坐标轴中包含:

    • 一个用于横跨坐标轴的覆盖范围
    • 若干个刻度.tick,每个刻度也是一个group
    • 每个刻度下属包含一个和一个
      • 用于展示轴线,如左到右或上到下
      • 用于展示刻度值,如实数,姓名,日期
    • (可选)一个标签用于描述坐标轴

    坐标轴的定义需要比例尺

    定义坐标轴(获得结果仍是函数)

    • const yAxis = d3.axisLeft(yScale);
    • const xAxis = d3.axisBottom(xScale);
    • axisLeft: 左侧坐标轴
    • axisBottom: 底侧坐标轴
    • 坐标轴的刻度对应比例尺的定义域
    • 坐标轴在画布的绘制对应比例尺的值域
    • 仅仅是对坐标轴的定义,没有绘制

    绘制坐标轴

    • const yAxisGroup = g.append(‘g’).call(yAxis);
    • const xAxisGroup = g.append(‘g’).call(xAxis);
    • 实际配置后会发现中增加了与坐标轴相关的元素

    任何坐标轴在初始化之后会默认放置在坐标原点,需要进一步平移

    关于 selection.call(…)

    • 函数的输入为另一个函数
    • 另一个函数以selection本身(也即图元)作为输入
    • 另一个函数将根据函数体的内容修改selection对应的图元
    • 定义一个空白的,D3会帮助我们定义好另一个函数,我们通过.call(…)让得以在另一个函数中修改
      • const yAxis = d3.axisLeft(yScale);
      • const yAxisGroup = g.append(‘g’).call(yAxis);

    配置坐标轴
    可以对坐标轴的风格进行修改

    • 坐标轴本质上是图元的集合
    • d3.selectAll(‘.tick text’).attr(‘font-size’, ‘2em’);
    • .tick是D3对于坐标轴定义的统一class

    坐标轴的标签加入不在D3.Axis接口的负责范围内:

    • 通过对坐标轴的标签.append(‘text’)来实现
    • 左(纵)轴坐标需要.attr(‘transform’, ‘rotate(-90)’)来旋转
    • 纵轴坐标旋转后,x/y会颠倒甚至取值范围相反
    • 回忆DOM: 父节点属性会影响子节点,而坐标轴默认的’fill’属性是’none’,因此请一定手动设置文字颜色.attr(‘fill’, ‘black’)

    Margin
    SVG对于D3.js是一个画布
    SVG范围外的任何内容属于画布之外,浏览器不予显示

    • 而坐标轴通常初始化在所在父节点的左上角

    定义Margin:

    • const margin = {top: 60, right: 30, bottom: 60, left: 200}

    计算实际操作的inner长/宽

    • const innerWidth = width - margin.left - margin.right;
    • const innerHeight = height - margin.top - margin,.bottom;

    在SVG下额外定义一个组作为新的根节点

    - const g = svg.append('g').attr('id', 'maingroup')
    .attr('transform', `translate(${margin.left}, ${margin.top})`)
    

    HTML确实在样式表中提供margin属性,然而设置其他图元的位置,仍
    需要计算innerWidth(Height)

    调用示例

    const yAxis = d3.axisLeft(yScale) // .tickSize(-innerWidth);
    const xAxis = d3.axisBottom(xScale) // .tickSize(-innerHeight);
    
    const yAxisGroup = g.append('g').call(yAxis)
    .append('text')
    .text('Name')
    .attr('font-size', '3em')
    .attr('transform', 'rotate(-90)') // y-axis label needs an additional transform;
    .attr('x', -innerHeight / 2)
    .attr('y', -120)
    .attr('fill', 'black')
    const xAxisGroup = g.append('g').call(xAxis)
    .attr('transform', `translate(${0}, ${innerHeight})`)
    .append('text')
    .text('Value')
    .attr('font-size', '3em')
    .attr('x', innerWidth / 2)
    .attr('y', 50)
    .attr('fill', 'black');
    
    d3.selectAll('.tick text).attr('font-size', '2em');
    
    g.append('text').text('Members of CSCG').attr('font-size', '3em')
    .attr('x', innerWidth / 2 - 200).attr('y', -10)
    

    17 DATA-JOIN

    本质上是将数据与图元进行绑定
    以数据为中心的可视化操作(Data-Driven)

    • 根据数据自动调整图元属性
    • .attr(…)接口可以基于图元自己绑定的数据自动调整属性值

    数据发生变化时可以自动对图元增删改查

    • 不需要手动添加,修改,删除图元
    • 根据数据的增删改,自动增删改图元

    d3.selectAll(‘.class’).data(dataArray)
    dataArray在保证是数组的前提下可以是任何形式如数值数组,对象数组

    。。。

    你可能感兴趣的:(D3.js,javascript,开发语言,ecmascript)