React 中的数据可视化与 D3.js
当我想在 Web 应用程序上可视化数据时,我首选的环境是在 React 应用程序中使用 d3.js。但这两种技术很难结合起来。原因是他们都想处理 DOM。
让我们开始吧!
创建 SVG 元素
当我们想要在浏览器中可视化数据时,我们很可能想要使用 SVG 元素,因为它们非常有表现力并且是绝对定位的。
首先,我们将呈现一个简单的
我添加了一个绿色边框,所以我们可以看到我们的
为了可视化数据,我们必须将数据点表示为形状。让我们从一个简单的基本形状开始:a
上面给出的 Circle.jsx 的解释
1.使用 ref 存储对我们渲染的引用
2. 组件挂载时运行 d3 代码
3.使用 d3.select() 将我们的 ref 变成一个 d3 选择对象
4.使用我们的 d3 选择对象附加一个
但这是绘制单个形状的大量代码,而且我不必尽可能少地使用 React refs 吗?
感谢 React 核心团队,随着 React 15 的发布,所有 SVG 元素都在 JSX 中得到支持,因此我们可以创建一个带有
使用标准 JSX 而不是在挂载时运行 d3 代码的好处?
声明式而不是命令式
该代码描述了正在绘制的内容,而不是如何绘制它。
更少的代码
我们的第二个 Circle 组件的行数不到我们第一次迭代的三分之二/
不那么老套
React 主要是一个渲染库,并且有很多优化来保持我们的 Web 应用程序的性能。当使用 d3 添加元素时,我们正在围绕 React 进行黑客攻击,重要的是必须与这些优化作斗争。
创建许多 SVG 元素
d3.js 的主要概念之一是将数据绑定到 DOM 元素。
现在我们生成一个包含 10 个随机 [x, y] 坐标的数据集。
如何生成此数据集
我开发了一个 generateDataset() 函数,它输出一个包含 10 个数组的数组。
如果我画一个会是什么样子
上面给出的 Circles.jsx 的解释
1.我正在制作所有的选择
2.每当数据集更改时,我都会重新运行我的 d3 代码
3.我正在利用 useInterval()(一个 React Hook)每 2 秒重新计算一次我的数据集
但是我们仍然有最初的问题:我们的代码非常命令式、冗长和 hacky。使用 React 渲染我们的
上面给出的 Circles.jsx 的解释
1.遍历每个数据点,以及
2.渲染一个
我们都知道 d3 很擅长跟踪哪些元素是新元素以及动画元素的进出。
现在看一下过渡:
好吧,这是大量的代码!
您不需要遍历所有这些 - 要点是我们有 6 个
好的,你可以看到上面给出的要点很难扫描,但是我们如何使用 React 来实现呢?
在 React 中动画元素并不是很简单,我保留了所有的
上面给出的Transitions.jsx的解释
- 循环我们的 allCircles 数组并创建一个
对于每个项目, - 定义一个带有 props 的 AnimatedCircle 组件:index(用于定位)和 isShowing
- 缓存最后一个 isShowing 值,所以我可以看到是否
正在进入或退出 - 动画我们的
使用来自 react-spring 的动画并将我们的动画值作为元素属性传播
可以说,与 d3.js 代码相比,这段代码不是很短,但很容易阅读。
轴
d3.js API 非常广泛,我们可以依赖它来为我们完成繁重的工作。尤其是可以为我们制作多个 DOM 元素的许多方法。
例如,.axisBottom() 函数将在一行代码中创建一个完整的图表轴!
上面给出的 Axis.jsx 的解释
- 创建一个将数据值 (0–100) 转换为相应物理位置 (10px — 290px) 的比例
- 存储
- 将比例传递给 .axisBottom() 以制作一个axisGenerator
- .call() 我们新的axisGenerator
元素。
我认为这很容易,但我们通常更喜欢保持 Reactish。
所以如果我们不想使用 .axisBottom() 来创建我们的轴 DOM 元素,我们会怎么做?
虽然我们不想使用创建 DOM 元素 (.axisBottom()) 的 d3 函数,但我们可以使用 d3 内部使用的 d3 方法来创建轴!
上面给出的 Axis.jsx 的解释
- 制作从数据值 (0–100) 转换为相应物理位置 (10px — 290px) 的刻度
- 利用我们的 d3 scale 的 .ticks() 函数。
- 映射我们的刻度值数组并创建一个包含该值和 xOffset 的对象(使用 xScale 转换)
- 做一个
标记我们轴顶部的元素。它从 [9, 0] 开始水平移动到 [290, 0] - 对于每个刻度,我想创建一个向右移动适当数量的像素的组。
- 我的每个组都将包含一个勾号
和 包含刻度值
好的!所以这肯定是更多的代码。但这是有道理的,因为我们从根本上在我们自己的代码库中复制了一些 d3 库代码。
但事情是这样的:新代码非常易读——我们只需查看 return 语句就知道我们正在渲染哪些元素。另外,我们可以将所有这些逻辑提取到单个 Axis 组件中。我们可以随心所欲地自定义它,而不必再次考虑这个额外的逻辑。
更可重用的 Axis 组件应该是什么样的?
Axis 组件将采用两个道具:域和范围。
上面给出的 Axis.jsx 的解释
- 我检查范围以动态更改我瞄准的刻度数(我可以通过将数字提供给 .ticks() 来设置)。
- 当我的道具改变时,我需要重新计算我的刻度。我必须注意我的域和范围数组的值,而不是数组引用,所以我会将它们 .join() 变成一个字符串。例如,我必须检查一个字符串“0–100”,而不是对数组 [0, 100] 的引用。这将使我能够在 Axis 的父组件中创建域和范围数组。
- 一点点改变,但相当重要。我将添加一个重复的第一个和最后一个刻度线,以防我的刻度线没有覆盖我们域的顶部或底部。
现在,我的 Axis 组件目前专门用于图表底部的轴。但可以肯定的是,这让您充分了解复制 d3 的轴绘图功能是多么简单。
我使用这个函数来重新创建任何生成许多元素的 d3 方法。除了使用 React 渲染元素的通常优势(声明性且不那么 hacky)之外,我发现这段代码对于其他不太熟悉 d3 API 的开发人员来说更容易理解代码。
我真正做到了两全其美,因为 d3 API 展现了它的许多内部功能。
尺寸和响应度
调整图表可能很困难!因为我们想要准确定位我们的数据元素,所以我们不能利用我们通常依赖于响应大小的 Web 开发技巧
沙.如果您阅读了许多 d3.js 示例,您就会知道有一种常用的方法来调整图表大小。
上面给定图像的解释
- Wrapper 是图表的范围,以及图表的维度
- Bound 包含数据元素,但不包括边距和图例。
- 边距确定边界周围的填充。
我们必须拆分包装和边界框,因为我们想在构建图表时知道它们的确切尺寸
这个例子有点复杂——让我解释一下发生了什么。这里需要注意的主要部分是:
上面给出的 ChartWithDimensions.jsx 的解释
- 利用自定义钩子来计算我们的包装器和边界的尺寸(稍后会详细介绍)
- 使用具有计算尺寸的 dms 对象来制作 x 比例。
- 利用我们自定义钩子中的 React ref 来提供一个非 svg 包装元素,这是我们需要包装器的大小。
- 更改图表的主要部分以尊重我们的上边距和左边距
现在我们已经了解了如何使用包装器、边界和边距,让我们看看我们的自定义钩子在做什么。
当我们向自定义 useChartDimensions 钩子提供设置对象时,它将:
上面给出的 useChartDimensions.js 的解释
- 通过预设默认值填充缺失的边距。
- 遵循给定的高度和宽度,如果在passedSettings中指定
- 当给定元素改变大小时,使用 ResizeObserver 重新计算尺寸。
- 保持包含的高度和宽度对于我们的包装尺寸。
- 计算边界的尺寸(命名为 boundedHeight 和 boundedWidth)
要记住的重要一点是,我们未设置的任何设置都会自动填写。
希望这能让您了解如何以响应式、简单的方式处理图表维度。
地图
因此,您已经看到人们使用 d3 制作详细地图以及可以旋转的地球仪的出色示例。你也想这样做。
不用担心!我们将让 d3 完成大量繁重的工作,并立即拥有地图!
上面给出的 useChartDimensions.js 的解释
- 首先,我们要创建一个投影。这是我们国家形状定义和我们在 2D 屏幕上绘制这些 3D 形状的过程之间的映射。我们将利用 .fitWidth() 函数在组件的宽度内调整地图的大小,并使用 d3.geoPath() 创建一个 pathGenerator 来为我们的地球和国家形状创建路径定义。
- 接下来,我们将在投影中找到整个地球(球体)的尺寸,并将 svg 的高度赋予球体的高度。
- 一些投影的形状超出了地球的边缘,因此我们将使用 clipPath 将它们保持在边界内。
- 我们可以利用我们的 pathGenerator 方法将 GeoJSONshape 定义转换为
d 属性字符串。首先,我们将整个地球画成浅灰色。 - d3-geo 有一些很棒的功能,比如 d3.geoGraticule10() 可以帮助我们绘制刻度线以供参考。
- 最后但同样重要的是,我们将绘制我们的国家形状!我们可以通过将 GeoJSON 定义给我们的 pathGenerator 方法来绘制各种类型的地理形状。例如,我们正在导入国家定义列表,然后创建
元素及其形状。
一旦你了解了基础知识,这是一种非常灵活的绘制地理的方法!诀窍是将 d3 视为一系列工具。
结论
我们已经完成了基础知识!我们已经涵盖:
- 如何绘制svg元素
- 如何绘制许多svg元素
- 如何复制用于绘制复杂元素(如轴)的内置 d3 方法
- 如何轻松调整图表大小
- 如何绘制地图!
根据我的经验,最重要的规则是了解你的工具。一旦您对使用 SVG 绘图、使用 d3 作为实用程序库并构建 React.js 代码感到满意,您将真正能够做出您能想象的任何事情。这就是学习基础知识的美妙之处,而不是仅仅掌握一个图表库——它需要学习更多的工作,但功能更强大。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明
本文链接:https://www.qanswer.top/22124/36000708
标签:代码,D3,元素,d3,React,js,我们 From: https://www.cnblogs.com/amboke/p/16664021.html