当前位置: 首页 > news >正文

D3.js 完整详细使用教程(从入门到实战)

一、D3.js 基础介绍

1. 什么是 D3.js

D3(Data-Driven Documents,数据驱动文档)是基于SVG、Canvas、HTML的数据可视化 JS 库,核心思想:绑定数据 → 操作 DOM,把数据映射成图形元素(柱状图、折线图、地图、散点图等)。

2. 优势

  • 高度自定义,无封装死图表,可自由控制每一个图形细节
  • 内置强大比例尺、坐标轴、动画、布局、插值、地理计算工具
  • 兼容现代浏览器,轻量无依赖
  • 生态丰富:图表、力导向图、热力图、树形图、地图可视化

3. 引入 D3

方式 1:CDN(推荐,快速上手)
<!-- D3 v7 稳定最新版 --> <script src="https://d3js.org/d3.v7.min.js"></script>
方式 2:npm 项目
npm install d3
import * as d3 from 'd3'

二、核心核心概念:数据绑定 enter/update/exit(D3 灵魂)

D3 通过select/selectAll选中 DOM,用.data()将数组数据和 DOM 元素一一绑定,分为三种状态:

  1. enter:数据比 DOM 多 → 新增元素(画新图形)
  2. update:数据和 DOM 数量相等 → 更新现有元素(修改位置、颜色、尺寸)
  3. exit:DOM 比数据多 → 删除多余元素

基础绑定示例

<svg width="400" height="200"></svg> <script src="https://d3js.org/d3.v7.min.js"></script> <script> const data = [30, 80, 50, 120, 60]; const svg = d3.select("svg"); // 1. 绑定数据,获取三组状态 const rects = svg.selectAll("rect") .data(data); // exit:多余矩形删除 rects.exit().remove(); // update:已有矩形更新属性 rects.attr("x", (d, i) => i * 70) .attr("y", d => 200 - d) .attr("width", 60) .attr("height", d => d) .fill("#4285f4"); // enter:新增缺失矩形 rects.enter() .append("rect") .attr("x", (d, i) => i * 70) .attr("y", d => 200 - d) .attr("width", 60) .attr("height", d => d) .fill("#4285f4"); </script>

三、D3 基础 API 分类详解

1. 选择器 Select(操作 DOM)

// 单选 d3.select("#box") d3.select(".item") d3.select("svg") // 多选(返回集合) d3.selectAll("rect") d3.selectAll(".circle") // 链式修改属性/样式/文本 d3.select("rect") .attr("width", 100) // SVG属性 .style("fill", "red") // css样式 .text("文字") // 文本内容 .html("<b>富文本</b>")

2. 比例尺 Scale(可视化核心:数据→像素映射)

