【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第一部分 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.4.1 比例尺简介(上篇)
        • 3.4.2 线性比例尺(中篇)
          • 3.4.2.1 基于 Mocha 测试 D3 线性比例尺(DIY 实战)
        • 3.4.3 分段比例尺(下篇)
          • 3.4.3.1 使用 Observable 在线绘制 D3 条形图(DIY 实战)
      • 3.5 加注图表标签(上篇) ✔️
        • 3.5.1 人物专访:Krisztina Szűcs(下篇,待翻译 ⏳)
      • 3.6 本章小结

文章目录

    • 3.5 加注图表标签 Adding labels to a chart

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

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

译者按
终于来到了本章代码量最为密集的最后一个小节了。作者真的是事无巨细,真正把大家当成零基础的数据可视化爱好者,竟然细致到 JS 的注释是怎么加的也要说明一下……不过这也算是本书的一大魅力吧。也多亏了这份执着和对细节把控的精益求精,新版才出现了这么多直观精美的配图。由于篇幅太长,本节最后的人物专访就放到下篇,本文为上篇,主要介绍条形图的最终实现。一起跟随作者实战起来吧!

3.5 加注图表标签 Adding labels to a chart

示例条形图就快做完了,但目前还不知道哪个矩形条对应哪个技术,也不知道矩形条的长度代表哪些票数。这些问题只要给图表加两组标签(label)就能解决:第一组列出技术名称,放在左侧;第二组则显示各矩形条对应的 count 票数值,分别放到各矩形条的最右端。

在基于 SVG 的可视化项目中,标签的制作可以通过 SVG 文本元素(text)实现:先将各矩形条分别与两个文本元素相结合,然后将其一同嵌入 SVG 的某个分组元素(group)内。根据第 1 章 1.2.2 节介绍的 SVG 分组元素的知识,这里可以用分组元素将多个子元素视为一个整体进行平移,以便于后续将绑定数据传递给它的后代元素。

