简介
- D3.js 是一个 JavaScript 库,用于在 Web 上创建图表、地图等可视化效果。
- D3 是
Data-Driven Documents(数据驱动文档)的简称 - 它使用可缩放矢量图形 (
SVG)、HTML5和级联样式表(CSS) 标准 - 与许多其他提供现成图表的数据可视化库不同,D3 为您提供了很大的创作自由,因为您可以完全控制您创建的可视化。D3 还使用 HTML、CSS、SVG 和 JavaScript 等 Web 技术。
特点:
- D3
速度极快, - 它鼓励代码可
重用性 - 它支持
大型数据集,并提供了一种加载和转换数据的简单方法 - 它非常适合创建具有
丰富交互的可视化效果
你得知道的 SVG
因为 D3 是基于 SVG 的
SVG,指可缩放矢量图形(Scalable Vector Graphics),是用于描述二维矢量图形的一种图形格式,是由万维网联盟制定的开放标准。SVG 使用 XML 格式来定义图形,绝大部分浏览器都支持 SVG,可将 SVG 文本直接嵌入 HTML 中显示。 SVG 有如下特点:
- SVG 绘制的是矢量图,因此对图像进行放大不会失真。
- 基于 XML,可以为每个元素添加 JavaScript 事件处理器。
- 每个图形均视为对象,更改对象的属性,图形也会改变。
环境准备
CDN 地址
NPM
yarn add d3
使用
import * as d3 from "d3";
// or
import { select, selectAll } from "d3";
元素选择
采用任何
CSS 选择器并返回与指定选择器匹配的元素。如果没有元素与选择器匹配,它将返回一个空选择。
d3.select():匹配它找到的第一个元素。d3.selectAll(): 选择与选择器匹配的所有元素
选择 DOM 并设置属性
d3.select("#d3_p").style("color", "blue");
d3.selectAll(".d3_p").style("color", "blue");
属性方法介绍
| 方法 | 解释 | 示例 |
|---|---|---|
.attr() | 更新所选元素属性 | d3.select("p").attr("name", "fred") |
.classed() | 在选定元素上赋值或取消赋值指定的 CSS 类名 | d3.select("p").classed("radio", true); |
.style() | 更新 style 属性 | d3.select("p").style("color", "blue"); |
.property() | 用于设置元素属性 | d3.select('input').property('value', 'hello world') |
.text() | 更新选定的元素文本内容 | d3.select('h1').text('Learning d3.js') |
.html() | 将内部 HTML 设置为所有选定元素的指定值 | d3.select('div').html('h1>learning d3.js') |
.append() | 追加一个新元素作为所选元素的最后一个子元素 | d3.select("div").append("p") |
.insert() | 追加一个新元素作为所选元素的最后一个子元素 | d3.select("div").insert("p", "h1") |
.remove() | 追加一个新元素作为所选元素的最后一个子元素 | d3.select("div").remove("p") |
上面的实例中,第二个参数是一个常量,第二个参数还可以是一个函数,例如:
d3.selectAll("circle").attr('cx', ((d, i) => i * 100))
数据驱动
- D3 是数据驱动的,它是支持 数组, CSV, XML, TSV, JSON 等数据格式,
- 数据原来:本地、服务器、第三方 API
- 使用
.data()方法向选中的元素中添加数据
let fruits = ['Apple', 'Orange', 'Mango']
d3.selectAll(".d3_fruit").data(fruits).text((d) => d)
// html
<p class="d3_fruit"></p>
输出结果
我们只能等到一个输出
<p class="d3_fruit">Apple</p>
join 函数
绑定 data 数据到空的选择器上, 内部自动创建空元素
import { useEffect, useRef } from 'react';
import { select, selectAll } from 'd3';
function App() {
let d3Dom = useRef<HTMLDivElement | null>(null);
useEffect(() => {
console.log(d3Dom.current!.id, '..');
let data = ['Apple', 'Orange', 'Mango'];
select(d3Dom.current)
.selectAll('div')
.data(data)
.join('div')
.text((e: string) => e);
// selectAll('p')
// .selectAll('div')
// .data(data)
// .join('div')
// .text((e: string) => e);
});
return (
<>
<p>select , selectAll</p>
<div id="d3" ref={d3Dom}></div>
</>
);
}
export default App;
数据加载方式
支持数据格式: :json 、csv 、xml、tsv、text
加载数据函数: :d3.json(url) 、d3.csv(url) 、d3.xml(url)、d3.tsv(url)、d3.text(url)
import { useEffect, useRef } from "react";
import { select, json } from "d3";
function LoadData() {
const d3Dom = useRef<HTMLDivElement | null>(null);
const loadData = async () => {
const data = await json<string>("./data.json");
select(d3Dom.current)
.selectAll("div")
.data(data!)
.join("div")
.text((e: string) => e);
};
useEffect(() => {
loadData();
});
return (
<>
<p>LoadData</p>
<div id="d3_1" ref={d3Dom}></div>
</>
);
}
export default LoadData;
Scale(比例 or 缩放)
简单描述,如果我们要展示一个地区跟人口相关的一个柱状图表,我们要展示的人口数量在(2w-200W)之间,我们不能让图表上显示 200w 个像素点
scale 需要设置
domain和range, (domain 代表缩放后的范围,range 代表真实数据的范围)
语法
// scaleLinear(domain, range)
d3.scaleLinear([0, 100], ["red", "blue"]);
d3.scaleLinear().domain([10, 500]).range([2000000, 16000000]); // 将 2w-160w ,限制在了10-500像素点显示
scale 有很多种类
Linear scales:- 用于定量数据Time scales:- 用于时间序列数据Pow scales:- 用于定量数据(范围很广)Log scales:- 用于定量数据(范围很广)Symlog scales:- 用于定量数据(范围很广)Ordinal scales:- 用于分类或序数数据Band scales:- 用于作为位置编码的分类或有序数据Point scales:- 用于作为位置编码的分类或有序数据Sequential scales:- 用于将定量数据作为顺序颜色编码Diverging scales:- 将定量数据作为发散颜色编码Quantile scales:- 用于作为离散编码的定量数据Quantize scales:- 将定量数据作为离散编码Threshold scales:- 将定量数据作为离散编码
用 D3 创建一个 柱状图
- 定义 x,y 轴的范围
const width = 960,
height = 500;
const x_scale = d3.scaleBand().range([0, width]);
const y_scale = d3.scaleLinear().range([height, 0]);
- 选择 DOM
const svg = d3.select("#d3_demo").attr("width", width).attr("height", height);
- 获取数据
d3.json(
"https://raw.githubusercontent.com/iamspruce/intro-d3/main/nigeria-states.json"
).then(({ data }) => {
data.forEach((d) => (d.Population = +d.info.Population));
});
- 设置 domain
x_scale.domain(data.map((d) => d.Name);
y_scale.domain([0, d3.max(data, (d) => d.Population)]);
- 展示区域设置
svg
.selectAll("rect")
.data(data)
.join("rect")
.attr("class", "bar")
.attr("x", (d) => x_scale(d.Name)) // 设置每个 react 在x轴上的位置
.attr("y", (d) => y_scale(d.Population))
.attr("width", x_scale.bandwidth()) // 设置每一个 rect的 宽
.attr("height", (d) => height - y_scale(d.Population));
Axis 轴线
给图表上添加轴线,让图表更可读
创建不同方向上的轴线
- d3.axisTop
- d3.axisBottom
- d3.axisLeft
- d3.axisRight
代码示例
let svg = d3.select('#d3_demo8').attr('width', 200).attr('height', 200)
let scale = d3.scaleLinear().domain([0, 100]).range([0, 200])
let bottom_axis = d3.axisBottom(scale)
svg.append('g').call(bottom_axis)
// html
<svg id="d3_demo"></svg>
给上面图表添加坐标
边缘设定
// 定义一个 边缘对象
const margin = { top: 20, right: 30, bottom: 55, left: 70 };
// 定义宽高变量
const width = document.querySelector("body").clientWidth;
const height = 500;
// 设置 svg的宽高
const svg = d3.select("#d3_demo").attr("viewBox", [0, 0, width, height]);
const x_scale = d3
.scaleBand()
.range([margin.left, width - margin.right]) // 结合nargin , 设置 x轴的范围
.padding(0.1);
const y_scale = d3.scaleLinear().range([height - margin.bottom, margin.top]); // 结合nargin , 设置 Y 轴的范围
设置轴线
let x_axis = d3.axisBottom(x_scale);
let y_axis = d3.axisLeft(y_scale);
// 最加 x 轴线
svg
.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(x_axis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// 最加 y 轴线
svg.append("g").attr("transform", `translate(${margin.left},0)`).call(y_axis);
给 D3 设置 css
.attr("class", "bar")
.bar {
fill: green;
}
完整代码:
最近好像
stackblitz.com对一些 cdn 访问有了限制,可能代码不能在线运行,但是不影响下载,下载后可以直接运行,查看运行结果
交互性
监听事件
为 SVG 元素添加事件监听器。
svg.selectAll("rect").on("mouseover", function (event, d) {
d3.select(this).style("fill", "red");
});
更新数据
根据新的数据更新图表。
const newData = [40, 50, 20, 70, 30];
svg
.selectAll("rect")
.data(newData)
.transition()
.duration(1000)
.attr("y", (d, i) => 250 - d * 2);
结语
D3.js 是一个功能丰富、灵活的数据可视化库。通过本教程,你应该已经对 D3.js 有了深入的了解,并且能够开始在项目中应用 D3.js 技术。随着实践的深入,你将能够发掘 D3.js 更多的潜力,创造出令人惊叹的视觉效果。