【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 项目中是如何处理数据值与视觉属性之间的对应关系的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Three.js 3D人物漫游项目(中)

本文目录 前言最终效果展示1、人物添加阴影1.1 添加地板1.1.1 效果 1.2 模型castShadow1.2.1 效果 1.3 轨道控制器1.3.1 效果 2、创建建筑物2.1 代码2.2 效果 前言 在数字技术的浪潮中,三维图形渲染技术以其独特的魅力,正逐步渗透到我们生活的方方面面&a…

手机、平板电脑编程———未来之窗行业应用跨平台架构

一、平板编程优点 1. 便携性强 - 可以随时随地携带平板进行编程,不受地点限制,方便在旅行、出差或休息时间进行学习和开发。 2. 直观的触摸操作 - 利用触摸屏幕进行代码编辑、缩放、拖动等操作,提供了一种直观和自然的交互方式。 …

联想(lenovo) 小新Pro13锐龙版(新机整理、查看硬件配置和系统版本、无线网络问题、windows可选功能)

新机整理 小新pro13win10新机整理 查看硬件配置和系统版本 设置-》系统-》系统信息 无线网络问题 部分热点可以,部分不可以 问题:是因为自己修改了WLAN的IP分配方式为手动分配,导致只能在连接家里无线网的时候可以,连接其他…

Unity 高亮插件HighlightPlus介绍

主要是对官方文档进行了翻译(我做了一些补充和一些小的调整) 但是如果你只是想快速入门: Unity 高亮插件Highlight Plus快速入门-CSDN博客 注意:官方文档本身就落后实际,但对入门仍很有帮助,核心并没有较大改变,有的功能有差异,以实际为准.(目前我已校正了大部分差异,后续我…

vue3 自定义el-tree树形结构样式

这里样式设置主要用到了 windcss 实现效果 模拟数据 这里也可以用模拟的数据,下面用的是后端请求的真实数据 [{"id": 5,"rule_id": 0,"status": 1,"create_time": "2019-08-11 13:36:09","update_time": "…

微信小程序拨打电话点取消报错“errMsg“:“makePhoneCall:fail cancel“

问题:微信小程序中拨打电话点取消,控制台报错"errMsg":"makePhoneCall:fail cancel" 解决方法:在后面加上catch就可以解决这个报错 wx.makePhoneCall({phoneNumber: 181********}).catch((e) > {console.log(e) //用…

金钥匙系列:Kubernetes (K8s) 服务集群技术栈学习路线

维护Kubernetes (K8s) 服务集群是一个复杂且多层次的技术任务,涉及容器化技术、集群管理、网络、安全、监控等多个领域。为了成为一名优秀的K8s集群维护工程师,技术栈需要广泛且深入。本文将为你详细介绍从零开始到深入掌握K8s集群维护的职业技术栈学习路…

在MAC中Ollama开放其他电脑访问

ollama安装完毕后默认只能在本地访问,之前我都是安装其他的软件之后可以结合开放其他端口访问,其实是可以新增或修改下电脑的系统配置,就可以打开端口允许除本机IP或localhost访问。 步骤如下: 1、查看端口(默认是&…

使用 Anaconda 环境在Jupyter和PyCharm 中进行开发

目录 前言 一、在特定环境中使用jupyter 1. 列出所有环境 2. 激活环境 3. 进入 Jupyter Notebook 二、在特定环境中使用pycham 1. 打开 PyCharm 2. 打开设置 3. 配置项目解释器 4. 选择 Conda 环境 5. 应用设置 6. 安装所需库(如果需要) 总结 &#x1f3…

大模型爬虫—ScrapeGraphAI

大模型爬虫—ScrapeGraphAI 一、介绍 ScrapeGraphAI是一个网络爬虫 Python 库,使用大型语言模型和直接图逻辑为网站和本地文档(XML,HTML,JSON 等)创建爬取管道。 只需告诉库您想提取哪些信息,它将为您完成! scrapegraphai有三种主要的爬取管道可用于从网站(或本地文…

统信服务器操作系统【搭建FTP】设置介绍

如何在操作系统上安装vsftp服务。设置匿名用户登录、设置授权用户密码访问功能,并介绍使用匿名方式、授权用户方式访问vsftp服务。本文适用于A、D、E三个服务器操作系统版本,除安装方式的差异,其他设置均相同。 文章目录 功能概述一、功能介绍二、准备环境三、安装步骤1. 在…

(undone) 学习语音学中关于 i-vector 和 x-vector

来源:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber8461375 (这是一篇跟 X-vector 有关的论文) 这里有更适合初学者的两个资料: 1.https://www.youtube.com/watch?vR3rzN6JYm38 (MIT教授的youtube视频) 2.https://people.c…

linux 基础(一)mkdir、ls、vi、ifconfig

1、linux简介 linux是一个操作系统(os: operating system) 中国有没有自己的操作系统(华为鸿蒙HarmonyOS,阿里龙蜥(Anolis) OS 8、百度DuerOS都有) 计算机组的组成:硬件软件 硬件:运算器&am…

数据结构和算法之树形结构(1)

文章出处: 数据结构和算法之树形结构(1) 关注码农爱刷题,看更多技术文章!! 树形结构是数据结构四种逻辑结构之一,也是被广泛使用的一种逻辑结构,它描述的是数据元素之间一对多的逻辑关系。树是一种非线性的数据结构&a…

初识模版!!

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

如何优化前端页面的 AJAX 请求性能并避免冲突

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

开源 AI 智能名片 S2B2C 商城小程序与正能量融入对社群归属感的影响

摘要:本文探讨了开源 AI 智能名片 S2B2C 商城小程序在社群运营中的作用,以及融入正能量对提高社群归属感的关键意义。通过分析正能量的精神感染力和对社群氛围的积极影响,阐述了在开源 AI 智能名片 S2B2C 商城小程序的各类活动中融入正能量的…

flask项目初始化

1、初始环境 python3.8 2、flask文档地址:https://flask.palletsprojects.com/en/latest/installation/#install-flask 3、初始化项目 $ mkdir myproject $ cd myproject $ python3 -m venv .venv $ . .venv/bin/activate $ pip install Flask4、打开项目mypr…

Ansible——Playbook基本功能???

文章目录 一、Ansible Playbook介绍1、Playbook的简单组成1)“play”2)“task”3)“playbook” 2、Playbook与ad-hoc简单对比区别联系 3、YAML文件语法:---以及多个---??使用 include 指令 1. 基本结构2. 数…

java后端字节一面

1. 我现在和你进行视频通话,这个是怎么做的? 视频通话通常基于实时通信技术(RTC),如WebRTC。它利用现代浏览器的API来实现视频、音频和数据的直接P2P(点对点)通信,或通过服务器中转。…