接下来需要稍微重构一下代码。首先注释掉与矩形条元素相关的所有代码行,留待后用。在 JavaScript 中,单行注释以双斜杠(//)开头,而多行注释则以 /* 开始、以 */ 结束。

再回到处理数据绑定的那部分代码。此时应该让数据绑定到 SVG 的分组元素(g)上,而不是之前的矩形条上。然后将该选择集赋给一个常量 barAndLabel

const barAndLabel = svg
  .selectAll("g")
  .data(data)
  .join("g");

为了让矩形条与标签元素同步移动,可以利用 transform 属性让各分组元素做垂直平移(vertical translation)。transform 变换属性(attribute)上的 translate 平移属性(property)接受两个参数:水平平移量,设为 0;以及垂直平移量,这里设为各矩形条的垂直坐标,由之前定义好的分段比例尺函数 yScale 计算得到:

const barAndLabel = svg
  .selectAll("g")
  .data(data)
  .join("g")
    .attr("transform", d => `translate(0, ${yScale(d.technology)})`);

虽然 SVG 的分组元素没有可视化的图形表示,也不以占据某个有界空间的形式存在,但我们仍然可以将其想象成能够封装所有子元素的内容盒。借助 transform 属性,这些分组元素实现了垂直方向的均匀排布,如图 3.30 所示。各矩形条及其标签元素将相对于它们所在的父级分组元素进行定位:

图 3.30 封装了矩形条与标签等后代元素的分组元素在 SVG 容器内的定位情况

【图 3.30 封装了矩形条与标签等后代元素的分组元素在 SVG 容器内的定位情况】

一切就绪后,就可以重新添加矩形条了。如下所示,调用选择集 barAndLabel,并将矩形元素添加进去:

const barAndLabel = svg
  .selectAll("g")
  .data(data)
  .join("g")
    .attr("transform", d => `translate(0, ${yScale(d.technology)})`);

barAndLabel
  .append("rect");

由于该选择集包含多个分组元素,D3 会分别给每个分组添加一个矩形元素。保存项目并使用检查工具进行查看,确认它们都已经添加到了 DOM 结构中,如图 3.31 所示:

图 3.31 添加到每个分组元素里的矩形元素示意图

【图 3.31 添加到每个分组元素里的矩形元素示意图】

现在可以取消刚才的注释,把它们用到新加的 rect 元素上。D3 数据绑定的一大好处,是绑定的数据会传递给分组内的所有后代元素。因此矩形条依然可以像之前那样拿到数据,唯一的区别是,矩形的 y 属性要设为 0,因为分组元素已经带着它完成了垂直平移:

barAndLabel
  .append("rect")
    .attr("width", d => xScale(d.count))
    .attr("height", yScale.bandwidth())
    .attr("x", 100)
    .attr("y", 0)  // 矩形不用再做垂直平移,其定位相对于其父级分组元素的位置
    .attr("fill", d => d.technology === "D3.js" ? "yellowgreen":"skyblue");

这时就能看到各个矩形条了,效果和之前完全相同(详见图 3.28)。

译注

为方便查看新的条形图效果,我这里直接附上图 3.28:

图 3.28 配置了分段比例尺并添加间隙后的条形图效果

接下来能可以正式添加标签了!再次调用选择集 barAndLabel,将 SVG 文本元素分别添加进去。由于各标签需要展示每个对应的技术名称,因此需要再链式调用一次 text() 方法。该方法只接受一个参数:文本元素要显示的文本内容。本例则需要根据每个绑定的数据项动态设置对应的文本内容:

barAndLabel
  .append("text")
    .text(d => d.technology);

内容设置好后,再用 xy 属性给每个标签定位。先来看水平方向,各标签末端要同矩形条的起始位置对齐。矩形条从 100px 开始,于是可以把文本元素放在大约 96px 的位置,与矩形条保持 4px 的间距。然后令其 text-anchor 属性(attribute)的值为 end,实现标签右对齐。这样 x 属性值就代表了各标签的末端位置,如图 3.32 所示:

图 3.32 各技术标签的定位计算示意图

【图 3.32 各技术标签的定位计算示意图】

再来看垂直方向。由于各标签的定位相对于所在的父级分组元素,只需稍向下平移即可与矩形条居中对齐。注意,SVG 文本元素的垂直定位是相对于它的基线(baseline)而言的。经反复试错与微调,最终给定的 y 值为 12 像素。位置的微调可以在浏览器的检查工具(inspector)里快速实现:

barAndLabel
  .append("text")
    .text(d => d.technology)
    .attr("x", 96)
    .attr("y", 12)
    .attr("text-anchor", "end");

最后,在根据各自的喜好,调用 style() 方法设置文本标签的 font-familyfont-size 属性,分别确定字体及字号。本例使用的字体为 11 号无衬线字体,如图 3.33 所示:

barAndLabel
  .append("text")
    .text(d => d.technology)
    .attr("x", 96)
    .attr("y", 12)
    .attr("text-anchor", "end")
    .style("font-family", "sans-serif")
    .style("font-size", "11px");

图 3.33 加注了技术标签的条形图效果

【图 3.33 加注了技术标签的条形图效果】

接着,再在矩形条的另一端添加一组标签,显示该技术在问卷调查中的得票数,做法与添加技术名称标签类似。先调用 barAndLabel 选择集常量,然后在每个分组元素内添加一个文本元素,再通过链式调用的 text() 方法给每项技术指定相应的 count 值:

barAndLabel
  .append("text")
    .text(d => d.count)

由于计数标签位于矩形条的末端,而矩形条的水平坐标可以通过 xScale 函数计算得到。再加上矩形条两边的间距(左边为预留的 100px,后边同样保持 4px 间隔),这样技术标签的 x 属性就能确定了。垂直方向,也令其下移 12px,如图 3.34 所示:

barAndLabel
  .append("text")
    .text(d => d.count)
    .attr("x", d => 100 + xScale(d.count) + 4)
    .attr("y", 12)

图 3.34 计数标签的定位计算示意图

【图 3.34 计数标签的定位计算示意图】

接着,再给技术标签设置 font-familyfont-size 属性。注意,计数标签的字号为 9px,比技术名称的字号 11px 小一些,目的是为了让两组标签保持视觉上的层次感。较大的标签更吸引眼球,也便于让观众理解得票数是次于技术名称的样式设计。

barAndLabel
  .append("text")
    .text(d => d.count)
    .attr("x", d => 100 + xScale(d.count) + 4)
    .attr("y", 12)
    .style("font-family", "sans-serif")
    .style("font-size", "9px");

最后一步,再在条形图左侧绘制一条垂直线,作为垂直方向的轴线。在以下代码片段中,我们将这条线段添加到 SVG 容器内。该线段的起点坐标 (x1, y1)(100, 0),即 SVG 容器的顶部;终点坐标 (x2, y2) 则位于 (100, 700),即容器底部。再指定好线条的描边色,让轴线显示出来:

svg
  .append("line")
    .attr("x1", 100)
    .attr("y1", 0)
    .attr("x2", 100)
    .attr("y2", 700)
    .attr("stroke", "black");

如果再把 SVG 容器的边框去掉,最终条形图的效果就应该如图 3.35 所示。该项目也托管到了 GitHub ,可以访问 http://mng.bz/mjor 进行访问。值得一提的是,本章给标签预留间距的做法并不常用。业内更通用的实现方案是遵守 D3 外边距约定(D3 margin convention),具体内容将在下一章进行介绍,后续章节也将按这种写法来进行讲解。

图 3.35 最终实现的在线版 D3 条形图效果,详见:http://mng.bz/mjor

【图 3.35 最终实现的在线版 D3 条形图效果,详见:http://mng.bz/mjor】

恭喜您完成了本章的学习——知识点着实很密集!如果还没有掌握讲过的所有概念,也不必过于担心。后续章节还将继续提到这些概念,相信很快就能融会贯通 。

译注

实测时发现,左边标签的字号取 11px 时部分标签显示不全,调整为 10px 正常。相应的得票数标签也最好该小些,设为 8px 比较合适(相关源码已同步上传到 CSDN 下载资源):

补图 1 本地实测并重新调整字号后的 D3 条形图效果

【补图 1 本地实测并重新调整字号后的 D3 条形图效果】

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

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

相关文章

aws(学习笔记第二课) AWS SDK(node js)

aws(学习笔记第二课) 使用AWS SDK(node js) 学习内容: 使用AWS SDK(node js) 1. AWS SDK(node js) AWS支持多种SDK开发(除了AWS CLI,还支持其他的SDK) AndroidPythonNode.js(Javas…

数据结构-C语言顺序栈功能实现

栈 栈&#xff1a;类似于一个容器&#xff0c;如我们生活中的箱子&#xff0c;我们向箱子里放东西&#xff0c;那么最先放的东西是最后才能拿出来的 代码实现 #include <stdio.h> #include <stdlib.h>#define MAX_SIZE 100typedef struct {int* base; // 栈底指针…

[Linux#65][TCP] 详解 延迟应答 | 捎带应答 | 流量控制 | 拥塞控制

目录 一、延迟应答 二、捎带应答 三. 流量控制 总结 四. 拥塞控制 1. 拥塞控制 2. 慢启动机制&#xff1a; 3.思考 4.拥塞避免算法 5. 快速恢复算法 一、延迟应答 1. 立即应答问题 接收数据的主机若立刻返回ACK应答&#xff0c;可能返回的窗口较小。例如&#xff1…

univer实现excel协同

快速入门 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src&q…

怎么看待数字化转型是大势所趋?

怎么看到数字化转型是大势所趋&#xff1f;下面我结合最新数据给大家讲明白这个事。 近日&#xff0c;我通过大量的数据相关性分析&#xff0c;有了一些关键发现。 【数字化转型】之所以势在必行&#xff0c;主要是因为数字化转型为各个国家数字经济发展提供了重要的参考依据。…

使用js和canvas实现简单的网页贪吃蛇小游戏

玩法介绍 点击开始游戏后&#xff0c;使用键盘上的↑↓←→控制移动&#xff0c;吃到食物增加长度&#xff0c;碰到墙壁或碰到自身就游戏结束 代码实现 代码比较简单&#xff0c;直接阅读注释即可&#xff0c;复制即用 <!DOCTYPE html> <html lang"en"…

SAP将假脱机(Spool requests)内容转换为PDF文档[RSTXPDFT4]

将假脱机(Spool requests)内容转换为PDF文档[RSTXPDFT4] 有时需要将Spool中的内容导出成PDF文件&#xff0c;sap提供了一个标准程序RSTXPDFT4可以实现此功能。 1, Tcode:SP01, 进入spool requests list 2, SE38 运行程序RSTXPDFT4 输入spool reqeust号码18680&#xff0c;然后…

im架构分享 即时通讯架构 即时消息 全球架构师峰会im分享 im分布式 企业级im架构 分布式im 即时通讯im架构

1. 之前收藏的淘宝李厉岷老师在全球架构师峰会上做的im技术分享&#xff0c;贴出来备注下。 2. 李老师infoQ主页链接&#xff1a; 李历岷 3. 文章&#xff1a; 电商IM消息系统架构演进_ArchSummit_李历岷_InfoQ精选文章 4. ppt下载地址 &#xff08;注&#xff1a;同期还有…

GAN(Generative Adversarial Nets)

GAN(Generative Adversarial Nets) 引言 GAN由Ian J. Goodfellow等人提出&#xff0c;是Ian J. Goodfellow的代表作之一&#xff0c;他还出版了大家耳熟能详的花书&#xff08;Deep Learning深度学习&#xff09;&#xff0c;GAN主要的思想是同时训练两个模型&#xff0c;生成…

蓝桥杯刷题--幸运数字

幸运数字 题目: 解析: 我们由题目可以知道,某个进制的哈沙德数就是该数和各个位的和取整为0.然后一个幸运数字就是满足所有进制的哈沙德数之和.然后具体就是分为以下几个步骤 1. 我们先写一个方法,里面主要是用来判断,这个数在该进制下是否是哈沙德数 2. 我们在main方法里面调用…

推荐几本编程入门书目

对于编程入门&#xff0c;推荐以下几本书籍&#xff0c;这些书籍覆盖了不同的编程语言&#xff0c;适合零基础的学习者逐步掌握编程基础&#xff1a; 1. 《Python编程快速上手——让繁琐工作自动化》 特点&#xff1a;以简单易懂的方式介绍了Python的基础知识和编程概念&#…

【最新华为OD机试E卷-支持在线评测】构成正方形的数量(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

vue实现列表自动滚动(纯与原生方式)

Vue实现列表自动滚动(纯与原生方式) 源码放在最后&#xff01;1.效果展示: 2.功能说明: 该滚动可能存在的Bug&#xff1a; 1.如果你写的大屏不是使用的接口轮询的方式可能会存在也页面空白的情况(需要手动刷新才能触发列表滚动)&#xff0c;因为我使用的是监听数据的变化然后…

【C++】关联式容器——map和set的使用

文章目录 一、 序列式容器和关联式容器二、set的介绍1.set的构造和迭代器2.set的增删查3.接口lower_bound和upper_bound4.multiset和set的差异 三、map的介绍1.map的构造2.map的增删查3.multimap和map的差异 四、map和set相关OJ 一、 序列式容器和关联式容器 序列式容器&#…

WordPress添加meta标签做seo优化

一、使用function.php文件添加钩子函数添加 方法1、使用is_page()判断不同页面的page_id进行辨别添加不同页面keyword和description &#xff08;1&#xff09;通过页面前台源码查看对应页面的id &#xff08;2&#xff09;或者通过wordpress后台&#xff0c;点击页面列表&…

【网易云音乐】--源代码分享

最近写了一个网易云音乐的音乐实现部分&#xff0c;是通过JavaScript和jQuery实现的&#xff0c;具体效果大家可以参照下面的视频 源代码分享 - git地址: 网易云音乐源代码 下面将着重讲解一下音乐实现部分 视频有点模糊&#xff0c;不好意思&#xff0c;在b站上添加视频的时候…

Ping32:专业的终端安全管理解决方案

在当今数字化转型迅速发展的时代&#xff0c;终端安全管理已成为企业信息安全的重要环节。随着远程办公和移动设备的普及&#xff0c;企业面临着越来越多的网络安全挑战。Ping32作为一款专业的终端安全管理解决方案&#xff0c;以其卓越的性能和易用性&#xff0c;成为众多企业…

[Linux] Linux 进程程序替换

标题&#xff1a;[Linux] Linux 进程程序替换 个人主页水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 O、前言 一、进程程序替换的直观现象&#xff08;什么是进程程序替换&#xff1f;&#xff09; 二、进程程序替换的原理 三、进程程序替换的函数&#xff08…

几种Word Embedding技术详解

NLP 中的词嵌入是一个重要术语&#xff0c;用于以实值向量的形式表示用于文本分析的单词。这是 NLP 的一项进步&#xff0c;提高了计算机更好地理解基于文本的内容的能力。它被认为是深度学习在解决具有挑战性的自然语言处理问题方面最重要的突破之一。 在这种方法中&#xff…

有了WPF后Winform还有活路吗?

近年来&#xff0c;随着技术的不断发展&#xff0c;Windows Presentation Foundation&#xff08;WPF&#xff09;和Windows Forms&#xff08;WinForms&#xff09;这两种技术在开发桌面应用程序方面一直备受关注。虽然WPF以其强大的功能和灵活性吸引了众多开发者&#xff0c;…