【D3.js in Action 3】1.2.5 与 D3 相关的 JavaScript 基础知识
当前内容所在位置
- 第一部分 D3.js 基础知识
- 第一章 D3.js 简介
- 1.1 何为 D3.js?
- 1.2 D3 生态系统——入门须知
- 1.2.1 HTML 与 DOM
- 1.2.2 SVG - 可缩放矢量图形
- 1.2.3 Canvas 与 WebGL
- 1.2.4 CSS
- 1.2.5 JavaScript ✔️
- 1.2.6 Node 与 JavaScript 框架(精译中 ⏳)
- 1.2.7 Observable 记事本(待翻译)
1.2.5 JavaScript
D3 是在 JavaScript 已有的核心功能上添加了众多新接口方法的一个 JavaScript 库,前期对 JavaScript 稍有了解都将对 D3 的使用有所帮助;此外,您也可以在构建 D3 项目时使用 JavaScript 已有的所有功能特性。
真正意义上的 JavaScript 入门知识就算单独写一本书来介绍都不为过;而本小节仅讨论在 D3 项目中用途最广泛的两个 JavaScript 话题:方法的链式调用(method chaining) 和 对象的操作(object manipulation)。
1 方法的链式调用
搜索网上的 D3 项目示例会发现,对于同一个选中的元素或区域(selection),其调用的方法在写法上往往是一个接一个的——该项技术我们称之为 方法的链式调用(method chaining,又称方法链)。它有利于保持代码的简洁性与可读性。
方法链可以用汽车装配生产线来进行类比。假设写好的脚本可供这样一条装配生产线运行:如下例所示,先声明一个变量 car
并赋值为一个新建的 Car()
对象;然后调用函数 putOnHood()
,用于在汽车顶部装上引擎盖;接着再继续调用分别装配车轮、轮胎和车灯的函数。每次连续调用都会为 Car()
对象添加某个构件元素。待所有方法执行完毕后,汽车就有了引擎盖、车轮、轮胎和车灯。每个方法都会将更新后的汽车对象传递给下一个方法,从而形成“链式”(“chaining”)。请注意,每个调用之间都用一个句点(dot)隔开,而且方法的执行顺序就是它们被链接起来的顺序。在本例中,则需要先安装车轮,然后才能安装轮胎,示例如下:
let car = new Car().putOnHood().putOnWheels().putOnTires().putOnLights();
再来看看方法的链式调用在 D3 中的具体应用。假设要从 DOM 中抓取所有 <div>
元素并在其中分别添加一个段落元素。该段落元素的 class
属性假设为 my-class
,并包含文本 Wow
;之后在向各段落插入一个 <span>
元素,并加粗显示文本 Even More Wow
。如果不用方法链,则需要将每个操作存到某个常量,然后在执行下一个操作时调用该常量,如下代码所示。光是看一眼就够累的了……
const mySelection = d3.selectAll("div");
const myParagraphs = mySelection.append("p");
const myParagraphsWithAClass = myParagraphs.attr("class", "my-class");
const myParagraphsWithText = myParagraphsWithAClass.text("Wow");
const mySpans = myParagraphsWithText.append("span");
const mySpansWithText = mySpans.text("Even More Wow")
const myBoldSpans = mySpansWithText.style("font-weight", "900");
而有了方法的链式调用,代码就简洁多了:
d3.selectAll("div").append("p").attr("class", "my-class").text("Wow")
.append("span").text("Even More Wow").style("font-weight", "900");
在 D3 中,换行(这一点 JavaScript 往往会忽略)和缩进这些链式调用的方法将会非常常见,也使得代码更容易阅读,缩进也有助于查看正在处理的元素:
d3.selectAll("div")
.append("p")
.attr("class", "my-class")
.text("Wow")
.append("span")
.text("Even More Wow")
.style("font-weight", "900");
如果不能完全理解上述代码的含义,您也不用过于担心。这里只是为了让您熟悉 JavaScript 中的方法是怎样被链式调用的。后续第 2 章会介绍 D3 的专用术语。
2 数组与对象操作
D3 的核心在于数据,而数据通常是由 JavaScript 对象构造的。了解这些对象的构造、访问方法、以及操作其包含的数据,对于构建可视化效果大有帮助。
先来谈谈简单数组——它是一组元素的列表形式。在与数据相关的项目中,数组通常是由数字或字符串构成的有序列表:
const arrayOfNumbers = [17, 82, 9, 500, 40];
const arrayOfStrings = ["blue", "red", "yellow", "orange"];
数组中的每个元素都有一个数值位置,称为 索引,第一个元素的索引为 0
(我们说 JavaScript 数组是从零开始索引的(zero-indexed))。
arrayOfNumbers[0] // => 17
arrayOfStrings[2] // => "yellow"
数组有一个 length
属性(property)。对于非稀疏数组(nonsparse arrays),该属性指定了数组包含的元素个数。由于数组的索引从零开始,因此数组中最后一个元素的索引值与数组长度减 1 相对应:
arrayOfNumbers.length; // => 5
arrayOfStrings[arrayOfStrings.length - 1] // => "orange"
数组还可以使用 includes()
方法来确定该数组是否包含特定的值。如果数组中的一个元素与作为参数传递的值完全对应,则返回 true
;否则返回 false
:
arrayOfNumbers.includes(9) // => true
arrayOfStrings.includes("pink") // => false
arrayOfStrings.includes("ellow") // => false
然而,大多数数据集都不是简单的数字或字符串列表,每个数据点通常都由多个属性(properties)组成。试想有一个如下表 1.1 所示的记录某虚拟机构雇员信息的数据库。该表包含四列:每名员工的 id、姓名(name)和职位(position),以及该员工是否使用 D3(works_with_d3)。
表 1.1 雇员及其职位的小型数据集
id | name | position | works_with_d3 |
---|---|---|---|
1 | Zoe | Data analyst(数据分析师) | False |
2 | James | Frontend developer(前端开发) | True |
3 | Alice | Fullstack developer(全栈开发) | True |
4 | Hubert | Designer(设计师) | False |
数据集中的每一行(或称数据点,即 data point)都可以用 JavaScript 对象来描述,如下面的 row1
所示:
const row1 = {
id:"1",
name:"Zoe",
position:"Data analyst",
works_with_d3:false
};
也可以用句点符(dot notation)轻松访问对象中每个属性(property)的值:
row1.name // => "Zoe"
row1.works_with_d3 // => false
此外,还可以使用中括号访问这些值。如果属性名包含空格等特殊字符,或者先前将属性名保存在常量或变量中,则使用中括号符访问属性值就非常方便:
row1["position"] // => "Data analyst"
const myProperty = "works_with_d3";
row1[myProperty] // => false
现实生活中,数据集通常格式化为对象数组。例如,用 D3 加载表 1.1 中的数据集(后续第 3 章会介绍)并保存到常量 data
中,将得到如下所示的对象数组:
const data = [
{id:"1", name:"Zoe", position:"Data analyst", works_with_d3:false},
{id:"2", name:"James", position:"Frontend developer", works_with_d3:true},
{id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true},
{id:"4", name:"Hubert", position:"Designer", works_with_d3:false}
];
我们可以通过循环(loop)来遍历 data
数组中的每个元素(或数据)。更具体地说,就是使用 JavaScript 的 forEach
循环,代码写起来既方便,访问数据又轻松。遍历数据集的一个常见用例是数据整理(data wrangling)。需要加载外部 CSV 文件时,数字通常会被格式化为字符串形式。下面以 data
数组为例,尝试将 id
属性的值从字符串转换为数字格式。
如下代码所示,数组迭代器 d
可以遍历数组中的每条数据。使用句点符以及 +
运算符,可将各 id 转换为数字:
data.forEach(d => {
d.id = +d.id;
});
JavaScript 提供了多种数组迭代器方法,以帮助开发者与数据交互,甚至在需要时重塑数据。比如,要将数据集中的每位员工定位到某个可视化项目中,假如创建一个只包含员工姓名的简单数组就行,则可以调用数组的 map()
方法:
data.map(d => d.name); // => ["Zoe", "James", "Alice", "Hubert"]
同理,如果只想筛选出正在使用 D3 的员工,则可以改用 filter()
方法:
data.filter(d => d.works_with_d3);
/* => [
{id:2, name:"James", position:"Frontend developer", works_with_d3:true},
{id:4, name:"Hubert", position:"Designer", works_with_d3:true}
]; */
最后,还可以使用 find()
方法找出 id
为 3
的员工。注意,find()
方法在找到要目标值后就会停止迭代,因此只能在搜索一个唯一的数据点时使用该方法。
data.find(d => d.id === 3);
// => {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true}
本节讨论的数组方法虽然远远不能涵盖 JavaScript 提供的所有数组和对象操作相关的知识点,但它们也是您在处理数据时会经常用到的方法。当需要通过其他方式访问或操作数据时,求助 MDN 的官方在线文档 MDN Web Docs 是个不错的选择,里面有大量可靠的示例供您参考。
原文地址:https://blog.csdn.net/frgod/article/details/140238042
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!