【D3.js in Action 3 精译_023】3.3 使用 D3 将数据绑定到 DOM 元素

当前内容所在位置:

  • 第一部分 D3.js 基础知识
    • 第一章 D3.js 简介(已完结)
      • 1.1 何为 D3.js?
      • 1.2 D3 生态系统——入门须知
      • 1.3 数据可视化最佳实践(上)
      • 1.3 数据可视化最佳实践(下)
      • 1.4 本章小结
    • 第二章 DOM 的操作方法(已完结)
      • 2.1 第一个 D3 可视化图表
      • 2.2 环境准备
      • 2.3 用 D3 选中页面元素
      • 2.4 向选择集添加元素
      • 2.5 用 D3 设置与修改元素属性
      • 2.6 用 D3 设置与修改元素样式
      • 2.7 本章小结
    • 第三章 数据的处理 ✔️
      • 3.1 理解数据
      • 3.2 准备数据
      • 3.3 将数据绑定到 DOM 元素 ✔️
        • 3.3.1 利用数据给 DOM 属性动态赋值 ✔️
      • 3.4 让数据适应屏幕(精译中 ⏳)
      • 3.5 加注图表标签
      • 3.6 本章小结

文章目录

    • 3.3 将数据绑定到 DOM 元素 Binding data to DOM elements
      • 3.3.1 利用数据给 DOM 属性动态赋值 Setting DOM attributes dynamically with data

《D3.js in Action》全新第三版封面

《D3.js in Action》全新第三版封面

译者按
上一节我们学习了 D3 进行数据加载、格式化处理、必要的指标测量等具体方法,最后得到一个符合可视化项目需要的标准数据集(以对象数组的形式)。然后将该对象传入一个专门用于实现可视化效果的自定义函数 createViz 中。本节就来看看 createViz 是如何一步步实现我们想要演示的条形图的。

3.3 将数据绑定到 DOM 元素 Binding data to DOM elements

接下来学习 D3 最激动人心的一个核心知识点:数据绑定。数据绑定能将数据(即单个数据项)与 DOM 元素关联起来。例如我们的条形图示例,其中的每个 rect 元素,都与问卷结果中的某项技术的投票总数相关联。

图 3.15 D3 数据工作流第四步:创建可视化 DOM 元素并实现数据绑定

图 3.15 D3 数据工作流第四步:创建可视化 DOM 元素并实现数据绑定

绑定数据需要按照以下代码的格式来书写。该写法由 选择集 链式调用的三个 D3 接口方法(selectAll()data()join())构成。

selection
  .selectAll("selector")
  .data(myData)
  .join("element to add");

再结合我们的条形图示例分析一下这段代码。示例项目需要根据数据集中的每一行(也称为 datum,即数据项)创建一个矩形元素。数据绑定的这种写法,就是在告诉 D3 每一个矩形元素要与某个数据项一一对应。

回到 main.js 文件,在函数 createViz() 内部创建一个与页面 SVG 容器相对应的 D3 选择集,并赋给常量 svg。该选择集就是后续添加矩形元素的容器。接着链式调用 selectAll() 方法,并传入一个待新增的元素标签名,即 "rect"selectAll() 方法可以接受任意 CSS 选择器作为参数,元素的标签名称往往是最常用的:

const createViz = (data) => {
  svg
    .selectAll("rect")
};

