ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

d3-selection 控制流详解:each、call、nodes 等 7 个方法的用法与实现原理

d3-selection 控制流详解:each、call、nodes 等 7 个方法的用法与实现原理 d3-selection 控制流详解each、call、nodes 等 7 个方法的用法与实现原理【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3在 d3 的数据驱动绘图流程中选中 DOM 元素只是第一步真正的定制往往发生在“对选区做点什么”的阶段。d3-selection 为此提供了一组控制流 APIselection.each、selection.call用于对每个选中元素执行任意代码或复用组件函数nodes、node、size、empty与[Symbol.iterator]则用于把选区还原为普通 DOM 节点数组以配合原生 JavaScript。读完本文你将能熟练掌握这 7 个方法的签名、参数与返回值差异并结合本仓库中的真实示例理解它们在坐标轴、缩放、拖拽等组件中被复用的方式。控制流方法在 d3-selection 中的定位selection 模块总览 把 d3-selection 的能力划分为六大主题选取元素selecting、修改元素modifying、数据联结joining、事件处理events、控制流control flow与局部变量locals。其中控制流Control flow文档的定位是“For advanced usage, selections provide methods for custom control flow”——面向进阶用法让选区能够以开发者自定义的方式遍历与调用。也就是说控制流方法是 d3 选区体系里的“逃生舱口”当你需要逐元素执行任意逻辑例如同时访问父子数据、操作this上下文用each或迭代器当你需要把选区当作参数传给可复用函数并保持链式调用用call当你需要跳出 d3 API、直接操作原生 DOM交给第三方库、挂载到页面、做测量计算用nodes、node、size、empty。本仓库的入口 src/index.js 通过export * from d3-selection把这些 API 原样汇入d3命名空间因此下面所有方法都可以通过d3.select(...)/d3.selectAll(...)返回的选区对象直接调用。selection.each(function)逐元素执行回调签名selection.each(function)行为按 DOM 顺序对每个选中元素调用一次指定函数。函数收到的参数为参数含义d第一个参数当前元素绑定的数据current datumi第二个参数当前元素在选区中的索引nodes第三个参数当前选区组group即整个节点数组this当前 DOM 元素本身即nodes[i]典型用途是创建能同时访问父数据与子数据的作用域。原文档给出的示例parent.each(function(p, j) { d3.select(this) .selectAll(.child) .text(d child ${d.name} of ${p.name}); });这里外层each回调中的p是父元素的数据this是父 DOM 元素通过d3.select(this)从父元素内部再选出所有.child于是内部回调里的d子数据与p父数据同时可见。这种“父上下文 子选区”的组合是each最经典的实战场景例如渲染一组尺寸各异的子环图donut multiples。仓库中 locals.md 的多个示例也依赖each提供的this上下文来在元素上读写局部变量modifying.md 则展示each结合selection.classed等修改方法的用法。可以推断凡是回调里需要“以当前元素为出发点再选一遍”的场景each都是首选入口。与迭代器的区别each的回调参数是(d, i, nodes)而原生for...of迭代只返回节点本身需要额外通过d3.select(node).datum()取数据。两者可互为补充。selection.call(function, ...arguments)可复用组件的关键签名selection.call(function, ...arguments)行为恰好一次调用指定函数把当前选区作为第一个参数、其余参数按原样传入无论被调函数返回什么call本身始终返回该选区。这与手工调用函数等价但让链式调用得以延续。文档示例——把“设置若干样式”封装为可复用函数function name(selection, first, last) { selection .attr(first-name, first) .attr(last-name, last); }然后d3.selectAll(div).call(name, John, Snow);大致等价于name(d3.selectAll(div), John, Snow);唯一的区别是selection.call永远返回selection而不是被调函数name的返回值。这个“返回值恒为选区”的语义正是它能无缝嵌入append → call → attr → transition链式调用的原因。仓库中的真实用例call是 d3 组件化设计的基石本仓库文档与组件代码中大量出现坐标轴docs/d3-axis.md 中所有示例都以svg.append(g).call(d3.axisBottom(x))挂载坐标轴刷选与拖拽docs/d3-brush.md 用d3.select(...).call(d3.brush().on(brush, brushed))docs/d3-drag.md 用d3.selectAll(.node).call(d3.drag().on(start, started))模式完全一致——行为工厂behavior factorycall示例组件ExampleBlankChart.vue 中x 轴与 y 轴分别通过.call(d3.axisBottom(x))和.call(d3.axisLeft(y))附加到svg上// 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));与 transition 联动ExampleAxis.vue 展示了call的另一常见姿势——作用于过渡选区d3.select(g.value).transition().duration(props.duration).call(props.axis)。这说明call的契约接收选区、不关心其“类型”同样适用于 transition 选区而 d3-transition 的控制流文档 也为过渡选区提供了同名的each/nodes/node/empty方法两边 API 形态对称。选区自省nodes、node、size、empty 与迭代器除each与call外文档还定义了 5 个用于检查与解包选区的方法。注意这 5 个方法都只统计/返回非空non-null元素——选区中的 null 节点例如selectAll时匹配不到的空位会被统一忽略。selection.nodes()签名selection.nodes()返回本选区中所有非空元素构成的数组d3.selectAll(p).nodes() // [p, p, p, …]等价于Array.from(selection)适合把选区交给不认 d3 选区对象的第三方代码例如console.table、测量函数或 DOM 操作库。selection.node()签名selection.node()返回选区中第一个非空元素若选区为空则返回null。仓库中有两个典型用法ExampleArcs.vue 构建完扇形 SVG 后return svg.node();把 d3 选区还原为单个可挂载的 DOM 节点ExampleBlankChart.vue 在图表组装完毕后用this.$el.append(svg.node())将整棵 SVG 挂载进 Vue 组件容器docs/d3-zoom.md 中d3.zoomTransform(selection.node())——把当前缩放变换查询建立在第一个节点之上。selection.size()签名selection.size()返回选区中非空元素的总数是“这个选区有多少东西”的快速答案。selection.empty()签名selection.empty()当选区不含任何非空元素时返回trued3.selectAll(p).empty() // false, here常用作防御性判断if (selection.empty()) { /* 选区为空走回退逻辑 */ }selectionSymbol.iterator签名selection[Symbol.iterator]()返回一个遍历选区中非空元素的迭代器。这使选区成为可迭代对象iterable两种典型用法// 迭代选区中的每个元素 for (const element of selection) { console.log(element); } // 展开为普通数组 const elements [...selection];由于实现了标准的迭代协议选区还可以配合Array.from、解构、includes检查等现代 JavaScript 语法直接使用。七个方法的速查与返回语义对比方法返回值典型场景each(fn)原选区逐元素执行任意代码回调内可用this当前节点与(d, i, nodes)三元组call(fn, ...args)原选区恒为选区与被调函数返回值无关复用组件函数坐标轴、缩放、拖拽等保持链式调用nodes()非空元素数组交给原生 DOM API / 第三方库node()首个非空元素空选区为null挂载单节点、zoomTransform等单节点查询size()非空元素数量数量判断、断言empty()布尔值空选区防御[Symbol.iterator]()迭代器for...of、[...selection]展开两条容易踩坑的语义each/ 迭代器只覆盖非空元素空选区上不会触发回调无需额外判空call的返回值不是被调函数的返回值。若组件函数如 d3 的行为工厂内部返回自身以支持其自身的链式写法call依然只把选区交还给你——这是设计约定不是 bug。验证与进一步阅读本仓库对 d3-selection API 的汇出有自动化保证test/d3-test.js 遍历 package.json 中的全部依赖含d3-selection: ^3.0.0断言d3命名空间导出了子模块中的每一个属性version除外即each、call、nodes等 7 个控制流方法都必然出现在d3聚合对象上。各方法的底层实现位于d3-selection包的src/selection/目录下分别对应each.js、call.js、empty.js、nodes.js、iterator.js、node.js、size.js七个源文件该包以依赖形式引入见 package.json 与 src/index.js。延伸阅读均位于本仓库文档中选取元素select/selectAll的查询语义是控制流方法作用的对象来源修改元素each常与其组合使用联结数据enter/exit 之后控制流方法决定了如何驱动后续处理局部变量利用each的this上下文在元素上存取状态transition 控制流过渡选区上形态对称的each/nodes/node/empty。【免费下载链接】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),仅供参考
返回列表