D3 v7 快速上手:CDN、npm 与 React/Svelte 集成的完整接入指南

发布时间:2026/9/7 5:04:48
D3 v7 快速上手:CDN、npm 与 React/Svelte 集成的完整接入指南 D3 v7 快速上手CDN、npm 与 React/Svelte 集成的完整接入指南【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3D3Data-Driven Documents是一个运行在任何 JavaScript 环境中的数据可视化底层库。本篇基于官方入门文档 getting-started.md 与仓库源码带你完整走通 D3 v7 的四种接入方式在线环境、原生 HTML、npm、React/Svelte并解释每种方式背后的模块组织与打包机制读完即可在自己的项目中复制一套可运行的空白图表骨架。一、D3 的运行形态30 个子模块的聚合层理解 D3 接入方式之前先理解 D3 包本身的结构。从 package.json 可以看到当前仓库版本为7.9.0type: module要求 Node 12dependencies中声明了 30 个子模块d3-array、d3-axis、d3-brush、d3-chord、d3-color、d3-contour、d3-delaunay、d3-dispatch、d3-drag、d3-dsv、d3-ease、d3-fetch、d3-force、d3-format、d3-geo、d3-hierarchy、d3-interpolate、d3-path、d3-polygon、d3-quadtree、d3-random、d3-scale、d3-scale-chromatic、d3-selection、d3-shape、d3-time、d3-time-format、d3-timer、d3-transition、d3-zoom。D3 主包并不重复实现这些功能src/index.js 仅由 30 行export * from组成把每个子模块的全部导出平铺到d3命名空间下bundle.js 再补上从package.json导出的version字段。这也解释了为什么入门文档中d3.scaleUtc()、d3.axisBottom()、d3.line()都能直接从d3根对象访问。测试用例 test/d3-test.js 用一条自动化断言守住了这一契约遍历package.json的dependencies动态import每个子模块并断言其每个导出除version外都出现在d3命名空间中——从源码结构看D3 主包的角色就是“全量子模块的再导出re-export层”而不是独立的功能实现。这个结构直接决定了后文的三种加载策略可以整包引入获得全部 30 个子模块的符号也可以只从 CDN 或 npm 单独引入某个子模块。二、第一张图比例尺 坐标轴的空白图表骨架无论使用哪种加载方式入门文档给出的第一个示例都是同一个用d3.create创建一个 640×400 的 SVG 容器声明 x/y 两个比例尺再用d3.axisBottom/d3.axisLeft挂上坐标轴得到一个可以填充数据的空白图表。这也是文档内交互组件 ExampleBlankChart.vue 中实际渲染的代码。核心代码Observable 单元形式完整继承自原文档{ // Declare the chart dimensions and margins. const width 640; const height 400; const marginTop 20; const marginRight 20; const marginBottom 30; const marginLeft 40; // Declare the x (horizontal position) scale. const x d3.scaleUtc() .domain([new Date(2023-01-01), new Date(2024-01-01)]) .range([marginLeft, width - marginRight]); // Declare the y (vertical position) scale. const y d3.scaleLinear() .domain([0, 100]) .range([height - marginBottom, marginTop]); // Create the SVG container. const svg d3.create(svg) .attr(width, width) .attr(height, height); // Add the x-axis. svg.append(g) .attr(transform, translate(0,${height - marginBottom})) .call(d3.axisBottom(x)); // Add the y-axis. svg.append(g) .attr(transform, translate(${marginLeft},0)) .call(d3.axisLeft(y)); // Return the SVG element. return svg.node(); }几个值得注意的细节边距约定margin conventionx 轴的范围是[marginLeft, width - marginRight]y 轴是[height - marginBottom, marginTop]注意 y 轴起点在下、终点在上符合 SVG 坐标系坐标轴g通过transformtranslate(...)平移到边距边界上d3.create(svg)创建的是一个尚未插入文档的 SVG 元素需要显式返回Observable或container.append(svg.node())原生 HTML该示例同时涉及三个子模块d3-scalescaleUtc/scaleLinear、d3-selectioncreate/append/call、d3-axisaxisBottom/axisLeft。2.1 在线体验Observable 环境官方文档推荐的入门路径是在 Observable 笔记本中使用D3 作为 Observable 标准库的一部分默认可用只需让单元返回生成的 DOM 元素即可渲染。除了上面的空白图表文档列出了五个可 fork 的入门模板面积图Area chart、柱状图Bar chart、环形图Donut chart、直方图Histogram、折线图Line chart并在 Observable 的 D3 gallery 中收录了数百个可 fork 的笔记本作为起步参考。点击新建单元并输入 “d3” 可以过滤出内置的 D3 片段Observable 还提供样例数据集、CSV/JSON 上传等便利功能供练习。2.2 原生 HTML三种加载方式在原生 HTML 页面中文档给出三种等价写法示例逻辑与上面的空白图表完全一致区别仅在 D3 的引入方式。方式一ESM CDN文档推荐!DOCTYPE html div idcontainer/div script typemodule import * as d3 from https://cdn.jsdelivr.net/npm/d37/esm; // Declare the chart dimensions and margins. const width 640; const height 400; const marginTop 20; const marginRight 20; const marginBottom 30; const marginLeft 40; // Declare the x (horizontal position) scale. const x d3.scaleUtc() .domain([new Date(2023-01-01), new Date(2024-01-01)]) .range([marginLeft, width - marginRight]); // Declare the y (vertical position) scale. const y d3.scaleLinear() .domain([0, 100]) .range([height - marginBottom, marginTop]); // Create the SVG container. const svg d3.create(svg) .attr(width, width) .attr(height, height); // Add the x-axis. svg.append(g) .attr(transform, translate(0,${height - marginBottom})) .call(d3.axisBottom(x)); // Add the y-axis. svg.append(g) .attr(transform, translate(${marginLeft},0)) .call(d3.axisLeft(y)); // Append the SVG element. container.append(svg.node()); /script方式二UMD CDNUMD 包以普通script加载时会挂出全局d3对象适合无法使用 ES 模块的旧环境!DOCTYPE html div idcontainer/div script srchttps://cdn.jsdelivr.net/npm/d37/script script typemodule // Declare the chart dimensions and margins. const width 640; const height 400; const marginTop 20; const marginRight 20; const marginBottom 30; const marginLeft 40; // Declare the x (horizontal position) scale. const x d3.scaleUtc() .domain([new Date(2023-01-01), new Date(2024-01-01)]) .range([marginLeft, width - marginRight]); // Declare the y (vertical position) scale. const y d3.scaleLinear() .domain([0, 100]) .range([height - marginBottom, marginTop]); // Create the SVG container. const svg d3.create(svg) .attr(width, width) .attr(height, height); // Add the x-axis. svg.append(g) .attr(transform, translate(0,${height - marginBottom})) .call(d3.axisBottom(x)); // Add the y-axis. svg.append(g) .attr(transform, translate(${marginLeft},0)) .call(d3.axisLeft(y)); // Append the SVG element. container.append(svg.node()); /script方式三UMD 本地文件离线场景!DOCTYPE html div idcontainer/div script srcd3.js/script script typemodule // Declare the chart dimensions and margins. const width 640; const height 400; const marginTop 20; const marginRight 20; const marginBottom 30; const marginLeft 40; // Declare the x (horizontal position) scale. const x d3.scaleUtc() .domain([new Date(2023-01-01), new Date(2024-01-01)]) .range([marginLeft, width - marginRight]); // Declare the y (vertical position) scale. const y d3.scaleLinear() .domain([0, 100]) .range([height - marginBottom, marginTop]); // Create the SVG container. const svg d3.create(svg) .attr(width, width) .attr(height, height); // Add the x-axis. svg.append(g) .attr(transform, translate(0,${height - marginBottom})) .call(d3.axisBottom(x)); // Add the y-axis. svg.append(g) .attr(transform, translate(${marginLeft},0)) .call(d3.axisLeft(y)); // Append the SVG element. container.append(svg.node()); /script说明官方文档页面上的d3.v7.js/d3.v7.min.js下载链接指向由构建流程生成的 UMD 包——prebuild.sh 会在文档构建时把dist/d3.js和dist/d3.min.js复制为docs/public/d3.v7.js/docs/public/d3.v7.min.js因此这两个文件并不直接提交在源码树中。调试时使用非压缩版生产环境使用压缩版以获得更快的加载性能。UMD 全局d3从何而来从 rollup.config.js 可以看到构建产物dist/d3.js采用format: umd、全局变量名为d3并附加了版本与版权 banner同一配置还额外产出dist/d3.mjsESM 格式和dist/d3.min.js经 terser 压缩。package.json 中的files字段确认发布包携带dist/d3.js与dist/d3.min.jsjsdelivr/unpkg字段与exports[umd]都指向dist/d3.min.js——这就是上述 CDN 与 UMD 加载方式背后的产物。2.3 只加载需要的子模块如果只需要力导向图不必引入整个 d3 聚合包可以直接从 CDN 按需导入单个子模块的具名导出script typemodule import {forceSimulation, forceCollide, forceX} from https://cdn.jsdelivr.net/npm/d3-force3/esm; const nodes [{}, {}]; const simulation forceSimulation(nodes) .force(x, forceX()) .force(collide, forceCollide(5)) .on(tick, () console.log(nodes[0].x)); /script注意这里导入的是独立的d3-force3包而不是d37子模块在 npm 上按各自的 v3 线发布与主包 v7 并存各子模块的最低版本约束以 package.json 中的dependencies为准。三、从 npm 安装如果你的应用基于 Node 构建Vite、webpack 等打包环境用任意包管理器安装整包# yarn yarn add d3# npm npm install d3# pnpm pnpm add d3安装后有三种导入粒度// 1. 整体导入获得 30 个子模块的全部符号最常见 import * as d3 from d3; // 2. 具名导入只取需要的符号便于打包器摇树 import {select, selectAll} from d3; // 3. 子模块直连直接依赖 d3-array 等独立包 import {mean, median} from d3-array;从源码结构看package.json 将main/module都指向src/index.js所以包管理器解析到的入口正是那个 30 行再导出文件三种导入方式最终拿到的是同一套符号表。TypeScript 类型声明由社区维护的 DefinitelyTyped 库提供types/d3文档未将其内置于包中按需安装即可。四、D3 在 React 中D3 的模块大致分两类不触碰 DOM 的纯计算模块d3-scale、d3-array、d3-interpolate、d3-format 等——在 React 中与普通模块无差别可以直接在 JSX 里做纯声明式渲染操作 selection 的模块d3-selection、d3-transition、d3-axis——直接改写真实 DOM会与 React 的虚拟 DOM 冲突需要借助 ref useEffect把 D3 的写入限制在 React 不管理的节点内。模式一纯声明式无 DOM 操作。下面这个折线图组件只用了比例尺与 d3-shape 的lineSVG 元素全部由 React 渲染import * as d3 from d3; export default function LinePlot({ data, width 640, height 400, marginTop 20, marginRight 20, marginBottom 20, marginLeft 20 }) { const x d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]); const y d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]); const line d3.line((d, i) x(i), y); return ( svg width{width} height{height} path fillnone strokecurrentColor strokeWidth1.5 d{line(data)} / g fillwhite strokecurrentColor strokeWidth1.5 {data.map((d, i) (circle key{i} cx{x(i)} cy{y(d)} r2.5 /))} /g /svg ); }模式二ref useEffect需要 DOM 操作的坐标轴。给两个g挂 ref在 effect 里把 D3 选集交给坐标轴import * as d3 from d3; import {useRef, useEffect} from react; export default function LinePlot({ data, width 640, height 400, marginTop 20, marginRight 20, marginBottom 30, marginLeft 40 }) { const gx useRef(); const gy useRef(); const x d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]); const y d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]); const line d3.line((d, i) x(i), y); useEffect(() void d3.select(gx.current).call(d3.axisBottom(x)), [gx, x]); useEffect(() void d3.select(gy.current).call(d3.axisLeft(y)), [gy, y]); return ( svg width{width} height{height} g ref{gx} transform{translate(0,${height - marginBottom})} / g ref{gy} transform{translate(${marginLeft},0)} / path fillnone strokecurrentColor strokeWidth1.5 d{line(data)} / g fillwhite strokecurrentColor strokeWidth1.5 {data.map((d, i) (circle key{i} cx{x(i)} cy{y(d)} r2.5 /))} /g /svg ); }关键点useEffect的依赖数组传入[gx, x]/[gy, y]数据变化导致比例尺重建时坐标轴随之重绘而path与circle仍由 React 声明D3 只负责d3.axisBottom/d3.axisLeft内部生成的刻度与标签——两者各管各的 DOM 子树互不覆盖。五、D3 在 Svelte 中Svelte 的策略与 React 相同优先只用不操作 DOM 的模块做纯渲染需要 DOM 操作时再借bind:this把节点交给 D3。模式一纯声明式折线图使用 d3-shape 与 d3-scalescript import * as d3 from d3; export let data; export let width 640; export let height 400; export let marginTop 20; export let marginRight 20; export let marginBottom 20; export let marginLeft 20; $: x d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]); $: y d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]); $: line d3.line((d, i) x(i), y); /script svg width{width} height{height} path fillnone strokecurrentColor stroke-width1.5 d{line(data)} / g fillwhite strokecurrentColor stroke-width1.5 {#each data as d, i} circle key{i} cx{x(i)} cy{y(d)} r2.5 / {/each} /g /svg模式二响应式语句驱动动态坐标轴。Svelte 的$:响应式语句与 D3 的数据联结data join天然契合——数据一变语句重算坐标轴自动更新script import * as d3 from d3; export let data; export let width 640; export let height 400; export let marginTop 20; export let marginRight 20; export let marginBottom 30; export let marginLeft 40; let gx; let gy; $: x d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]); $: y d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]); $: line d3.line((d, i) x(i), y); $: d3.select(gy).call(d3.axisLeft(y)); $: d3.select(gx).call(d3.axisBottom(x)); /script svg width{width} height{height} g bind:this{gx} transform{translate(0,${height - marginBottom})} / g bind:this{gy} transform{translate(${marginLeft},0)} / path fillnone strokecurrentColor stroke-width1.5 d{line(data)} / g fillwhite strokecurrentColor stroke-width1.5 {#each data as d, i} circle key{i} cx{x(i)} cy{y(d)} r2.5 / {/each} /g /svg与 React 版对比Svelte 不需要useEffect来声明副作用边界bind:this$:语句本身就承担了这个职责因此框架内使用 D3 的“DOM 操作型”模块时Svelte 的样板代码更少。六、选型小结与后续路径场景推荐方式依据快速试验、教学演示Observable 在线笔记本D3 默认内置于其标准库单元返回 DOM 即渲染静态页面、一次性嵌入ESM CDNd37/esm官方推荐无构建步骤script typemodule直用旧环境 / 无模块支持UMD CDN全局d3dist/d3.js为 UMD 格式加载即挂全局离线 / 内网环境本地 UMD 文件非压缩版调试、压缩版生产Node 构建应用npm install d3 ES 导入入口即 src/index.js 再导出层React / Svelte纯计算模块声明式渲染selection 类模块走 ref /bind:this避免 D3 与虚拟 DOM 争抢节点入门之后可按主题沿仓库文档深入选择与数据联结见 d3-selection/selecting.md 与 d3-selection/joining.md比例尺体系见 d3-scale.md 及其下的 band/linear/ordinal 等专题文档图形生成器见 d3-shape/line.md 等完整 API 总览可参考 API.md。由于 D3 v7 是纯 ESM 发布type: module若你的运行环境不支持原生 ES 模块或import语法需要借助 UMD 包或自行使用打包工具做转译——这是选择加载方式时最核心的兼容性前提。【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