原始数据范围(域domain)→ 画布像素范围(范围range

(1)线性比例尺 scaleLinear(柱状图 / 折线图)

数值均匀映射

// 数据0~200 映射到画布高度0~180 const yScale = d3.scaleLinear() .domain([0, 200]) // 原始数据区间 .range([180, 0]); // 画布区间(svg y轴向下,倒置) console.log(yScale(100)); // 90
(2)序数比例尺 scaleOrdinal(分类颜色、分类 X 轴)

离散分类数据映射

const colorScale = d3.scaleOrdinal() .domain(["苹果", "香蕉", "橙子"]) .range(["red", "yellow", "orange"]); colorScale("香蕉"); // yellow
(3)band 分段比例尺 scaleBand(柱状图 X 轴均分)

自动均分宽度、设置内边距

const xData = ["1月","2月","3月","4月"] const xScale = d3.scaleBand() .domain(xData) .range([20, 380]) .padding(0.1); // 柱子间距 xScale.bandWidth() // 单根柱子宽度
其他常用比例尺
  • scaleLog:对数比例尺(跨度极大数据)
  • scaleTime:时间比例尺(时间轴折线图)
  • scalePow:幂等比例尺
  • scaleQuantize:分阶比例尺(热力图分级)

3. 坐标轴 Axis(自动生成 x/y 轴)

依赖比例尺,自动生成刻度、轴线、文字

// 生成x轴渲染函数 const xAxis = d3.axisBottom(xScale); // 底部x轴,刻度文字朝下 const yAxis = d3.axisLeft(yScale); // 左侧y轴 // 在svg中渲染坐标轴 svg.append("g") .attr("transform", "translate(0, 200)") // 下移放到底部 .call(xAxis); svg.append("g") .attr("transform", "translate(20, 0)") .call(yAxis);

transform="translate(x,y)":SVG 平移,解决坐标轴偏移问题

4. 动画 Transition

.transition()实现平滑过渡

rects.enter() .append("rect") .attr("height", 0) // 初始高度0 .transition() // 开启动画 .duration(800) // 动画时长ms .delay((d,i)=>i*100) // 每个柱子延迟错开 .attr("height", d=>d)

5. 数据处理工具 d3-array

const data = [10,50,30,90]; d3.max(data) // 最大值 90 d3.min(data) // 最小值 10 d3.sum(data) // 总和 d3.mean(data) // 平均值 d3.range(0,10) // [0,1,2...9]

四、实战 1:完整柱状图(可直接复制运行)

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>D3 柱状图完整示例</title> <style> svg { border: 1px solid #eee; } </style> </head> <body> <svg width="500" height="300"></svg> <script src="https://d3js.org/d3.v7.min.js"></script> <script> // 1. 数据源 const dataset = [ {month:"1月",value:80}, {month:"2月",value:120}, {month:"3月",value:60}, {month:"4月",value:150}, {month:"5月",value:90} ] const width = 500; const height = 300; const margin = {top:20, right:20, bottom:40, left:40}; // 边距 // 画布 = 总宽高 - 边距 const innerW = width - margin.left - margin.right; const innerH = height - margin.top - margin.bottom; // 2. 创建svg画布,整体右移下移留出边距 const svg = d3.select("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", `translate(${margin.left},${margin.top})`); // 3. 创建比例尺 // X轴 band比例尺 const xScale = d3.scaleBand() .domain(dataset.map(d=>d.month)) .range([0, innerW]) .padding(0.15); // Y轴线性比例尺 const yScale = d3.scaleLinear() .domain([0, d3.max(dataset, d=>d.value)]) .range([innerH, 0]); // 4. 坐标轴 const xAxis = d3.axisBottom(xScale); const yAxis = d3.axisLeft(yScale); // 渲染X轴(放在画布底部) svg.append("g") .attr("transform", `translate(0,${innerH})`) .call(xAxis); // 渲染Y轴 svg.append("g") .call(yAxis); // 5. 绘制柱状图 enter/update/exit const bars = svg.selectAll("rect") .data(dataset); bars.exit().remove(); bars.attr("x", d=>xScale(d.month)) .attr("y", d=>yScale(d.value)) .attr("width", xScale.bandwidth()) .attr("height", d=>innerH - yScale(d.value)) .fill("#3498db"); bars.enter() .append("rect") .attr("x", d=>xScale(d.month)) .attr("width", xScale.bandwidth()) .attr("y", innerH) // 初始在底部 .transition().duration(1000) .attr("y", d=>yScale(d.value)) .attr("height", d=>innerH - yScale(d.value)) .fill("#3498db"); </script> </body> </html>

五、实战 2:折线图(时间轴示例)

<svg width="600" height="300"></svg> <script src="https://d3js.org/d3.v7.min.js"></script> <script> const data = [ {date:new Date("2025-01-01"), val:20}, {date:new Date("2025-02-01"), val:45}, {date:new Date("2025-03-01"), val:32}, {date:new Date("2025-04-01"), val:60}, {date:new Date("2025-05-01"), val:48} ] const margin = {t:20, r:20, b:30, l:40}; const w = 600 - margin.l - margin.r; const h = 300 - margin.t - margin.b; const svg = d3.select("svg") .append("g") .attr("transform",`translate(${margin.l},${margin.t})`); // 时间比例尺 const x = d3.scaleTime() .domain(d3.extent(data, d=>d.date)) .range([0,w]); const y = d3.scaleLinear() .domain([0, d3.max(data, d=>d.val)]) .range([h,0]); // 折线生成器 line const line = d3.line() .x(d=>x(d.date)) .y(d=>y(d.val)) .curve(d3.curveMonotoneX); // 平滑曲线 // 绘制折线path svg.append("path") .datum(data) // 单组数据绑定用datum .attr("fill","none") .attr("stroke","#e74c3c") .attr("stroke-width",2) .attr("d", line); // 坐标轴 svg.append("g").attr("transform",`translate(0,${h})`).call(d3.axisBottom(x)); svg.append("g").call(d3.axisLeft(y)); // 圆点标记 svg.selectAll("circle") .data(data) .enter() .append("circle") .attr("cx",d=>x(d.date)) .attr("cy",d=>y(d.val)) .attr("r",4) .fill("#e74c3c"); </script>

六、常用布局 Layout(复杂图表)

D3 内置布局函数,专门处理复杂图形数据转换,只需要传入数据,返回图形坐标:

  1. d3.pie():饼图 / 环形图布局
  2. d3.forceSimulation():力导向网络图
  3. d3.tree() / d3.hierarchy:树形图、组织架构图
  4. d3.arc():饼图扇形生成器
  5. d3.map/geo:地图地理投影

饼图极简示例

const pieData = [10,20,30,40]; const pie = d3.pie(); // 饼图布局 const arcs = pie(pieData); // 转换为扇形坐标数据 const arc = d3.arc() .innerRadius(0) // 内半径,大于0就是环形图 .outerRadius(100); svg.selectAll("path") .data(arcs) .enter() .append("path") .attr("d", arc) .fill((d,i)=>d3.schemeSet2[i]);

七、交互:鼠标事件、tooltip

1. 鼠标监听

bars.on("mouseover", function(event, d){ d3.select(this).style("fill","#ff6600"); }) .on("mouseout", function(){ d3.select(this).style("fill","#3498db"); }) .on("click", (e,d)=>{ console.log("点击数据", d) })

2. Tooltip 悬浮提示

.tooltip { position:absolute; padding:6px 10px; background:#222; color:#fff; border-radius:4px; pointer-events:none; opacity:0; }
<div class="tooltip"></div>
const tooltip = d3.select(".tooltip"); bars.on("mouseover", (e,d)=>{ tooltip.html(`数值:${d.value}`) .style("left", e.pageX + "px") .style("top", e.pageY - 20 + "px") .style("opacity",1); }).on("mouseout", ()=>{ tooltip.style("opacity",0) })

八、D3 分层开发规范(工程化推荐)

  1. 边距模式 margin convention:统一预留上下左右边距,避免坐标轴被截断(上面示例全部使用)
  2. 分离数据、比例尺、坐标轴、图形渲染逻辑
  3. 图表封装成函数,支持传入配置(宽高、颜色、数据)
  4. 数据更新只调用一次渲染函数,依赖 enter/update/exit 自动 diff
  5. 样式分离,尽量用 class 代替 inline style

九、常见踩坑问题

  1. SVG y 轴向下,比例尺 range 必须倒置 [maxH, 0],否则柱子倒置
  2. .data()绑定数组,单条数据用.datum()
  3. 坐标轴需要.call(axis)才能渲染
  4. 折线 path 使用fill:none,否则会填充闭合区域
  5. 动画 transition 只能写在修改属性前
  6. 页面缩放模糊:svg 设置宽高,不要用 css 拉伸

十、官方资源 & 拓展学习

  1. 官方文档:https://d3js.org/
  2. 官方示例图库:https://observablehq.com/@d3/gallery(海量可编辑可视化案例)
  3. D3 API 完整手册:https://github.com/d3/d3/blob/main/API.md
  4. 进阶方向:地图可视化、3D 结合、Canvas 渲染大数据、交互式大屏

十一、扩展练习路线

  1. 基础:柱状图 → 横向柱状图 → 折线图 → 散点图
  2. 中级:饼图 / 环形图、堆叠柱状图、面积图、Tooltip 交互
  3. 高级:树形图、力导向网络图、中国地图、热力图、动态实时更新图表
http://www.cnnetsun.cn/news/3027256.html

相关文章:

  • ScaleTail:自托管服务一键接入 Tailscale 网络
  • OpenAI芯片Jalapeño亮相,能否打破英伟达算力垄断?
  • 自己开店怎么弄扫码点餐,扫码点餐小程序,门店盈利翻倍的秘密武器
  • 基点起源半年订单金额升一级,工业AI系统为传统行业提质增效、降本千万!
  • AI 能力溢出,人成瓶颈!深度解析写代码与网关重写中的技术变革与决策挑战
  • 开源跨平台终端工具 uniTerm v1.1 系列发布,新增串口、WSL 支持及 22 款终端主题
  • 2026年小程序开发公司哪家好?从价格、周期、功能和售后看选择
  • cURL 8.21.0 发布:创单次发布 18 个漏洞新纪录,新增功能与错误修复并存
  • Day8 Java线程池终极指南:7个参数你真的理解了吗
  • CSS核心知识体系深度梳理:从基础到进阶的完整思维导图
  • 手机内存融合彻底翻车:8G+8G看似16G,实际体验不如原生12G
  • sanag 塞那S6S Ultra入门开放式AI音频场景信息发布
  • 零基础怎么做AI数据标注?我的入门实践记录
  • 小红书 商品详情 + 关键词 API 调用实战分享:精准降本、高效运营
  • Android 7系统输入(一):从硬件到应用的事件旅程
  • 低代码平台2026真相:实在Agent凭啥让业务人员5分钟上手自动化?
  • 数字员工与AI销冠系统是什么?它们在提高企业效率中有哪些重要作用?
  • 第一次选远程控制软件怎么不踩坑?6款主流工具实测告诉你答案
  • 2026 年 5 款企业数字人直播系统横评:全场景效果实测适配建议
  • 风爆远征 - 英雄年代手游官网下载:风爆远征英雄年代最新官方下载渠道
  • 多卡并行怎么配,AMD GPU 张量并行实战笔记
  • 海龟实验室的网页版
  • CMake变量赋值
  • 基于DeepSeek的AI作文批改系统
  • 公共子序列(动态规划)
  • Agent Harness:2026 年 AI 工程最重要的概念,一篇文章讲透
  • AI 写小说能力深度评测与实战指南
  • 这9款开发工具夯爆了,用了都说好
  • AI漫剧剪辑生成主流AI创作工具与工作流盘点
  • 告别随手记事杂乱无章,一站式收纳生活工作任务,条理规划日程完整步骤