您也许好奇:怎么选了一组根本不存在的元素?这就是被业内称之为 空选择集(empty selection 的概念。但此时 D3 还不知道需要添加多少个矩形元素,这就得再链式调用一个 data() 方法,并将上一节处理过的数据集(data)传进去。这样一来 D3 才会给数据集中的每一行创建一个 rect 元素:

svg
  .selectAll("rect")
  .data(data)

最后,这些矩形元素通过 join() 方法正式进入 DOM 对象:

svg
  .selectAll("rect")
  .data(data)
  .join("rect")

保存项目,并在浏览器的调试工具中检查 DOM 结构。如图 3.16 所示,SVG 容器中此时包含 33 个矩形元素,每一个都对应数据集的中某项技术。

图 3.16 完成数据绑定并添加到页面 DOM 结构中的矩形元素截图

图 3.16 完成数据绑定并添加到页面 DOM 结构中的矩形元素截图

整个数据绑定的详细过程如图 3.17 所示。从选择集开始,这里就是 SVG 容器;然后调用 selectAll() 方法创建一个空选择集,传入我们的标签选择器;接着再调用 data() 方法;最后通过 D3 的 join() 方法给每个数据项添加一个对应的矩形元素。完成数据绑定的选择集实现了元素与数据的特定 组合(combination。后续每当复用该选择集中的元素,或者对其执行某些 DOM 操作,都能直接访问到元素对应的数据。

图 3.17 数据绑定过程示意图

图 3.17 数据绑定过程示意图

数据绑定的另一种写法

如果上网搜索 D3 的代码示例,想必会碰到下面这样的写法。这是 D3 数据绑定的另一种写法,与本节介绍的略有不同。其中链式调用的方法为 .enter().append(),而不是 join()

selection
  .selectAll("selector")
  .data(myData)
  .enter().append("element type");

虽然使用 .enter().append() 仍然有效,但该写法从 D3 第 6 版开始,基本就被 join() 所替代了。在代码的底层实现中,join() 方法不仅能够根据数据处理这些有待添加到选择集中的元素,还进一步考虑了很多细节:会有多少新元素进入 DOM、有多少元素退出 DOM、以及有多少元素正在 DOM 中更新。这种更为复杂、更加精细化的模式设计,以其对可视化数据不断演变本质的准确把控,而在众多交互式可视化项目实践中脱颖而出、独占鳌头。此外,除了全面考虑数据绑定涉及的这些相关细节,join() 写起来也比之前的 .enter().append() 更简单。

本书将在第 7 章《交互式可视化》中详细介绍这种更精巧复杂的数据绑定模式。此刻您只需要知道,D3 的早期版本在绑定数据的写法上,和本节介绍的版本略有不同即可。这些历史版本的代码今后大概率可能还将继续发挥余热,被您碰到。

3.3.1 利用数据给 DOM 属性动态赋值 Setting DOM attributes dynamically with data

之前讲过,D3 会将加载的 CSV 文件转换成一个可迭代的对象数组结构。利用这个数据结构,就能将其中的每个对象绑定到对应的矩形元素上。这些被绑定的数据不仅控制着新增矩形元素的个数,还可以在执行元素操作时供访问器函数(accessor functions)及其他内置函数直接访问。

下面结合本章的条形图示例来进行演示。在刚才的数据绑定代码后面,再次链式调用一个 attr() 方法,目的是给每个矩形元素指定一个 class 属性(attribute)。但这里传入第二个参数的不是简单的属性值,而是一个访问器函数,如下列代码所示。

可以看到,这里的访问器函数与其他 JavaScript 函数没什么不同。它返回一个样式类的值,也就是代码中的 bar,或者任何需要赋给矩形元素的有效类名:

svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    .attr("class", d => {
      console.log(d);
      return `bar bar-${d.technology}`;
    })

该访问器函数接受一个参数 d,表示各矩形所绑定的数据项 datum。如果把 d 打印到控制台,就会看到包含一门技术及其总票数的每一个对象元素依次输出,就像直接在遍历这些矩形一样。

关于模板字面量与连接字符串

上面的代码片段(译注:即倒数第 2 行)使用了 模板字面量(template literals,也称为 模板字符串(template strings,用反引号(``)进行引用。它用于将传统的 JavaScript 字符串与表达式相结合。其中,表达式以一个美元符号 $ 开头,并用大括号包起来,如 ${表达式}

模板字面量与连接字符串对比

模板字面量与连接字符串对比

将表达式与字符串组合在一起,您可能更容易想到连接字符串,虽然这种写法老套了点,但也没什么问题。如上图所示,在连接字符串中,字符串的两边使用了引号(""),而表达式的连接则用的是加号(+)。其实两种写法都可以,但模板字面量正在成为新主流。

绑定数据的这种访问机制,对于矩形位置和大小的设置而言十分有利。条形图最终要实现如图 3.18 所示的垂直堆叠效果:每个矩形宽(width 属性)表示选用该工具的从业者数量,对应绑定数据的 count 值;矩形越长,选用该技术的人就越多,反之亦然。另一方面,矩形的高(height 属性)则是固定的,并且在垂直方向上相互留有一定间隙。

图 3.18 找出每个矩形左上角位置的通用公式

图 3.18 找出每个矩形左上角位置的通用公式

若将柱形的高度值赋给常量 barHeight,则可以用下面的代码来设置矩形的宽高。注意属性 width 的设置,仔细观察回调函数的用法以及获取绑定数据的 count 值的实现过程:

const barHeight = 20;
svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    .attr("class", d => {
      console.log(d);
      return "bar";
    })
    .attr("width", d => d.count)
    .attr("height", barHeight)

然后,矩形位置的设置则需要分别计算出其 x 属性和 y 属性的值。这里的 xy 分别表示各矩形元素在 SVG 容器坐标系中左上角的坐标。如图 3.18 所示,矩形与 SVG 父容器的左边界对齐,也就是说其 x 属性始终为 0

与此同时,y 属性的值则需要算一算了——
第 1 个矩形条的左上角位于 SVG 容器的顶部,此时 y 值为 0
第 2 个矩形位于第 1 个的正下方,与上一个矩形的左上角相距一个单位的柱形高度,外加一部分间距(切记,SVG 元素的 y 坐标是向下为正);
第 3 个矩形的位置还要低一些,其 y 坐标的值为两个柱形高度,外加两倍的垂直间距。
如图 3.18 所示,可以观察出 y 值满足的某种规律。任一矩形的 y 值,应该等于在它之前的矩形数,乘以条形高度与垂直间距的和。

这样,在 y 属性的回调函数中,需要用到第二个循环参数,通常命名为 i,表示 索引(index。前面介绍过,使用访问器函数就像在循环遍历被绑元素的数据。在 JavaScript 的循环语法中,通常可以访问到每个当前元素的索引,即它们在循环数组中的位置再减 1(JavaScript 中的数组索引是从 0 开始的)。入一下代码片段所示,利用索引来计算每个矩形元素的垂直位置,并相互预留出 5px 的间隙:

const barHeight = 20;
svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    .attr("class", d => {
      console.log(d);
      return "bar";
    })
    .attr("width", d => d.count)
    .attr("height", barHeight)
    .attr("x", 0)
    .attr("y", (d, i) => (barHeight + 5) * i)

上述代码在访问器函数中,使用了 JavaScript箭头函数(arrow function 语法(即 ECMAScript 6,也叫 ES6 语法)。当函数只用到一个参数时,比如设置第 6 行的 class 属性与第 10 行的 width 属性,则不需要小括号;而当参数存在多个时,则必须用小括号包起来(如最后一行用于设置 y 属性的 (d, i))。另外,访问器函数如果存在多行语句,则函数体必须用大括号({})括起来,同时必须存在返回语句(如代码段第 6 行至第 9 行对 class 属性的设置);而对于简单的单行函数,则无需大括号与返回语句(如第 10 行设置属性 width 的写法)。如图 3.19 所示,这些语法规则可以总结归纳如下:

图 3.19 箭头函数的用法示意图

图 3.19 箭头函数的用法示意图

保存并重新加载项目,会看到如图 3.20 所示的矩形顺次排列。终于看着有点像条形图了!

图 3.20 利用数据对各矩形进行定位并调整其大小后的渲染效果

图 3.20 利用数据对各矩形进行定位并调整其大小后的渲染效果

提示

下一节将介绍分段比例尺(band scales)在计算条形元素垂直位置时的具体用法。但是像本节这样手动计算各矩形元素位置的做法也很有意义。开发 D3 项目时经常需要进行这样的元素定位计算,因此熟悉这类任务是很有必要的。刚开始接触可能不太轻松,但加以时日练习,就能彻底掌握其中的要领。应对这些计算的最佳方法之一,是将可视化中的其中几个元素画在一张纸上,然后找出它们在 SVG 父级坐标系中的位置坐标,如上图 3.18 所示。这项练习能帮助您更好地理解可视化项目的构建过程,尤其是处理复杂项目的时候。

接下来,需要设置矩形元素的 fill 属性来给上面的条形图上色,让画面看起来更美观。以下代码段使用了 CSS 内置的天蓝色 skyblue。当然也可以填充您喜欢的任意颜色:

svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    ...
    .attr("fill", "skyblue");

最后,在检查一下绑定到矩形的数据,识别出 D3.js 对应的那个数据项。为此,需要用到 JavaScript 的三目运算符(ternary operator):如果当前技术是 D3.js,则给 fill 属性填充黄绿色 "yellowgreen";否则填充为天蓝色 "skyblue",如图 3.21 所示。

  ...
  .attr("fill", d => d.technology === "D3.js" ? "yellowgreen" : "skyblue");

图 3.21 给 D3.js 对应的条形元素填充绿色,其余则填充蓝色

图 3.21 给 D3.js 对应的条形元素填充绿色,其余则填充蓝色

这样,示例中的条形图就初步成型了。目前每个矩形的宽度都是直接用的数据本身的值,这种做法可能并不太实用。想象一下:要是数据中的数值是以百万为单位,难道也像这样对应到矩形宽度上吗?下一节将介绍比例尺相关的知识,看看它们在 D3 项目中是如何处理数据值与视觉属性之间的对应关系的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/882704.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开源免费】基于SpringBoot+Vue.JS教师工作量管理系统(JAVA毕业设计)

本文项目编号 T 043 ,文末自助获取源码 \color{red}{T043,文末自助获取源码} T043,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

两数之和、三数之和、四数之和

目录 两数之和 题目链接 题目描述 思路分析 代码实现 三数之和 题目链接 题目描述 思路分析 代码实现 四数之和 题目链接 题目描述 思路分析 代码实现 两数之和 题目链接 LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode) 题目…

算法:69.x的平方根

题目 链接:leetcode链接 思路分析(二分算法) 当然你可以使用暴力查找,但是二分算法的时间复杂度更好。 我们先用暴力查找找点灵感 x :1 2 3 4 5 6 7 8 x2:1 4 9 16 25 36 49 64 我们的目的是找到一个x…

《程序猿之设计模式实战 · 适配器模式》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…

【数据结构初阶】链式二叉树接口实现超详解

文章目录 1. 节点定义2. 前中后序遍历2. 1 遍历规则2. 2 遍历实现2. 3 结点个数2. 3. 1 二叉树节点个数2. 3. 2 二叉树叶子节点个数2. 3. 3 二叉树第k层节点个数 2. 4 二叉树查找值为x的节点2. 5 二叉树层序遍历2. 6 判断二叉树是否是完全二叉树 3. 二叉树性质 1. 节点定义 用…

推荐一款开源的Redis桌面客户端

TinyRDM 是一个现代化的、轻量级的跨平台 Redis 桌面客户端,能在 Mac、Windows 和 Linux 系统上使用。它有着现代化的设计风格,界面既简洁又清晰,操作起来方便又高效。不管是刚开始接触的新手,还是经验丰富的开发者,都…

软考(9.22)

1 在浏览器的地址栏中输入xxxyftp.abc.can.cn,在该URL中( )是要访问的主机名。 A.xxxyftp B.abc C.can D.cn 协议://主机名.域名.域名后缀或IP地址(:端口号)/目录/文件名。 本题xxxyftp是主机名,选择A选项。 2 假设磁盘块与缓冲区大小相同,…

WPF 的TreeView的TreeViewItem下动态生成TreeViewItem

树形结构仅部分需要动态生成TreeViewItem的可以参考本文。 xaml页面 <TreeView MinWidth"220" ><TreeViewItem Header"功能列表" ItemsSource"{Binding Functions}"><TreeViewItem.ItemTemplate><HierarchicalDataTempla…

一.python入门

gyp的读研日记&#xff0c;哈哈哈哈&#xff0c;&#x1f642;&#xff0c;从复习python开始&#xff0c; 目录 1.python入门 1.1 Python说明书 1.2 Python具备的功能 1.3 学习前提 1.4 何为Python 1.5 编程语言 2.Python环境搭建 2.1 开发环境概述 2.2 Python的安装与…

C++: unordered系列关联式容器

目录 1. unordered系列关联式容器1.1 unordered_map1.2 unordered_set 2. 哈希概念3. 哈希冲突4. 闭散列5. 开散列 博客主页: 酷酷学 感谢关注!!! 正文开始 1. unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时…

【论文阅读】Grounding Language with Visual Affordances over Unstructured Data

Abstract 最近的研究表明&#xff0c;大型语言模型&#xff08;llms&#xff09;可以应用于将自然语言应用于各种各样的机器人技能。然而&#xff0c;在实践中&#xff0c;学习多任务、语言条件机器人技能通常需要大规模的数据收集和频繁的人为干预来重置环境或帮助纠正当前的…

Pyspark dataframe基本内置方法(5)

文章目录 Pyspark sql DataFrame相关文章toDF 设置新列名toJSON row对象转换json字符串toLocallterator 获取迭代器toPandas 转换python dataframetransform dataframe转换union unionALL 并集不去重&#xff08;按列顺序&#xff09;unionByName 并集不去重&#xff08;按列名…

力扣234 回文链表 Java版本

文章目录 题目描述代码 题目描述 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&…

Mac电脑上最简单安装Python的方式

背景 最近换了一台新的 MacBook Air 电脑&#xff0c;所有的开发软件都没有了&#xff0c;需要重新配环境&#xff0c;而我现在最常用的开发程序就是Python。这篇文章记录一下我新Mac电脑安装Python的全过程&#xff0c;也给大家一些思路上的提醒。 以下是我新电脑的配置&…

初识模版!!

初识模版 1.泛型编程1.1 如何实现一个交换函数呢&#xff08;使得所有数据都可以交换&#xff09;&#xff1f;1.2 那可以不可以让编译器根据不同的类型利用该模子来生成代码呢&#xff1f; 2.模版类型2.1 模版概念2.2 函数模版的原理2.3 函数模板的实例化2.4 模板参数的匹配原…

如何在openEuler上安装和配置openGauss数据库

本文将详细介绍如何在openEuler 22.03 LTS SP1上安装和配置openGauss数据库&#xff0c;包括数据库的启动、停止、远程连接配置等关键步骤。 1、安装 使用OpenEuler-22.03-LTS-SP1-x64版本的系统&#xff0c;通过命令行安装openGauss数据库。 1.1、确保系统软件包索引是最新…

2024最受欢迎的3款|数据库管理和开发|工具

1.SQLynx&#xff08;原SQL Studio&#xff09; 概述&#xff1a; SQLynx是一个原生基于Web的SQL编辑器&#xff0c;由北京麦聪软件有限公司开发。它最初被称为SQL Studio&#xff0c;后改名为SQLynx&#xff0c;支持企业的桌面和Web数据库管理。SQLynx支持所有流行的数据库&a…

lettuce引起的Redis command timeout异常

项目使用Lettuce&#xff0c;在自己的环境下跑是没有问题的。在给客户做售前压测时&#xff0c;因为客户端环境比较恶劣&#xff0c;service服务和中间件服务不在同一机房。服务启动后不一会就会出现Redis command timeout异常。 经过差不多两周的追查&#xff0c;最后没办法把…

Fyne ( go跨平台GUI )中文文档-Fyne总览(二)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2​​​​​​​ 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne…

本地生活商城开发搭建 同城O2O线上线下推广

同城本地化商城目前如火如荼&#xff0c;不少朋友咨询本地生活同城平台怎么开发&#xff0c;今天商淘云与大家分享同城O2O线上商城的设计和开发。 本地生活商城一般会涉及到区域以及频道类&#xff0c;一般下单需要支持用户定位、商家定位&#xff0c;这样利于用户可以快速找到…